Moves locale preferences from calendar settings to account settings; beefs up config with the date and time formatting and region options; refactors button groups and focus handling; refactors shadow complexity in button groups
This commit is contained in:
parent
0b82c88333
commit
5fd9628dc9
@ -13,12 +13,14 @@ use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* landing page
|
||||
*/
|
||||
public function index(): RedirectResponse
|
||||
@ -27,6 +29,7 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* info pane (name, email, timezone, etc.)
|
||||
*/
|
||||
public function infoForm(Request $request)
|
||||
@ -40,9 +43,6 @@ class AccountController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* save info pane
|
||||
*/
|
||||
public function infoStore(AccountUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
@ -59,6 +59,88 @@ class AccountController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* locale pane
|
||||
*/
|
||||
public function localeForm(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
return $this->frame('account.settings.locale', [
|
||||
'title' => __('account.settings.locale.title'),
|
||||
'sub' => __('account.settings.locale.subtitle'),
|
||||
'values' => [
|
||||
// language comes from column
|
||||
'language' => $user->locale ?? config('app.locale'),
|
||||
// timezone comes from column (fallback to app timezone then UTC)
|
||||
'timezone' => $user->timezone ?? config('app.timezone', 'UTC'),
|
||||
// the other three live in user.settings json
|
||||
'region' => $user->getSetting('app.region', 'US'),
|
||||
'date_format' => $user->getSetting('app.date_format', 'mdy'),
|
||||
'time_format' => $user->getSetting('app.time_format', '12'),
|
||||
],
|
||||
'options' => [
|
||||
'languages' => config('kithkin.locales', []), // optgroups
|
||||
'regions' => config('kithkin.regions', []), // optgroups
|
||||
'date_formats' => config('kithkin.date_formats', []), // flat
|
||||
'time_formats' => config('kithkin.time_formats', []), // flat
|
||||
'timezones' => config('timezones', []), // optgroups
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function localeStore(Request $request): RedirectResponse
|
||||
{
|
||||
$allowedLocales = collect(config('kithkin.locales', []))
|
||||
->flatMap(fn ($group) => is_array($group) ? array_keys($group) : [])
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$allowedRegions = collect(config('kithkin.regions', []))
|
||||
->flatMap(fn ($group) => is_array($group) ? array_keys($group) : [])
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$allowedTimezones = collect(config('timezones', []))
|
||||
->flatMap(fn ($group) => is_array($group) ? array_keys($group) : [])
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$data = $request->validate([
|
||||
'language' => ['required', Rule::in($allowedLocales)],
|
||||
'region' => ['required', Rule::in($allowedRegions)],
|
||||
'date_format' => ['required', 'in:mdy,dmy,ymd'],
|
||||
'time_format' => ['required', 'in:12,24'],
|
||||
'timezone' => ['required', 'string', Rule::in($allowedTimezones)],
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
// set language and timezone to their dedicated columns
|
||||
$user->locale = $data['language'];
|
||||
$user->timezone = $data['timezone'];
|
||||
|
||||
// everything else to json settings
|
||||
$user->setSettings([
|
||||
'app.region' => $data['region'],
|
||||
'app.date_format' => $data['date_format'],
|
||||
'app.time_format' => $data['time_format'],
|
||||
]);
|
||||
|
||||
$user->save();
|
||||
|
||||
// apply locale immediately
|
||||
app()->setLocale($user->locale);
|
||||
|
||||
return Redirect::route('account.locale')
|
||||
->with('toast', __('Settings saved!'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* addresses pane (home + work)
|
||||
*/
|
||||
public function addressesForm(Request $request)
|
||||
|
||||
@ -14,93 +14,10 @@ use Illuminate\Support\Facades\Redirect;
|
||||
|
||||
class CalendarSettingsController extends Controller
|
||||
{
|
||||
/* landing page shows the first settings pane (language/region) */
|
||||
/* landing page shows the first settings pane */
|
||||
public function index()
|
||||
{
|
||||
return redirect()->route('calendar.settings.language');
|
||||
}
|
||||
|
||||
/**
|
||||
* Language and region
|
||||
**/
|
||||
|
||||
/* language and region form */
|
||||
public function languageForm(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
$settings = (array) ($user->settings ?? []);
|
||||
|
||||
return $this->frame('calendar.settings.language', [
|
||||
'title' => __('calendar.settings.language_region.title'),
|
||||
|
||||
'values' => [
|
||||
'language' => $user->getSetting('app.language', app()->getLocale()),
|
||||
'region' => $user->getSetting('app.region', 'US'),
|
||||
'date_format' => $user->getSetting('app.date_format', 'mdy'),
|
||||
'time_format' => $user->getSetting('app.time_format', '12'),
|
||||
],
|
||||
|
||||
'options' => [
|
||||
'languages' => [
|
||||
'en' => 'English',
|
||||
'es' => 'Spanish',
|
||||
'fr' => 'French',
|
||||
'de' => 'German',
|
||||
'it' => 'Italian',
|
||||
'pt' => 'Portuguese',
|
||||
'nl' => 'Dutch',
|
||||
],
|
||||
'regions' => [
|
||||
'US' => 'United States',
|
||||
'CA' => 'Canada',
|
||||
'GB' => 'United Kingdom',
|
||||
'AU' => 'Australia',
|
||||
'NZ' => 'New Zealand',
|
||||
'IE' => 'Ireland',
|
||||
'DE' => 'Germany',
|
||||
'FR' => 'France',
|
||||
'ES' => 'Spain',
|
||||
'IT' => 'Italy',
|
||||
'NL' => 'Netherlands',
|
||||
],
|
||||
'date_formats' => [
|
||||
'mdy' => 'MM/DD/YYYY (01/15/2026)',
|
||||
'dmy' => 'DD/MM/YYYY (15/01/2026)',
|
||||
'ymd' => 'YYYY-MM-DD (2026-01-15)',
|
||||
],
|
||||
'time_formats' => [
|
||||
'12' => '12-hour (1:30 PM)',
|
||||
'24' => '24-hour (13:30)',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/* handle POST from language/region pane */
|
||||
public function languageStore(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'language' => ['required', 'string', 'max:10', 'regex:/^[a-z]{2}([-_][A-Z]{2})?$/'],
|
||||
'region' => ['required', 'string', 'size:2', 'regex:/^[A-Z]{2}$/'],
|
||||
'date_format' => ['required', 'in:mdy,dmy,ymd'],
|
||||
'time_format' => ['required', 'in:12,24'],
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$user->setSettings([
|
||||
'app.language' => $data['language'],
|
||||
'app.region' => $data['region'],
|
||||
'app.date_format' => $data['date_format'],
|
||||
'app.time_format' => $data['time_format'],
|
||||
]);
|
||||
|
||||
// apply immediately for the current request cycle going forward
|
||||
app()->setLocale($data['language']);
|
||||
|
||||
return redirect()
|
||||
->route('calendar.settings.language')
|
||||
->with('toast', __('Settings saved!'));
|
||||
return redirect()->route('calendar.settings.create');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,6 +41,7 @@ class CalendarSettingsController extends Controller
|
||||
];
|
||||
|
||||
if ($request->header('HX-Request')) {
|
||||
$data['redirect'] = route('calendar.index');
|
||||
return view('calendar.partials.create-modal', $data);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class SetUserLocale
|
||||
{
|
||||
@ -12,7 +13,13 @@ class SetUserLocale
|
||||
$user = $request->user();
|
||||
|
||||
if ($user) {
|
||||
// prefer dedicated column
|
||||
$locale = $user->locale;
|
||||
|
||||
// fallback for legacy
|
||||
if (!is_string($locale) || $locale === '') {
|
||||
$locale = $user->getSetting('app.language');
|
||||
}
|
||||
|
||||
if (is_string($locale) && $locale !== '') {
|
||||
app()->setLocale($locale);
|
||||
|
||||
@ -33,6 +33,7 @@ class User extends Authenticatable
|
||||
'email',
|
||||
'timezone',
|
||||
'phone',
|
||||
'locale',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -16,4 +16,53 @@ return [
|
||||
// options: 'first' | 'random'
|
||||
'default_color_strategy' => 'random',
|
||||
],
|
||||
'locales' => [
|
||||
'English' => [
|
||||
'en' => 'English',
|
||||
'en_US' => 'English (United States)',
|
||||
'en_GB' => 'English (United Kingdom)',
|
||||
],
|
||||
'Deutsch' => [
|
||||
'de' => 'Deutsch',
|
||||
'de_DE' => 'Deutsch (Deutschland)',
|
||||
'de_CH' => 'Deutsch (Schweiz)',
|
||||
],
|
||||
'Español' => [
|
||||
'es' => 'Español',
|
||||
'es_MX' => 'Español (México)',
|
||||
],
|
||||
'Italiano' => [
|
||||
'it' => 'Italiano',
|
||||
],
|
||||
],
|
||||
'regions' => [
|
||||
'North America' => [
|
||||
'US' => 'United States',
|
||||
'CA' => 'Canada',
|
||||
'MX' => 'Mexico',
|
||||
],
|
||||
'Europe' => [
|
||||
'GB' => 'United Kingdom',
|
||||
'DE' => 'Germany',
|
||||
'FR' => 'France',
|
||||
'IE' => 'Ireland',
|
||||
'IT' => 'Italy',
|
||||
'NL' => 'Netherlands',
|
||||
'ES' => 'Spain',
|
||||
'CH' => 'Switzerland',
|
||||
],
|
||||
'Oceania' => [
|
||||
'AU' => 'Australia',
|
||||
'NZ' => 'New Zealand',
|
||||
],
|
||||
],
|
||||
'date_formats' => [
|
||||
'mdy' => 'MM/DD/YYYY (12/31/2026)',
|
||||
'dmy' => 'DD/MM/YYYY (31/12/2026)',
|
||||
'ymd' => 'YYYY-MM-DD (2026-12-31)',
|
||||
],
|
||||
'time_formats' => [
|
||||
'12' => '12-hour (1:30 PM)',
|
||||
'24' => '24-hour (13:30)',
|
||||
],
|
||||
];
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// store a laravel locale string, e.g. "en", "es", "pt_BR"
|
||||
$table->string('locale', 12)->nullable()->after('timezone');
|
||||
$table->index('locale');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropIndex(['locale']);
|
||||
$table->dropColumn('locale');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -50,9 +50,13 @@ return [
|
||||
'subtitle' => 'Please enter your password and confirm that you would like to permanently delete your account.',
|
||||
],
|
||||
'information' => [
|
||||
'title' => 'Account information',
|
||||
'title' => 'Personal information',
|
||||
'subtitle' => 'Your name, email address, and other primary account details.',
|
||||
],
|
||||
'locale' => [
|
||||
'title' => 'Locale preferences',
|
||||
'subtitle' => 'Location, timezone, and other regional preferences for calendars and events.'
|
||||
],
|
||||
'password' => [
|
||||
'title' => 'Password',
|
||||
'subtitle' => 'Ensure your account is using a long, random password to stay secure. We always recommend a password manager as well!',
|
||||
|
||||
@ -36,6 +36,7 @@ return [
|
||||
'time_format' => 'Time format',
|
||||
'time_format_select' => 'Select a time format',
|
||||
'timezone' => 'Time zone',
|
||||
'timezone_default' => 'Default time zone',
|
||||
'timezone_select' => 'Select a time zone',
|
||||
|
||||
];
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
@import './lib/calendar.css';
|
||||
@import './lib/checkbox.css';
|
||||
@import './lib/color.css';
|
||||
@import './lib/icon.css';
|
||||
@import './lib/indicator.css';
|
||||
@import './lib/input.css';
|
||||
@import './lib/mini.css';
|
||||
|
||||
@ -87,6 +87,9 @@
|
||||
--shadow-drop: 2.5px 2.5px 0 0 var(--color-primary);
|
||||
--shadow-input: inset 0 0.25rem 0 0 var(--color-gray-100);
|
||||
--shadow-input-hover: inset 0 0.25rem 0 0 var(--color-teal-200);
|
||||
--shadow-checked: inset 2.5px 0 0 var(--color-primary), inset 0 0.25rem 0 0 var(--color-cyan-500);
|
||||
--shadow-active: inset 0 0.25rem 0 0 var(--color-cyan-500);
|
||||
--shadow-sibling: inset 1.5px 0 0 0 var(--color-primary);
|
||||
|
||||
--spacing-md: 1.5px;
|
||||
--spacing-2px: 2px;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
button,
|
||||
.button {
|
||||
@apply relative inline-flex items-center cursor-pointer gap-2 rounded-md h-11 px-4 text-lg font-medium;
|
||||
/*transition: background-color 125ms ease-in-out; */
|
||||
@apply focus:ring-2 focus:ring-offset-2 focus:ring-cyan-600 focus:outline-none;
|
||||
transition: border-color 125ms ease-in-out;
|
||||
@apply outline-0 outline-transparent outline-offset-0;
|
||||
@apply focus:outline-2 focus:outline-offset-2 focus:outline-cyan-600;
|
||||
transition: border-color 125ms ease-in-out, outline 125ms ease-in-out;
|
||||
--button-border: var(--color-primary);
|
||||
--button-accent: var(--color-primary-hover);
|
||||
|
||||
@ -18,15 +18,7 @@ button,
|
||||
border-color: var(--button-accent);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow:
|
||||
2.5px 2.5px 0 0 var(--button-border),
|
||||
0 0 0 2px var(--color-white),
|
||||
0 0 0 4px var(--color-cyan-600);
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply shadow-none outline-none;
|
||||
left: 2.5px;
|
||||
top: 2.5px;
|
||||
}
|
||||
@ -65,7 +57,7 @@ button,
|
||||
aspect-ratio: 1 / 1;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0,0,0,0.075);
|
||||
background-color: rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +75,9 @@ button,
|
||||
> button {
|
||||
@apply relative flex items-center justify-center h-full pl-3.5 pr-3 cursor-pointer;
|
||||
@apply border-md border-primary border-l-0 font-medium rounded-none;
|
||||
/*transition: background-color 100ms ease-in-out; */
|
||||
transition: outline 125ms ease-in-out;
|
||||
box-shadow: var(--shadows);
|
||||
--shadows: none;
|
||||
|
||||
&:hover {
|
||||
@apply bg-cyan-200;
|
||||
@ -92,27 +86,36 @@ button,
|
||||
&:has(input:checked),
|
||||
&:active {
|
||||
@apply bg-cyan-400 border-r-transparent;
|
||||
box-shadow:
|
||||
inset 2.5px 0 0 0 var(--color-primary),
|
||||
inset 0 0.25rem 0 0 var(--color-cyan-500);
|
||||
top: 2.5px;
|
||||
|
||||
+ label,
|
||||
+ button {
|
||||
box-shadow: inset 1.5px 0 0 0 var(--color-primary);
|
||||
}
|
||||
--shadows: var(--shadow-checked);
|
||||
|
||||
&:hover {
|
||||
@apply bg-cyan-500;
|
||||
}
|
||||
|
||||
+ label,
|
||||
+ button {
|
||||
--shadows: var(--shadow-sibling);
|
||||
}
|
||||
}
|
||||
|
||||
&:has(input:checked) {}
|
||||
|
||||
&:first-child {
|
||||
@apply rounded-l-md border-l-md;
|
||||
|
||||
&:has(input:checked),
|
||||
&:active {
|
||||
box-shadow: inset 0 0.25rem 0 0 var(--color-cyan-500);
|
||||
--shadows: var(--shadow-active);
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:active {
|
||||
box-shadow:
|
||||
0 0 0 2px var(--color-white),
|
||||
0 0 0 4px var(--color-cyan-600),
|
||||
var(--focus-ring);
|
||||
--focus-ring: ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +129,10 @@ button,
|
||||
}
|
||||
}
|
||||
|
||||
button:active + button {
|
||||
|
||||
}
|
||||
|
||||
> label {
|
||||
> input[type="radio"] {
|
||||
@apply hidden absolute top-0 left-0 w-0 h-0 max-w-0 max-h-0;
|
||||
|
||||
10
resources/css/lib/icon.css
Normal file
10
resources/css/lib/icon.css
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* icons
|
||||
*/
|
||||
|
||||
/* sizes */
|
||||
.icon-12 { @apply w-3 h-3; }
|
||||
.icon-16 { @apply w-4 h-4; }
|
||||
.icon-20 { @apply w-5 h-5; }
|
||||
.icon-24 { @apply w-6 h-6; }
|
||||
.icon-32 { @apply w-8 h-8; }
|
||||
1
resources/svg/icons/earth.svg
Normal file
1
resources/svg/icons/earth.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.54 15H17a2 2 0 0 0-2 2v4.54"/><path d="M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17"/><path d="M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05"/><circle cx="12" cy="12" r="10"/></svg>
|
||||
|
After Width: | Height: | Size: 433 B |
1
resources/svg/icons/solid/earth.svg
Normal file
1
resources/svg/icons/solid/earth.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M22.116,7.676c0.569,1.328 0.884,2.789 0.884,4.324c0,6.071 -4.929,11 -11,11c-6.071,0 -11,-4.929 -11,-11c0,-6.071 4.929,-11 11,-11c4.479,0 8.336,2.682 10.051,6.527c0.024,0.049 0.046,0.098 0.065,0.149Zm-16.106,-2.391c-1.371,1.224 -2.365,2.861 -2.787,4.715l1.777,-0c1.646,0 3,1.354 3,3l0,1c0,0.549 0.451,1 1,1c1.646,0 3,1.354 3,3l0,3c0.687,0 1.357,-0.077 2,-0.223l-0,-3.777c0,-1.646 1.354,-3 3,-3l3.777,0c0.146,-0.643 0.223,-1.313 0.223,-2c0,-1.052 -0.181,-2.061 -0.513,-3l-2.487,0c-0.55,0 -1,0.45 -1,1c0,1.646 -1.354,3 -3,3c-1.65,0 -3,-1.35 -3,-3c0,-0.549 -0.451,-1 -1,-1c-2.099,0 -3.842,-1.652 -3.99,-3.715Z"/></svg>
|
||||
|
After Width: | Height: | Size: 740 B |
@ -5,12 +5,13 @@
|
||||
|
||||
<div class="description">
|
||||
<p>
|
||||
{{ __('calendar.settings.language_region.subtitle') }}
|
||||
{{ __('account.settings.locale.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ route('calendar.settings.language.store') }}" class="settings">
|
||||
<form method="post" action="{{ route('account.locale.store') }}" class="settings">
|
||||
@csrf
|
||||
@method('patch')
|
||||
|
||||
<div class="input-row input-row--1-1">
|
||||
<div class="input-cell">
|
||||
@ -66,10 +67,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-row input-row--1-1">
|
||||
<div class="input-cell">
|
||||
<x-input.select-label
|
||||
:label="__('common.timezone_default')"
|
||||
id="timezone"
|
||||
name="timezone"
|
||||
placeholder="{{ __('common.timezone_select') }}"
|
||||
:value="$values['timezone']"
|
||||
:options="$options['timezones']"
|
||||
:selected="old('timezone', $values['timezone'])"
|
||||
description="This can be overridden for each calendar."
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('date_format')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-row input-row--actions input-row--start sticky-bottom">
|
||||
<x-button variant="primary" type="submit">{{ __('common.save_changes') }}</x-button>
|
||||
<x-button type="anchor"
|
||||
variant="tertiary"
|
||||
href="{{ route('calendar.settings.language') }}">{{ __('common.cancel') }}</x-button>
|
||||
href="{{ route('account.locale') }}">{{ __('common.cancel') }}</x-button>
|
||||
</div>
|
||||
</form>
|
||||
@ -1,21 +0,0 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="text-xl font-semibold leading-tight">
|
||||
{{ __('Create Calendar') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-6">
|
||||
<div class="max-w-2xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white shadow-sm sm:rounded-lg p-6">
|
||||
<form method="POST" action="{{ route('calendar.store') }}">
|
||||
@csrf
|
||||
|
||||
{{-- just render the form component --}}
|
||||
<x-calendar-form />
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@ -27,7 +27,11 @@
|
||||
<div class="input-row input-row--1-1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="timezone" :value="__('Timezone')" />
|
||||
<x-input.select id="timezone" name="timezone" :options="config('timezones')" :selected="old('timezone', $defaults['timezone'] ?? 'UTC')" />
|
||||
<x-input.select
|
||||
id="timezone"
|
||||
name="timezone"
|
||||
:options="config('timezones')"
|
||||
:selected="old('timezone', $defaults['timezone'] ?? 'UTC')" />
|
||||
<x-input.error :messages="$errors->get('timezone')" />
|
||||
</div>
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
@if ($iconComponent)
|
||||
<x-dynamic-component :component="$iconComponent" width="20" :color="$color" />
|
||||
<x-dynamic-component :component="$iconComponent" class="icon-20" :color="$color" />
|
||||
@endif
|
||||
|
||||
@if (!is_null($label))
|
||||
|
||||
30
resources/views/components/input/select-label.blade.php
Normal file
30
resources/views/components/input/select-label.blade.php
Normal file
@ -0,0 +1,30 @@
|
||||
@props([
|
||||
'label' => '', // label text
|
||||
'labelclass' => '', // extra CSS classes for the label
|
||||
'inputclass' => '', // input classes
|
||||
'id' => '',
|
||||
'name' => '', // input name
|
||||
'disabled' => false, // disabled flag
|
||||
'options' => [],
|
||||
'selected' => '', // input value
|
||||
'placeholder' => '', // placeholder text
|
||||
'style' => '', // raw style string for the input
|
||||
'required' => false, // true/false or truthy value
|
||||
'autocomplete' => false,
|
||||
'description' => '', // optional descriptive text below the input
|
||||
])
|
||||
|
||||
<label {{ $attributes->class("text-label $labelclass") }}>
|
||||
<span class="label">{{ $label }}</span>
|
||||
<x-input.select
|
||||
:id="$id"
|
||||
:name="$name"
|
||||
:class="$inputclass"
|
||||
:options="$options"
|
||||
:selected="$selected"
|
||||
:placeholder="$placeholder"
|
||||
:required="$required"
|
||||
:autocomplete="$autocomplete"
|
||||
{{ $attributes }} />
|
||||
@if($description !== '')<span class="description">{{ $description}}</span>@endif
|
||||
</label>
|
||||
@ -12,10 +12,10 @@
|
||||
</li>
|
||||
<li>
|
||||
<x-app.pagelink
|
||||
href="{{ route('account.password') }}"
|
||||
:active="request()->routeIs('account.password')"
|
||||
:label="__('common.password')"
|
||||
icon="key"
|
||||
href="{{ route('account.locale') }}"
|
||||
:active="request()->routeIs('account.locale', 'account.delete.*')"
|
||||
:label="__('account.settings.locale.title')"
|
||||
icon="earth"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
@ -26,6 +26,19 @@
|
||||
icon="pin"
|
||||
/>
|
||||
</li>
|
||||
</menu>
|
||||
</details>
|
||||
<details open>
|
||||
<summary>{{ __('Account settings') }}</summary>
|
||||
<menu class="content pagelinks">
|
||||
<li>
|
||||
<x-app.pagelink
|
||||
href="{{ route('account.password') }}"
|
||||
:active="request()->routeIs('account.password')"
|
||||
:label="__('common.password')"
|
||||
icon="key"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<x-app.pagelink
|
||||
href="{{ route('account.delete') }}"
|
||||
|
||||
@ -2,14 +2,6 @@
|
||||
<details open>
|
||||
<summary>{{ __('General settings') }}</summary>
|
||||
<menu class="content pagelinks">
|
||||
<li>
|
||||
<x-app.pagelink
|
||||
href="{{ route('calendar.settings.language') }}"
|
||||
:active="request()->routeIs('calendar.settings.language')"
|
||||
:label="__('calendar.settings.language_region.title')"
|
||||
icon="globe"
|
||||
/>
|
||||
</li>
|
||||
</menu>
|
||||
</details>
|
||||
<details open>
|
||||
|
||||
@ -54,6 +54,9 @@ Route::middleware('auth')->group(function ()
|
||||
Route::get('info', [AccountController::class, 'infoForm'])->name('info');
|
||||
Route::patch('info', [AccountController::class, 'infoStore'])->name('info.store');
|
||||
|
||||
Route::get('locale', [AccountController::class, 'localeForm'])->name('locale');
|
||||
Route::patch('locale', [AccountController::class, 'localeStore'])->name('locale.store');
|
||||
|
||||
Route::get('addresses', [AccountController::class, 'addressesForm'])->name('addresses');
|
||||
Route::patch('addresses', [AccountController::class, 'addressesStore'])->name('addresses.store');
|
||||
|
||||
@ -81,10 +84,6 @@ Route::middleware('auth')->group(function ()
|
||||
// settings landing
|
||||
Route::get('settings', [CalendarSettingsController::class, 'index'])->name('settings');
|
||||
|
||||
// language/region settings
|
||||
Route::get('settings/language', [CalendarSettingsController::class, 'languageForm'])->name('settings.language');
|
||||
Route::post('settings/language', [CalendarSettingsController::class, 'languageStore'])->name('settings.language.store');
|
||||
|
||||
// settings / subscribe to a calendar
|
||||
Route::get('settings/subscribe', [CalendarSettingsController::class, 'subscribeForm'])->name('settings.subscribe');
|
||||
Route::post('settings/subscribe', [CalendarSettingsController::class, 'subscribeStore'])->name('settings.subscribe.store');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user