Skip to content

Commit

Permalink
feat: actions (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
francoism90 committed May 2, 2024
1 parent 3d09d96 commit bfe71cf
Show file tree
Hide file tree
Showing 64 changed files with 1,626 additions and 243 deletions.
10 changes: 10 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Upgrading

Because there are many breaking changes an upgrade is not that easy. There are many edge cases this guide does not cover. We accept PRs to improve this guide.

## From v0 to v1

- It now includes a basic set of components. It can optionally be disabled in `config/wireuse.php`.
- The `classFor` behavior has been changed. You now need to specify the class attribute: `<label class="{{ $attributes->classFor('label') }}" />`.
- The `spatie/laravel-model-states` package is now not registered by default. You now need to register `ModelStateObjectSynth::class` manually in a `Service Provider`.
- The `CreateForm` and `UpdateForm` classes have been removed.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"illuminate/contracts": "^10.0|^11.0",
"laravel/scout": "^10.0|^11.0",
"livewire/livewire": "^3.4",
"spatie/laravel-model-states": "^2.7",
"spatie/laravel-package-tools": "^1.16.3",
"spatie/php-structure-discoverer": "^2.1"
},
Expand All @@ -36,6 +35,7 @@
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan-deprecation-rules": "^1.1.4",
"phpstan/phpstan-phpunit": "^1.3.16",
"spatie/laravel-model-states": "^2.7",
"spatie/laravel-ray": "^1.35.1"
},
"autoload": {
Expand Down
22 changes: 22 additions & 0 deletions config/wireuse.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,26 @@
*/

'register_macros' => true,

/*
|--------------------------------------------------------------------------
| Components
|--------------------------------------------------------------------------
|
| This controls components registration.
|
*/

'register_components' => true,

/*
|--------------------------------------------------------------------------
| Views
|--------------------------------------------------------------------------
|
| This controls views registration.
|
*/

'view_prefix' => 'wireuse',
];
8 changes: 8 additions & 0 deletions resources/css/presets/tailwind.config.preset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import forms from '@tailwindcss/forms';
import typography from '@tailwindcss/typography';

/** @type {import('tailwindcss').Config} */
export default {
content: ['./resources/**/*.blade.php', './app/View/**/*.php', './src/**/*.php', './vendor/foxws/wireuse/**/*.blade.php'],
plugins: [forms, typography],
};
Empty file added resources/views/.gitkeep
Empty file.
20 changes: 20 additions & 0 deletions resources/views/actions/button.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<button {{ $attributes
->cssClass([
'layer' => 'inline-flex shrink-0 cursor-pointer items-center justify-center',
'primary' => 'py-1.5 px-3 bg-primary-500 rounded border border-primary-500',
])
->mergeAttributes($action->getComponentAttributes())
->classMerge([
'layer',
'primary' => $attributes->get('type') === 'submit',
])
->merge([
'aria-label' => $label(),
])
}}>
@if ($slot->isEmpty())
{{ $label() }}
@else
{{ $slot }}
@endif
</button>
29 changes: 29 additions & 0 deletions resources/views/actions/icon.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div {{ $attributes
->cssClass([
'layer' => 'inline-flex items-center justify-center',
'icon' => 'size-6 sm:size-7',
])
->classMerge([
'layer',
])
}}>
@if ($iconName() && filled($action->getState()))
<x-icon
x-cloak
x-show="! {{ $action->getState() }}"
:name="$iconName()"
class="{{ $attributes->classFor('icon') }}"
/>

@if ($hasActiveIcon())
<x-icon
x-cloak
x-show="{{ $action->getState() }}"
:name="$action->getActiveIcon()"
class="{{ $attributes->classFor('icon') }}"
/>
@endif
@elseif ($iconName())
<x-icon :name="$iconName()" class="{{ $attributes->classFor('icon') }}" />
@endif
</div>
24 changes: 24 additions & 0 deletions resources/views/actions/link.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<a {{ $attributes
->cssClass([
'layer' => 'inline-flex shrink-0 cursor-pointer items-center justify-center',
'active' => 'text-primary-400 hover:text-primary-300',
'inactive' => 'text-secondary-400 hover:text-primary-400',
])
->mergeAttributes($action->getComponentAttributes())
->classMerge([
'layer',
'active' => $isCurrent(),
'inactive' => ! $isCurrent(),
])
->merge([
'wire:navigate' => $navigate(),
'href' => $url(),
'aria-label' => $label(),
])
}}>
@if ($slot->isEmpty())
{{ $label() }}
@else
{{ $slot }}
@endif
</a>
19 changes: 19 additions & 0 deletions resources/views/auth/login.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<form wire:submit="submit">
<x-wireuse::forms.input
label="{{ __('Email') }}"
id="form.email"
type="email"
wire:model.live="form.email"
/>

<x-wireuse::forms.input
label="{{ __('Password') }}"
id="form.password"
type="password"
wire:model.live="form.password"
/>

@foreach ($actions as $action)
<x-wireuse::actions-button :$action />
@endforeach
</form>
3 changes: 3 additions & 0 deletions resources/views/auth/logout.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
{{-- redirecting --}}
</div>
3 changes: 3 additions & 0 deletions resources/views/auth/register.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<form wire:submit="submit">
{{-- TODO --}}
</form>
16 changes: 16 additions & 0 deletions resources/views/components/forms/actions.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@props([
'actions',
])

<nav class="my-3 py-3 overflow-x-auto border-t border-secondary-700/50">
<x-app.layout.container fluid>
<nav class="flex flex-nowrap items-center gap-x-3">
@foreach ($actions as $action)
<x-wireuse::actions-button :$action>
<x-wireuse::actions-icon :$action />
<span class="text-sm font-medium">{{ $action->getLabel() }}</span>
</x-wireuse::actions-button>
@endforeach
</nav>
</x-app.layout.container>
</nav>
15 changes: 15 additions & 0 deletions resources/views/components/forms/checkbox.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<input {{ $attributes
->cssClass([
'layer' => 'peer shrink-0',
'error' => 'border-red-500',
])
->classMerge([
'layer',
'error' => $errors->has($wireModel()),
])
->merge([
'wire:key' => $wireKey(),
'id' => $wireKey(),
'type' => 'checkbox',
])
}}>
53 changes: 53 additions & 0 deletions resources/views/components/forms/input.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@props([
'prepend' => null,
'append' => null,
'label' => null,
'hint' => null,
])

<div {{ $attributes
->cssClass([
'layer' => 'flex flex-col gap-1.5 w-full',
'input' => 'p-3 h-10 w-full text-base bg-secondary-800/90 border-secondary-500/50 focus:border-secondary-500 focus:border-2 focus:ring-0',
'label' => 'flex items-center',
'error' => '!border-red-500',
'hint' => 'py-3 text-xs',
'message' => 'text-red-500 text-sm',
])
->classMerge([
'layer',
])
->only('class')
}}>
<label
class="{{ $attributes->classFor('label') }}"
for="{{ $attributes->wireKey() }}"
>
{{ $label }}
</label>

{{ $prepend }}

<input {{ $attributes
->classMerge([
'input',
'error' => $errors->has($attributes->wireModel()),
])
->merge([
...['id' => $attributes->wireKey(), 'type' => 'text'],
...$attributes->whereStartsWith('wire:model')
])
}} />

{{ $append }}

@if ($hint)
<p class="{{ $attributes->classFor('hint') }}">{{ $hint }}</p>
@endif

@error($attributes->wireKey())
<p class="{{ $attributes->classFor('message') }}">
{{ $message }}
</p>
@enderror
</div>
36 changes: 36 additions & 0 deletions resources/views/components/forms/label.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@props([
'id',
'label' => null,
'required' => false,
'hint' => null,
])

<label {{ $attributes
->cssClass([
'layer' => 'flex items-center text-sm font-medium cursor-pointer',
'error' => 'text-red-500',
'hint' => 'pt-1 text-red-500',
'required' => 'px-1 text-primary-400',
])
->classMerge([
'layer',
'error' => $errors->has($id),
])
->merge([
'for' => $id,
])
}}>
{{ $slot }}

{{ $label }}

@if ($required)
<span class="{{ $attributes->classFor('required') }}">*</span>
@endif

@if ($hint)
<p class="{{ $attributes->classFor('hint') }}">
{{ $hint }}
</p>
@endif
</label>
14 changes: 14 additions & 0 deletions resources/views/components/forms/messages.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@if (flash()->message)
<div {{ $attributes
->cssClass([
'layer' => 'flex gap-3 w-full',
'success' => 'bg-primary-500 rounded text-base p-3 text-sm font-medium',
])
->classMerge([
'layer',
'success' => flash()->level === 'success',
])
}}>
<span>{{ flash()->message }}</span>
</div>
@endif
84 changes: 84 additions & 0 deletions resources/views/components/forms/tags.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@props([
'prepend' => null,
'append' => null,
'label' => null,
'hint' => null,
'items' => [],
])

<div {{ $attributes
->cssClass([
'layer' => 'flex flex-col gap-y-3 relative',
'items' => 'flex items-start gap-2 pt-1 w-full',
'item' => 'inline-flex items-center gap-2 px-2 py-1 rounded-xs text-xs bg-secondary-500',
'error' => '!border-red-500',
])
->classMerge([
'layer',
])
->merge([
'x-data' => 'tags',
'x-modelable' => 'tags',
])
}}>
<x-dashboard.forms.input
:$append
:$prepend
x-on:click="open = ! open"
label="{{ __('Tags') }}"
id="tags.query"
wire:model.live="tags.query"
autocomplete="off"
placeholder="{{ __('Filter tags') }}"
/>

<div
x-cloak
x-show="open"
class="absolute z-50 top-20 inset-0"
>
<div class="flex flex-col w-full divide-y divide-solid divide-secondary-500/50 border border-secondary-500/50 bg-secondary-800">
@foreach ($items as $id => $value)
<a
x-on:click="add('{{ $id }}')"
class="text-sm hover:bg-secondary-600 px-3 py-2"
>
{{ $value }}
</a>
@endforeach
</div>
</div>

<div class="{{ $attributes->classFor('items') }}">
<template x-for="(tag, index) in tags" :key="tag">
<a
x-show="selected[tag]"
x-text="selected[tag]"
x-on:click="tags.splice(index, 1)"
class="{{ $attributes->classFor('item') }}"
>
</a>
</template>
</div>
</div>

@script
<script data-navigate-track>
Alpine.data('tags', () => ({
tags: [],
selected: [],
open: false,
init() {
this.$watch('tags', async (value) => {
this.selected = await $wire.getTagModels(value)
})
},
add(id) {
this.tags.push(id)
this.open = false
},
}));
</script>
@endscript

0 comments on commit bfe71cf

Please sign in to comment.