Skip to content

Commit 0a30633

Browse files
committed
style(theme): improve dark mode support with data-theme attribute
- Switch dark mode detection from class 'dark' to use data-theme="dark" attribute - Update Tailwind config to enable dark mode with data-theme attribute - Adjust dark theme CSS selectors to target [data-theme="dark"] for consistent styling - Enhance ThemeService to add/remove 'dark' class alongside data-theme attribute for compatibility - Refactor color scheme switcher styles to improve hover and text color effects - Fix rendering logic and add missing imports in dashboards widgets add by type page - Modify dashboards and widgets list layout and hover scale effects - Clean up minor code style and formatting issues across components and services - Add null check for optional clock widget timezones array to prevent runtime errors
1 parent 23bd595 commit 0a30633

File tree

12 files changed

+127
-98
lines changed

12 files changed

+127
-98
lines changed

web/src/app/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,4 @@ export class AppComponent implements OnInit {
164164
new Error('This feature is not available yet')
165165
);
166166
}
167-
}
167+
}

web/src/app/components/theme/color-scheme-switcher.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { ThemeService } from '../../services/theme.service';
2424
fill="none"
2525
strokeLinecap="round"
2626
strokeLinejoin="round"
27+
class="text-gray-700"
2728
>
2829
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
2930
<path
@@ -44,6 +45,7 @@ import { ThemeService } from '../../services/theme.service';
4445
fill="none"
4546
strokeLinecap="round"
4647
strokeLinejoin="round"
48+
class="hover:bg-pastel-blue hover:text-white"
4749
>
4850
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
4951
<path

web/src/app/formly/flat-input-wrapper.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,4 @@ export class FlatInputWrapperComponent extends FieldWrapper<FormlyFieldConfig> {
8888
}
8989
return errors;
9090
}
91-
}
91+
}

web/src/app/pages/dashboards/[dashboardId]/index.page.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export const routeMeta: RouteMeta = {
161161
@if (last) {
162162
<!-- "Add Widget" Button for when there are widgets -->
163163
<div
164-
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer h-40 flex items-center justify-center dark:border-gray-700 dark:hover:bg-pastel-blue/10"
164+
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer h-40 flex items-center justify-center"
165165
>
166166
<div class="text-center">
167167
<p
@@ -176,7 +176,7 @@ export const routeMeta: RouteMeta = {
176176
href="/dashboards/{{
177177
dashboardAndWidgets.dashboard.id
178178
}}/widgets/add/{{ widgetType }}"
179-
class="text-xs bg-gray-200 hover:bg-pastel-blue hover:text-white px-3 py-1 rounded-full transition-colors whitespace-nowrap"
179+
class="text-xs bg-gray-200 hover:bg-gray-300 hover:text-gray-700 px-3 py-1 rounded-full transition-colors whitespace-nowrap"
180180
>
181181
{{ widgetType | titlecase }}
182182
</a>
@@ -205,7 +205,7 @@ export const routeMeta: RouteMeta = {
205205
206206
<!-- "Add Widget" Button -->
207207
<div
208-
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 p-8 flex flex-col items-center justify-center dark:border-gray-700 dark:hover:bg-pastel-blue/10"
208+
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 p-8 flex flex-col items-center justify-center"
209209
>
210210
<p
211211
class="text-gray-500 hover:text-pastel-blue font-bold text-lg flex items-center justify-center mb-4"
@@ -219,7 +219,7 @@ export const routeMeta: RouteMeta = {
219219
href="/dashboards/{{
220220
dashboardAndWidgets.dashboard.id
221221
}}/widgets/add/{{ widgetType }}"
222-
class="text-xs bg-gray-200 hover:bg-pastel-blue hover:text-white px-3 py-1 rounded-full transition-colors whitespace-nowrap"
222+
class="text-xs bg-gray-200 hover:bg-gray-300 hover:text-gray-700 px-3 py-1 rounded-full transition-colors whitespace-nowrap"
223223
>
224224
{{ widgetType | titlecase }}
225225
</a>
@@ -283,7 +283,6 @@ export default class DashboardsEditPageComponent {
283283

284284
onSubmit(model: UpdateDashboardType) {
285285
this.setFormFields({});
286-
// todo: при обновлении не выставляются серверные ошибки валидации, нужно починить
287286
this.dashboardsService
288287
.update(model)
289288
.pipe(
@@ -298,4 +297,4 @@ export default class DashboardsEditPageComponent {
298297
)
299298
.subscribe();
300299
}
301-
}
300+
}

web/src/app/pages/dashboards/[dashboardId]/widgets/add/[type]/index.page.ts

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { RouteMeta } from '@analogjs/router';
2-
import { AsyncPipe, TitleCasePipe } from '@angular/common';
2+
import { AsyncPipe, NgIf, TitleCasePipe } from '@angular/common';
33
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
44
import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
55
import { ActivatedRoute, Router } from '@angular/router';
@@ -33,68 +33,72 @@ export const routeMeta: RouteMeta = {
3333
ReactiveFormsModule,
3434
FormlyForm,
3535
AsyncPipe,
36-
TitleCasePipe,
36+
NgIf,
3737
LucideAngularModule,
38+
TitleCasePipe,
3839
],
39-
template: ` @if (data$ | async; as data) {
40-
<h1 class="text-4xl font-extrabold text-gray-800 mb-2">
41-
Add {{ data.type | titlecase }} Widget
42-
</h1>
43-
<p class="text-xl text-gray-500 mb-8">
44-
<a
45-
href="/dashboards/{{ data.dashboard.id }}"
46-
class="text-gray-500 hover:text-pastel-blue transition-colors mb-10 mt-2 flex items-center"
47-
>
48-
<i-lucide name="arrow-left" class="w-6 h-6 mr-0 lg:mr-2"></i-lucide>
49-
<span class="hidden lg:inline text-lg font-medium"
50-
>Dashboard "{{ data.dashboard.name }}"</span
51-
>
52-
</a>
53-
Configure your new widget.
54-
</p>
40+
template: `
41+
@if (data$ | async; as data) {
42+
<h1 class="text-4xl font-extrabold text-gray-800 mb-2">
43+
Add {{ data.type | titlecase }} Widget
44+
</h1>
5545
56-
<!-- Widget Configuration Panel -->
57-
<div class="bg-white p-6 rounded-2xl long-shadow mb-8 space-y-4">
58-
@if (formFields$ | async; as formlyFields) {
59-
<form
60-
[formGroup]="form"
61-
(ngSubmit)="
62-
onSubmit({ type: data.type, dashboardId: data.dashboard.id })
63-
"
46+
<p class="text-xl text-gray-500 mb-8">
47+
<a
48+
href="/dashboards/{{ data.dashboard.id }}"
49+
class="text-gray-500 hover:text-pastel-blue transition-colors mb-10 mt-2 flex items-center"
6450
>
65-
<formly-form
66-
[form]="form"
67-
[fields]="formlyFields || []"
68-
[(model)]="formModel"
69-
></formly-form>
70-
<div class="flex gap-4">
71-
<a
72-
href="/dashboards/{{ data.dashboard.id }}"
73-
class="flex items-center text-lg font-bold py-3 px-6 rounded-xl text-white bg-gray-500 transition-all duration-300 transform hover:scale-[1.02] flat-btn-shadow mb-8
74-
bg-gradient-to-tr from-[#9CA3AF] to-[#6B7280] tracking-wide cursor-pointer"
75-
>
76-
<i-lucide name="x" class="w-5 h-5 mr-2"></i-lucide>
77-
Cancel
78-
</a>
51+
<i-lucide name="arrow-left" class="w-6 h-6 mr-0 lg:mr-2"></i-lucide>
52+
<span class="hidden lg:inline text-lg font-medium"
53+
>Dashboard "{{ data.dashboard.name }}"</span
54+
>
55+
</a>
56+
Configure your new widget.
57+
</p>
7958
80-
<button
81-
type="submit"
82-
class="flex items-center text-lg font-bold py-3 px-6 rounded-xl text-white bg-pastel-blue transition-all duration-300 transform hover:scale-[1.02] flat-btn-shadow mb-8
83-
bg-gradient-to-tr from-[#8A89F0] to-[#A2C0F5] tracking-wide cursor-pointer"
84-
>
85-
<i-lucide name="plus" class="w-5 h-5 mr-2"></i-lucide>
86-
Add Widget
87-
</button>
88-
</div>
89-
</form>
90-
}
91-
</div>
92-
}`,
59+
<!-- Widget Configuration Panel -->
60+
<div class="bg-white p-6 rounded-2xl long-shadow mb-8 space-y-4">
61+
@if (formFields$ | async; as formlyFields) {
62+
<form
63+
[formGroup]="form"
64+
(ngSubmit)="
65+
onSubmit({ type: data.type, dashboardId: data.dashboard.id })
66+
"
67+
>
68+
<formly-form
69+
[form]="form"
70+
[fields]="formlyFields || []"
71+
[(model)]="formModel"
72+
></formly-form>
73+
<div class="flex gap-4">
74+
<a
75+
href="/dashboards/{{ data.dashboard.id }}"
76+
class="flex items-center text-lg font-bold py-3 px-6 rounded-xl text-white bg-gray-500 transition-all duration-300 transform hover:scale-[1.02] flat-btn-shadow mb-8
77+
bg-gradient-to-tr from-[#9CA3AF] to-[#6B7280] tracking-wide cursor-pointer"
78+
>
79+
<i-lucide name="x" class="w-5 h-5 mr-2"></i-lucide>
80+
Cancel
81+
</a>
82+
83+
<button
84+
type="submit"
85+
class="flex items-center text-lg font-bold py-3 px-6 rounded-xl text-white bg-pastel-blue transition-all duration-300 transform hover:scale-[1.02] flat-btn-shadow mb-8
86+
bg-gradient-to-tr from-[#8A89F0] to-[#A2C0F5] tracking-wide flex items-center justify-center cursor-pointer"
87+
>
88+
<i-lucide name="plus" class="w-5 h-5 mr-2"></i-lucide>
89+
Create Widget
90+
</button>
91+
</div>
92+
</form>
93+
}
94+
</div>
95+
}
96+
`,
9397
})
9498
export default class DashboardsWidgetsAddByTypePageComponent {
95-
private readonly dashboardsService = inject(DashboardsService);
9699
private readonly widgetsService = inject(WidgetsService);
97100
private readonly errorHandlerService = inject(ErrorHandlerService);
101+
private readonly dashboardsService = inject(DashboardsService);
98102
private readonly route = inject(ActivatedRoute);
99103
private readonly router = inject(Router);
100104
private readonly formHandlerService = inject(FormHandlerService);

web/src/app/pages/dashboards/index.page.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,32 @@ export const routeMeta: RouteMeta = {
1313
@Component({
1414
selector: 'dashboards-list-page',
1515
standalone: true,
16-
imports: [AsyncPipe, LucideAngularModule],
1716
changeDetection: ChangeDetectionStrategy.OnPush,
17+
imports: [AsyncPipe, LucideAngularModule],
1818
template: ` <h1 class="text-4xl font-extrabold text-gray-800 mb-2">
1919
Dashboards
2020
</h1>
2121
<p class="text-xl text-gray-500 mb-8">
22-
Manage all your projects in one place.
22+
Manage your dashboards and widgets.
2323
</p>
2424
2525
<div
26-
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-6 gap-8"
26+
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-8"
2727
>
2828
@for (
2929
dashboard of dashboards$ | async;
3030
track dashboard.id;
3131
let last = $last
3232
) {
3333
<a
34-
class="bg-white p-6 rounded-2xl long-shadow transition-all duration-300 hover:scale-[1.01] cursor-pointer"
3534
href="/dashboards/{{ dashboard.id }}"
35+
class="bg-white p-6 rounded-2xl long-shadow transition-all duration-300 hover:scale-[1.02] cursor-pointer"
3636
>
3737
<div class="flex justify-between items-start mb-4">
38-
<!--i
39-
data-lucide="database"
38+
<i-lucide
39+
name="layout-dashboard"
4040
class="w-10 h-10 text-pastel-blue bg-pastel-blue/10 p-2 rounded-lg"
41-
></i-->
41+
></i-lucide>
4242
<span
4343
class="text-sm font-medium text-gray-500 px-3 py-1 bg-gray-100 rounded-full"
4444
>{{ dashboard.isActive ? 'Active' : 'Draft' }}</span
@@ -61,7 +61,7 @@ export const routeMeta: RouteMeta = {
6161
</a>
6262
@if (last) {
6363
<a
64-
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer h-40 flex items-center justify-center dark:border-gray-700 dark:hover:bg-pastel-blue/10"
64+
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer h-40 flex items-center justify-center"
6565
href="/dashboards/new"
6666
>
6767
<i-lucide name="plus" class="w-6 h-6 mr-2"></i-lucide>
@@ -86,7 +86,7 @@ export const routeMeta: RouteMeta = {
8686
</p>
8787
8888
<a
89-
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer p-8 flex flex-col items-center justify-center dark:border-gray-700 dark:hover:bg-pastel-blue/10"
89+
class="border-4 border-dashed border-gray-200 rounded-2xl transition-all duration-300 hover:border-pastel-blue/50 hover:bg-pastel-blue/5 cursor-pointer p-8 flex flex-col items-center justify-center"
9090
href="/dashboards/new"
9191
>
9292
<i-lucide name="plus" class="w-6 h-6 mr-2"></i-lucide>

web/src/app/pages/dashboards/new.page.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ export const routeMeta: RouteMeta = {
2929
changeDetection: ChangeDetectionStrategy.OnPush,
3030
imports: [
3131
FormlyBootstrapModule,
32-
AsyncPipe,
3332
ReactiveFormsModule,
3433
FormlyForm,
34+
AsyncPipe,
3535
LucideAngularModule,
3636
],
3737
template: `
38-
<h1 class="text-4xl font-extrabold text-gray-800 mb-2">New dashboard</h1>
38+
<h1 class="text-4xl font-extrabold text-gray-800 mb-2">
39+
New Dashboard
40+
</h1>
3941
<p class="text-xl text-gray-500 mb-8">
4042
<a
4143
href="/dashboards"
@@ -122,4 +124,4 @@ export default class DashboardsNewPageComponent {
122124
)
123125
.subscribe();
124126
}
125-
}
127+
}

web/src/app/pages/login.page.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,4 @@ export default class LoginPageComponent {
159159
)
160160
.subscribe();
161161
}
162-
}
162+
}

web/src/app/services/theme.service.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,23 @@ export class ThemeService extends LocalStorageService<ColorScheme> {
2020
e: StorageChangeType<string>
2121
) => Promise<unknown>)[] = [
2222
async e => {
23-
const htmlTag = this.document.querySelector('html');
24-
23+
const htmlTag = this.document.documentElement;
2524
const theme = e.newValue;
25+
2626
if (!theme) {
2727
await this.set('light');
2828
} else {
29+
// Set the data-theme attribute for any components that might use it
2930
if (htmlTag) {
3031
htmlTag.setAttribute('data-theme', theme);
3132
}
33+
34+
// Apply the appropriate class for Tailwind dark mode
35+
if (theme === 'dark') {
36+
this.document.documentElement.classList.add('dark');
37+
} else {
38+
this.document.documentElement.classList.remove('dark');
39+
}
3240
}
3341
},
3442
];
@@ -51,7 +59,7 @@ export class ThemeService extends LocalStorageService<ColorScheme> {
5159
if (current) {
5260
await this.set(current);
5361
} else {
54-
await this.switchTheme();
62+
await this.set('light'); // Default to light theme
5563
}
5664
}
57-
}
65+
}

web/src/server/widgets/clock-widget.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
/* eslint-disable @typescript-eslint/no-explicit-any */
33
import { FormlyFieldConfig } from '@ngx-formly/core';
4-
import { delay, of, tap } from 'rxjs';
4+
import { of, tap } from 'rxjs';
55
import { z } from 'zod';
66

77
import { getClockName, linkFunctionsToWindow } from './clock-widget.utils';
@@ -50,7 +50,7 @@ export const ClockWidgetSchema = z.object({
5050
hourFormat: z
5151
.enum(ClockWidgetHourFormatKeys as any)
5252
.default(HourFormat['24h']),
53-
timezones: z.array(ClockWidgetTimezoneSchema),
53+
timezones: z.array(ClockWidgetTimezoneSchema).nullish().optional(),
5454
});
5555

5656
export type ClockWidgetTimezoneType = z.infer<typeof ClockWidgetTimezoneSchema>;
@@ -209,7 +209,7 @@ export class ClockWidgetRender implements WidgetRender<ClockWidgetType> {
209209
: '--:--';
210210

211211
// Get current times for the timezones
212-
const mainTimeName = widget.options.timezones[0].name
212+
const mainTimeName = widget.options.timezones[0]?.name
213213
? getClockName(widget.id, 'main')
214214
: '--:--';
215215
const smallTime1Name = widget.options.timezones[1]

0 commit comments

Comments
 (0)