Complete initial food picker component

This commit is contained in:
Christopher C. Wells 2021-01-18 22:58:19 -08:00
parent 6dccf05f2d
commit 5877d24f64
8 changed files with 71 additions and 40 deletions

View File

@ -71,16 +71,8 @@ class RecipeController extends Controller
*/ */
public function edit(Recipe $recipe): View public function edit(Recipe $recipe): View
{ {
$foods = Food::all(['id', 'name', 'detail'])->sortBy('name')->collect()
->map(function ($food) {
return [
'value' => $food->id,
'label' => "{$food->name}" . ($food->detail ? ", {$food->detail}" : ""),
];
});
return view('recipes.edit') return view('recipes.edit')
->with('recipe', $recipe) ->with('recipe', $recipe)
->with('foods', $foods)
->with('food_units', new Collection([ ->with('food_units', new Collection([
['value' => 'tsp', 'label' => 'tsp.'], ['value' => 'tsp', 'label' => 'tsp.'],
['value' => 'tbsp', 'label' => 'tbsp.'], ['value' => 'tbsp', 'label' => 'tbsp.'],

View File

@ -7,7 +7,17 @@ use Livewire\Component;
class FoodPicker extends Component class FoodPicker extends Component
{ {
public string $term = ''; public ?string $term = NULL;
public int $index;
public ?int $defaultId = NULL;
public ?string $defaultName = NULL;
/**
* Set the default term on mount.
*/
public function mount() {
$this->term = $this->defaultName;
}
/** /**
* Get the view / contents that represent the component. * Get the view / contents that represent the component.
@ -21,6 +31,7 @@ class FoodPicker extends Component
} else { } else {
$foods = []; $foods = [];
} }
return view('livewire.food-picker')->with('foods', $foods); return view('livewire.food-picker')
->with('foods', $foods);
} }
} }

6
public/css/app.css vendored
View File

@ -31425,6 +31425,12 @@ select {
animation: bounce 1s infinite; animation: bounce 1s infinite;
} }
/* See: https://ryangjchandler.co.uk/articles/hiding-elements-until-alpine-is-ready-with-x-cloak */
[x-cloak] {
display: none !important;
}
@media (min-width: 640px) { @media (min-width: 640px) {
.sm\:container { .sm\:container {
width: 100%; width: 100%;

4
public/js/app.js vendored
View File

@ -21338,8 +21338,8 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/*! no static exports found */ /*! no static exports found */
/***/ (function(module, exports, __webpack_require__) { /***/ (function(module, exports, __webpack_require__) {
__webpack_require__(/*! /Users/wellc/PhpstormProjects/prndb/resources/js/app.js */"./resources/js/app.js"); __webpack_require__(/*! /home/chris/PhpstormProjects/pfnj/resources/js/app.js */"./resources/js/app.js");
module.exports = __webpack_require__(/*! /Users/wellc/PhpstormProjects/prndb/resources/css/app.css */"./resources/css/app.css"); module.exports = __webpack_require__(/*! /home/chris/PhpstormProjects/pfnj/resources/css/app.css */"./resources/css/app.css");
/***/ }) /***/ })

View File

@ -0,0 +1,8 @@
/**
* @license
* Lodash <https://lodash.com/>
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/

View File

@ -1,3 +1,8 @@
@import 'tailwindcss/base'; @import 'tailwindcss/base';
@import 'tailwindcss/components'; @import 'tailwindcss/components';
@import 'tailwindcss/utilities'; @import 'tailwindcss/utilities';
/* See: https://ryangjchandler.co.uk/articles/hiding-elements-until-alpine-is-ready-with-x-cloak */
[x-cloak] {
display: none !important;
}

View File

@ -1,35 +1,46 @@
<div x-data="{isTyped: false}"> <div x-data="{searching: false}">
<div> <div>
<div> <div>
<x-inputs.input type="hidden"
name="foods[{{ $index }}]"
:value="$defaultId"
x-ref="foods{{ $index }}"/>
<x-inputs.input type="text" <x-inputs.input type="text"
name="food" name="foods_name[{{ $index }}]"
placeholder="{{__('Search ...')}}" :value="$defaultName"
x-on:input.debounce.400ms="isTyped = ($event.target.value != '')" placeholder="Search..."
x-on:focusout="isTyped = false; $event.target.value = ''"
autocomplete="off" autocomplete="off"
wire:model.debounce.500ms="term" wire:model.debounce.500ms="term"
aria-label="Search input" /> x-on:input.debounce.400ms="searching = ($event.target.value != '')"
x-on:focusout.debounce.200ms="searching = false;"
x-ref="foods_name{{ $index }}" />
</div> </div>
<div x-show="isTyped" x-cloak> <div x-show="searching" x-cloak>
<div class="absolute border-2 border-gray-500 border-b-0 bg-white"> <div class="absolute border-2 border-gray-500 border-b-0 bg-white"
x-on:click="selected = $event.target; if (selected.dataset.id) { $refs.foods_name{{ $index }}.value = selected.dataset.value; $refs.foods{{ $index }}.value = selected.dataset.id; searching = false; }">
@forelse($foods as $food) @forelse($foods as $food)
<div class="p-1 border-b-2 border-gray-500 hover:bg-yellow-300 cursor-pointer"> <div class="p-1 border-b-2 border-gray-500 hover:bg-yellow-300 cursor-pointer"
<div class="text"> wire:key="{{ $food->id }}"
{{ $food->name }}@if($food->detail), <span class="text-gray-500">{{ $food->detail }}</span>@endif data-id="{{ $food->id }}"
</div> data-value="{{ $food->name }}">
@if($food->brand) <div class="pointer-events-none">
<div class="text-sm text-gray-600"> <div>
{{ $food->brand }} {{ $food->name }}@if($food->detail), <span class="text-gray-500">{{ $food->detail }}</span>@endif
</div>
@if($food->brand)
<div class="text-sm text-gray-600">
{{ $food->brand }}
</div>
@endif
<div class="text-sm">
Serving size {{ \App\Support\Number::fractionStringFromFloat($food->serving_size) }}
{{ $food->serving_unit }}
({{ $food->serving_weight }}g)
</div> </div>
@endif
<div class="text-sm">
Serving size {{ \App\Support\Number::fractionStringFromFloat($food->serving_size) }}
{{ $food->serving_unit }}
({{ $food->serving_weight }}g)
</div> </div>
</div> </div>
@empty @empty
<div class="border-b-2 border-gray-500" x-cloak> <div class="p-1 border-b-2 border-gray-500" x-cloak>
No results found. No results found.
</div> </div>
@endforelse @endforelse

View File

@ -70,10 +70,11 @@
$amount = \App\Support\Number::fractionStringFromFloat($foodAmount->amount); $amount = \App\Support\Number::fractionStringFromFloat($foodAmount->amount);
$unit = $foodAmount->unit; $unit = $foodAmount->unit;
$food_id = $foodAmount->food->id; $food_id = $foodAmount->food->id;
$food_name = $foodAmount->food->name;
$detail = $foodAmount->detail; $detail = $foodAmount->detail;
} else { } else {
$foodAmount = new \App\Models\FoodAmount(); $foodAmount = new \App\Models\FoodAmount();
$amount = $food_id = $unit = $detail = null; $amount = $food_id = $food_name = $unit = $detail = null;
} }
@endphp @endphp
<div class="flex flex-row space-x-4 mb-4"> <div class="flex flex-row space-x-4 mb-4">
@ -86,12 +87,9 @@
:selectedValue="old('foods_unit.' . $i, $unit)"> :selectedValue="old('foods_unit.' . $i, $unit)">
<option value=""></option> <option value=""></option>
</x-inputs.select> </x-inputs.select>
{{-- <x-inputs.select name="foods[]"--}} <livewire:food-picker :index="$i"
{{-- :options="$foods"--}} :default-id="old('foods.' . $i, $food_id)"
{{-- :selectedValue="old('foods.' . $i, $food_id)">--}} :default-name="old('foods_name.' . $i, $food_name)">
{{-- <option value=""></option>--}}
{{-- </x-inputs.select>--}}
<livewire:food-picker>
<x-inputs.input type="text" <x-inputs.input type="text"
class="block" class="block"
name="foods_detail[]" name="foods_detail[]"