✨ Features added: - 🔍 Implement functional search in header navigation - ⚙️ Add basic user settings page - 📱 Make dashboard fully responsive 🔧 Enhancements: - 🎭 Standardize CSS with consistent theming across components - 🧹 Remove unused CSS for better performance - 📊 Improve dashboard layout and visual hierarchy - 📦 Redesign last block widget for better usability 💅 This commit introduces a cohesive design system with functional design-token components for a more ✨ polished user experience.
296 lines
8.3 KiB
TypeScript
296 lines
8.3 KiB
TypeScript
import { StyledToggle } from '@/components/General/Toggle';
|
|
import { LitElement, html } from 'lit';
|
|
import { customElement, state } from 'lit/decorators.js';
|
|
|
|
import '@components/General/Input';
|
|
import '@components/General/Fieldset';
|
|
import '@components/General/Select';
|
|
|
|
interface DateTimeFormatOptions {
|
|
locale: string;
|
|
weekday: 'long' | 'short' | 'narrow' | '';
|
|
year: 'numeric' | '2-digit' | '';
|
|
month: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow' | '';
|
|
day: 'numeric' | '2-digit' | '';
|
|
hour: 'numeric' | '2-digit' | '';
|
|
minute: 'numeric' | '2-digit' | '';
|
|
second: 'numeric' | '2-digit' | '';
|
|
hour12: boolean;
|
|
}
|
|
|
|
const DEFAULT_OPTIONS: DateTimeFormatOptions = {
|
|
locale: 'en-US',
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: true,
|
|
};
|
|
|
|
@customElement('arx-date-time-settings')
|
|
export class DateTimeSettings extends LitElement {
|
|
@state()
|
|
private options: DateTimeFormatOptions = { ...DEFAULT_OPTIONS };
|
|
|
|
@state()
|
|
private previewDate = new Date();
|
|
|
|
override connectedCallback() {
|
|
super.connectedCallback();
|
|
this.loadFromLocalStorage();
|
|
setInterval(() => {
|
|
this.previewDate = new Date();
|
|
this.requestUpdate();
|
|
}, 1000);
|
|
}
|
|
|
|
private loadFromLocalStorage() {
|
|
const savedOptions = localStorage.getItem('dateTimeFormatOptions');
|
|
if (savedOptions) {
|
|
try {
|
|
this.options = { ...DEFAULT_OPTIONS, ...JSON.parse(savedOptions) };
|
|
} catch (e) {
|
|
console.error('Failed to parse saved options', e);
|
|
this.options = { ...DEFAULT_OPTIONS };
|
|
}
|
|
}
|
|
}
|
|
|
|
private saveToLocalStorage() {
|
|
localStorage.setItem('dateTimeFormatOptions', JSON.stringify(this.options));
|
|
this.dispatchEvent(
|
|
new CustomEvent('settings-changed', {
|
|
bubbles: true,
|
|
composed: true,
|
|
detail: { options: this.options },
|
|
}),
|
|
);
|
|
}
|
|
|
|
private handleChange(key: keyof DateTimeFormatOptions, e: Event) {
|
|
const target = e.target as HTMLSelectElement | HTMLInputElement | StyledToggle;
|
|
let value: string | boolean | undefined = target.value;
|
|
|
|
if (key === 'hour12' && target instanceof StyledToggle) value = target.checked;
|
|
|
|
this.options = {
|
|
...this.options,
|
|
[key]: value,
|
|
};
|
|
|
|
if (key === 'locale') this.requestUpdate();
|
|
|
|
this.saveToLocalStorage();
|
|
}
|
|
|
|
private formatWithOption(option: string, type: keyof DateTimeFormatOptions): string {
|
|
if (option === '') return '';
|
|
const date = this.previewDate;
|
|
const locale = this.options.locale;
|
|
|
|
const formatterOptions: Intl.DateTimeFormatOptions = {
|
|
[type]: option,
|
|
};
|
|
|
|
// Special case for hour to respect hour12 setting
|
|
if (type === 'hour') formatterOptions.hour12 = this.options.hour12;
|
|
|
|
try {
|
|
return new Intl.DateTimeFormat(locale, formatterOptions).format(date);
|
|
} catch (e) {
|
|
console.error(`Error formatting with option ${option} for ${type}`, e);
|
|
return 'Error: Invalid format';
|
|
}
|
|
}
|
|
|
|
private formatPreview(): string {
|
|
return new Date(this.previewDate).toLocaleString(this.options.locale, {
|
|
weekday: this.options.weekday === '' ? undefined : this.options.weekday,
|
|
year: this.options.year === '' ? undefined : this.options.year,
|
|
month: this.options.month === '' ? undefined : this.options.month,
|
|
day: this.options.day === '' ? undefined : this.options.day,
|
|
hour: this.options.hour === '' ? undefined : this.options.hour,
|
|
minute: this.options.minute === '' ? undefined : this.options.minute,
|
|
second: this.options.second === '' ? undefined : this.options.second,
|
|
hour12: this.options.hour12,
|
|
});
|
|
}
|
|
|
|
override render() {
|
|
return html`
|
|
<arx-fieldset legend="Date/Time Settings">
|
|
<arx-input
|
|
label="Locale"
|
|
type="text"
|
|
.value=${this.options.locale}
|
|
@input=${(e: Event) => this.handleChange('locale', e)}
|
|
>
|
|
</arx-input>
|
|
|
|
<arx-select
|
|
label="Weekday Format"
|
|
.value=${this.options.weekday}
|
|
@change=${(e: Event) => this.handleChange('weekday', e)}
|
|
.options=${[
|
|
{
|
|
value: 'long',
|
|
label: `Long (${this.formatWithOption('long', 'weekday')})`,
|
|
},
|
|
{
|
|
value: 'short',
|
|
label: `Short (${this.formatWithOption('short', 'weekday')})`,
|
|
},
|
|
{
|
|
value: 'narrow',
|
|
label: `Narrow (${this.formatWithOption('narrow', 'weekday')})`,
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Year Format"
|
|
.value=${this.options.year}
|
|
@change=${(e: Event) => this.handleChange('year', e)}
|
|
.options=${[
|
|
{
|
|
value: 'numeric',
|
|
label: `Numeric (${this.formatWithOption('numeric', 'year')})`,
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: `2-digit (${this.formatWithOption('2-digit', 'year')})`,
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Month Format"
|
|
.value=${this.options.month}
|
|
@change=${(e: Event) => this.handleChange('month', e)}
|
|
.options=${[
|
|
{
|
|
value: 'long',
|
|
label: `Long (${this.formatWithOption('long', 'month')})`,
|
|
},
|
|
{
|
|
value: 'short',
|
|
label: `Short (${this.formatWithOption('short', 'month')})`,
|
|
},
|
|
{
|
|
value: 'narrow',
|
|
label: `Narrow (${this.formatWithOption('narrow', 'month')})`,
|
|
},
|
|
{
|
|
value: 'numeric',
|
|
label: `Numeric (${this.formatWithOption('numeric', 'month')})`,
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: `2-digit (${this.formatWithOption('2-digit', 'month')})`,
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Day Format"
|
|
.value=${this.options.day}
|
|
@change=${(e: Event) => this.handleChange('day', e)}
|
|
.options=${[
|
|
{
|
|
value: 'numeric',
|
|
label: `Numeric (${this.formatWithOption('numeric', 'day')})`,
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: `2-digit (${this.formatWithOption('2-digit', 'day')})`,
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Hour Format"
|
|
.value=${this.options.hour}
|
|
@change=${(e: Event) => this.handleChange('hour', e)}
|
|
.options=${[
|
|
{
|
|
value: 'numeric',
|
|
label: 'Numeric',
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: '2-digit',
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Minute Format"
|
|
.value=${this.options.minute}
|
|
@change=${(e: Event) => this.handleChange('minute', e)}
|
|
.options=${[
|
|
{
|
|
value: 'numeric',
|
|
label: 'Numeric',
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: '2-digit',
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-select
|
|
label="Second Format"
|
|
.value=${this.options.second}
|
|
@change=${(e: Event) => this.handleChange('second', e)}
|
|
.options=${[
|
|
{
|
|
value: 'numeric',
|
|
label: 'Numeric',
|
|
},
|
|
{
|
|
value: '2-digit',
|
|
label: '2-digit',
|
|
},
|
|
{
|
|
value: '',
|
|
label: 'None',
|
|
},
|
|
]}
|
|
></arx-select>
|
|
|
|
<arx-toggle
|
|
label="Use 12-hour format"
|
|
?checked=${this.options.hour12}
|
|
@change=${(e: Event) => this.handleChange('hour12', e)}
|
|
></arx-toggle>
|
|
|
|
<h3>Preview</h3>
|
|
<p>${this.formatPreview()}</p>
|
|
</arx-fieldset>
|
|
`;
|
|
}
|
|
}
|