Skip to content

Commit 14b1f7b

Browse files
committed
Add Actions layout playground for Blade, React, Vue, and Svelte
1 parent d072980 commit 14b1f7b

13 files changed

Lines changed: 450 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace App\Filament\Pages;
4+
5+
use App\Filament\Widgets\ActionsBlade;
6+
use App\Filament\Widgets\ActionsReact;
7+
use App\Filament\Widgets\ActionsSvelte;
8+
use App\Filament\Widgets\ActionsVue;
9+
use Filament\Pages\Dashboard;
10+
11+
class ActionsPlayground extends Dashboard
12+
{
13+
protected static string $routePath = 'actions-playground';
14+
15+
protected static ?string $title = 'Actions playground';
16+
17+
public function getWidgets(): array
18+
{
19+
return [ActionsBlade::class, ActionsReact::class, ActionsVue::class, ActionsSvelte::class];
20+
}
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Widget;
6+
7+
class ActionsBlade extends Widget
8+
{
9+
protected string $view = 'filament.widgets.actions-blade';
10+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class ActionsReact extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/actions-react.jsx');
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class ActionsSvelte extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/actions-svelte.svelte.js');
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Filament\Widgets;
4+
5+
use Filament\Widgets\Concerns\HasJsRenderer;
6+
use Filament\Widgets\Widget;
7+
use Illuminate\Support\Facades\Vite;
8+
9+
class ActionsVue extends Widget
10+
{
11+
use HasJsRenderer;
12+
13+
public function getRenderer(): string
14+
{
15+
return Vite::asset('resources/js/filament/widgets/actions-vue.js');
16+
}
17+
}

‎resources/css/filament/admin/theme.css‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,28 @@
164164
.callout-demo {
165165
@apply grid gap-4;
166166
}
167+
168+
.actions-demo {
169+
@apply grid gap-4;
170+
171+
& form {
172+
@apply grid gap-4;
173+
}
174+
175+
& form > label {
176+
@apply grid gap-2 text-sm;
177+
}
178+
179+
& form input {
180+
@apply min-w-0 rounded-md border border-gray-300 bg-white p-2 text-gray-950 dark:border-gray-600 dark:bg-gray-900 dark:text-white;
181+
}
182+
183+
& button,
184+
& a {
185+
@apply text-primary-700 ring-primary-300 dark:text-primary-300 dark:ring-primary-700 rounded-md px-3 py-2 text-sm font-medium ring-1;
186+
}
187+
188+
& p {
189+
@apply text-sm;
190+
}
191+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script>
2+
import Actions from '../../../../vendor/filament/support/resources/js/svelte/Actions.svelte'
3+
let alignment = $state('start')
4+
let fullWidth = $state(false)
5+
let visible = $state(true)
6+
let name = $state('Community garden')
7+
let message = $state('No changes saved.')
8+
</script>
9+
10+
<section class="actions-demo" data-framework="svelte">
11+
<h2 class="fi-section-header-heading">Svelte · JavaScript</h2>
12+
<form
13+
onsubmit={(event) => {
14+
event.preventDefault()
15+
message = `Saved ${name} locally.`
16+
}}
17+
>
18+
<label
19+
>Project name <input bind:value={name} data-testid="name" /></label
20+
>
21+
{#if visible}<Actions {alignment} {fullWidth} data-testid="actions">
22+
<button type="submit" data-testid="save">Save</button>
23+
<button
24+
type="button"
25+
data-testid="archive"
26+
onclick={() => (message = `Archived ${name} locally.`)}
27+
>Archive</button
28+
>
29+
<a href="#svelte-project">View project</a>
30+
</Actions>{/if}
31+
</form>
32+
<div class="icon-demo-controls">
33+
<label
34+
>Alignment <select bind:value={alignment} data-testid="alignment"
35+
>{#each ['start', 'left', 'center', 'end', 'right', 'between', 'justify'] as value}<option
36+
>{value}</option
37+
>{/each}</select
38+
></label
39+
>
40+
<label
41+
><input
42+
bind:checked={fullWidth}
43+
type="checkbox"
44+
data-testid="full-width"
45+
/>Full width</label
46+
>
47+
<label
48+
><input
49+
bind:checked={visible}
50+
type="checkbox"
51+
data-testid="visible"
52+
/>Show actions</label
53+
>
54+
<button
55+
type="button"
56+
data-testid="reset"
57+
onclick={() => {
58+
alignment = 'start'
59+
fullWidth = false
60+
visible = true
61+
name = 'Community garden'
62+
message = 'No changes saved.'
63+
}}>Reset</button
64+
>
65+
</div>
66+
<p role="status" data-testid="result">{message}</p>
67+
<p id="svelte-project" tabindex="-1">Community garden · Project details</p>
68+
</section>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<script setup>
2+
import { ref } from 'vue'
3+
import Actions from '../../../../vendor/filament/support/resources/js/vue/Actions.vue'
4+
const alignment = ref('start')
5+
const fullWidth = ref(false)
6+
const visible = ref(true)
7+
const name = ref('Community garden')
8+
const message = ref('No changes saved.')
9+
function reset() {
10+
alignment.value = 'start'
11+
fullWidth.value = false
12+
visible.value = true
13+
name.value = 'Community garden'
14+
message.value = 'No changes saved.'
15+
}
16+
</script>
17+
<template>
18+
<section class="actions-demo" data-framework="vue">
19+
<h2 class="fi-section-header-heading">Vue · JavaScript</h2>
20+
<form @submit.prevent="message = `Saved ${name} locally.`">
21+
<label
22+
>Project name <input v-model="name" data-testid="name"
23+
/></label>
24+
<Actions
25+
v-if="visible"
26+
:alignment="alignment"
27+
:full-width="fullWidth"
28+
data-testid="actions"
29+
>
30+
<button type="submit" data-testid="save">Save</button>
31+
<button
32+
type="button"
33+
data-testid="archive"
34+
@click="message = `Archived ${name} locally.`"
35+
>
36+
Archive
37+
</button>
38+
<a href="#vue-project">View project</a>
39+
</Actions>
40+
</form>
41+
<div class="icon-demo-controls">
42+
<label
43+
>Alignment
44+
<select v-model="alignment" data-testid="alignment">
45+
<option
46+
v-for="value in [
47+
'start',
48+
'left',
49+
'center',
50+
'end',
51+
'right',
52+
'between',
53+
'justify',
54+
]"
55+
:key="value"
56+
>
57+
{{ value }}
58+
</option>
59+
</select></label
60+
>
61+
<label
62+
><input
63+
v-model="fullWidth"
64+
type="checkbox"
65+
data-testid="full-width"
66+
/>Full width</label
67+
>
68+
<label
69+
><input
70+
v-model="visible"
71+
type="checkbox"
72+
data-testid="visible"
73+
/>Show actions</label
74+
>
75+
<button type="button" data-testid="reset" @click="reset">
76+
Reset
77+
</button>
78+
</div>
79+
<p role="status" data-testid="result">{{ message }}</p>
80+
<p id="vue-project" tabindex="-1">Community garden · Project details</p>
81+
</section>
82+
</template>
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import React, { useState } from 'react'
2+
import { createRoot } from 'react-dom/client'
3+
import Actions from '../../../../vendor/filament/support/resources/js/react/Actions'
4+
5+
function ActionsReact() {
6+
const [alignment, setAlignment] = useState('start')
7+
const [fullWidth, setFullWidth] = useState(false)
8+
const [visible, setVisible] = useState(true)
9+
const [name, setName] = useState('Community garden')
10+
const [message, setMessage] = useState('No changes saved.')
11+
return (
12+
<section className="actions-demo" data-framework="react">
13+
<h2 className="fi-section-header-heading">React · JavaScript</h2>
14+
<form
15+
onSubmit={(event) => {
16+
event.preventDefault()
17+
setMessage(`Saved ${name} locally.`)
18+
}}
19+
>
20+
<label>
21+
Project name{' '}
22+
<input
23+
data-testid="name"
24+
value={name}
25+
onChange={(event) => setName(event.target.value)}
26+
/>
27+
</label>
28+
{visible && (
29+
<Actions
30+
alignment={alignment}
31+
fullWidth={fullWidth}
32+
data-testid="actions"
33+
>
34+
<button type="submit" data-testid="save">
35+
Save
36+
</button>
37+
<button
38+
type="button"
39+
data-testid="archive"
40+
onClick={() =>
41+
setMessage(`Archived ${name} locally.`)
42+
}
43+
>
44+
Archive
45+
</button>
46+
<a href="#react-project">View project</a>
47+
</Actions>
48+
)}
49+
</form>
50+
<div className="icon-demo-controls">
51+
<label>
52+
Alignment{' '}
53+
<select
54+
data-testid="alignment"
55+
value={alignment}
56+
onChange={(event) => setAlignment(event.target.value)}
57+
>
58+
{[
59+
'start',
60+
'left',
61+
'center',
62+
'end',
63+
'right',
64+
'between',
65+
'justify',
66+
].map((value) => (
67+
<option key={value}>{value}</option>
68+
))}
69+
</select>
70+
</label>
71+
<label>
72+
<input
73+
type="checkbox"
74+
data-testid="full-width"
75+
checked={fullWidth}
76+
onChange={(event) => setFullWidth(event.target.checked)}
77+
/>
78+
Full width
79+
</label>
80+
<label>
81+
<input
82+
type="checkbox"
83+
data-testid="visible"
84+
checked={visible}
85+
onChange={(event) => setVisible(event.target.checked)}
86+
/>
87+
Show actions
88+
</label>
89+
<button
90+
type="button"
91+
data-testid="reset"
92+
onClick={() => {
93+
setAlignment('start')
94+
setFullWidth(false)
95+
setVisible(true)
96+
setName('Community garden')
97+
setMessage('No changes saved.')
98+
}}
99+
>
100+
Reset
101+
</button>
102+
</div>
103+
<p role="status" data-testid="result">
104+
{message}
105+
</p>
106+
<p id="react-project" tabIndex={-1}>
107+
Community garden · Project details
108+
</p>
109+
</section>
110+
)
111+
}
112+
113+
export default function mountActionsReact({ host, props }) {
114+
const root = createRoot(host)
115+
root.render(<ActionsReact {...props} />)
116+
return {
117+
update: (next) => root.render(<ActionsReact {...next} />),
118+
destroy: () => root.unmount(),
119+
}
120+
}

0 commit comments

Comments
 (0)