Skip to content

Commit 1488405

Browse files
committed
refactor: streamline WebUI push notifications spec and enhance job components
- Consolidate WebUI push notifications spec from 1686 to 223 lines - Focus on localhost-only implementation with clear architectural summary - Define core components: WebPushSubscriptionManager, WebPushService, and service worker - Simplify requirements for client ID tracking and subscription persistence - Document VAPID key management and rate limiting approach - Update job-info and job-stats components with Lucide icon system - Replace emoji/text indicators with consistent SVG icons - Improve visual styling and layout for better readability - Extend lucide.ts with additional icons for job tracking UI - Improve shortcut-config-dialog keyboard navigation consistency
1 parent 683796c commit 1488405

8 files changed

Lines changed: 315 additions & 1737 deletions

File tree

ai_specs/webui-push-notifications.md

Lines changed: 186 additions & 1649 deletions
Large diffs are not rendered by default.

src/ui/components/job-info/job-info.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,4 @@
168168
.component-job-info .camera-controls button {
169169
transition: none;
170170
}
171-
}
171+
}

src/ui/components/job-info/job-info.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
<div class="camera-controls">
1313
<button id="btn-preview">Preview On</button>
1414
</div>
15-
</div>
15+
</div>
Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
/**
22
* @fileoverview Job Statistics Component Styles
33
*
4-
* Modern, professional job statistics display with enhanced readability
5-
* and visual hierarchy. Optimized for grid-based layouts with dynamic sizing.
6-
*
7-
* Key features:
8-
* - Flexible height that adapts to grid item size
9-
* - Enhanced typography with proper visual hierarchy
10-
* - Modern card-based panel header
11-
* - Smooth scrolling with refined scrollbar styling
12-
* - Consistent with unified design language
4+
* Compact pill-based presentation matching the Additional Info component to
5+
* deliver a cohesive layout with reduced vertical space usage.
136
*/
147

158
.component-job-stats {
16-
border-top: 1px solid var(--border-color-light);
179
display: flex;
1810
flex-direction: column;
1911
height: 100%;
2012
min-height: 0;
21-
flex: 1 1 auto;
13+
background: transparent;
14+
}
15+
16+
.component-job-stats .job-stats-container {
17+
display: flex;
18+
flex-direction: column;
19+
height: 100%;
20+
min-height: 0;
2221
overflow: hidden;
2322
background: transparent;
2423
}
@@ -37,63 +36,91 @@
3736
}
3837

3938
.component-job-stats .panel-content {
40-
padding: 16px 14px 18px;
41-
flex: 1 1 auto;
42-
overflow: auto;
39+
padding: 10px 8px;
40+
flex: 1;
4341
display: flex;
4442
flex-direction: column;
45-
gap: 12px;
46-
min-height: 0;
43+
justify-content: center;
44+
gap: 6px;
45+
min-width: 200px;
46+
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
47+
overflow: auto;
4748
}
4849

49-
.component-job-stats .info-row {
50+
.component-job-stats .info-display-row {
5051
display: flex;
51-
justify-content: space-between;
5252
align-items: center;
53-
gap: 12px;
54-
flex-wrap: wrap;
55-
padding: 8px 0;
56-
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
53+
justify-content: space-between;
54+
padding: 8px 10px;
55+
background: linear-gradient(135deg, rgba(45, 45, 45, 0.8) 0%, rgba(35, 35, 35, 0.9) 100%);
56+
border-radius: 6px;
57+
border: 1px solid var(--border-color);
58+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), var(--shadow-sm);
59+
transition: all var(--transition-normal);
60+
min-height: 36px;
61+
width: 100%;
62+
backdrop-filter: blur(8px);
5763
}
5864

59-
.component-job-stats .info-row:last-child {
60-
border-bottom: none;
65+
.component-job-stats .info-display-row:hover {
66+
border-color: var(--border-color-light);
67+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow-md);
68+
background: linear-gradient(135deg, rgba(50, 50, 50, 0.85) 0%, rgba(40, 40, 40, 0.95) 100%);
69+
transform: translateY(-1px);
6170
}
6271

6372
.component-job-stats .info-label {
64-
font-size: clamp(11px, 1.4vw, 13px);
65-
font-weight: 600;
73+
font-size: 11px;
74+
font-weight: 700;
6675
color: var(--text-color-secondary);
6776
letter-spacing: 0.5px;
6877
text-transform: uppercase;
78+
min-width: 70px;
79+
flex-shrink: 0;
6980
}
7081

7182
.component-job-stats .info-value {
72-
font-size: clamp(14px, 1.6vw, 16px);
83+
font-size: 14px;
7384
font-weight: 700;
7485
color: var(--text-color);
75-
word-break: break-word;
86+
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', sans-serif;
87+
letter-spacing: 0.2px;
7688
text-align: right;
77-
transition: color var(--transition-normal);
89+
flex-grow: 1;
90+
margin-left: 8px;
91+
transition: color var(--transition-normal), text-shadow var(--transition-normal);
7892
}
7993

80-
.component-job-stats .info-row:hover .info-value {
94+
.component-job-stats .info-value:hover {
8195
color: var(--accent-color);
96+
text-shadow: 0 0 12px rgba(66, 133, 244, 0.3);
8297
}
8398

84-
@media (max-width: 900px) {
85-
.component-job-stats .info-row {
86-
align-items: flex-start;
99+
@media (max-width: 768px) {
100+
.component-job-stats .panel-content {
101+
padding: 12px 8px;
102+
gap: 8px;
103+
}
104+
105+
.component-job-stats .info-label {
106+
font-size: 10px;
107+
min-width: 60px;
87108
}
88109

89110
.component-job-stats .info-value {
90-
width: 100%;
111+
font-size: 13px;
91112
}
92113
}
93114

94-
@media (max-height: 600px) {
95-
.component-job-stats .panel-content {
96-
padding: 8px 10px 12px;
97-
gap: 8px;
115+
@media (prefers-contrast: high) {
116+
.component-job-stats .info-display-row {
117+
border-color: var(--border-color-light);
118+
}
119+
}
120+
121+
@media (prefers-reduced-motion: reduce) {
122+
.component-job-stats .info-display-row,
123+
.component-job-stats .info-value {
124+
transition: none;
98125
}
99126
}

src/ui/components/job-stats/job-stats.html

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,28 @@
1212
component-scoped selectors and proper semantic markup.
1313
-->
1414

15-
<div class="panel-header">Job Info</div>
16-
<div class="panel-content">
17-
<div class="info-row">
18-
<span class="info-label">Layer:</span>
19-
<span class="info-value" id="layer-info">0 / 0</span>
15+
<div class="job-stats-container">
16+
<div class="panel-header">Job Info</div>
17+
<div class="panel-content">
18+
<div class="info-display-row">
19+
<span class="info-label">Layer:</span>
20+
<span class="info-value" id="layer-info">0 / 0</span>
21+
</div>
22+
<div class="info-display-row">
23+
<span class="info-label">ETA:</span>
24+
<span class="info-value" id="eta">--:--</span>
25+
</div>
26+
<div class="info-display-row">
27+
<span class="info-label">Job Time:</span>
28+
<span class="info-value" id="job-time">00:00</span>
29+
</div>
30+
<div class="info-display-row">
31+
<span class="info-label">Weight:</span>
32+
<span class="info-value" id="weight">0g</span>
33+
</div>
34+
<div class="info-display-row">
35+
<span class="info-label">Length:</span>
36+
<span class="info-value" id="length">0m</span>
37+
</div>
2038
</div>
21-
<div class="info-row">
22-
<span class="info-label">ETA:</span>
23-
<span class="info-value" id="eta">--:--</span>
24-
</div>
25-
<div class="info-row">
26-
<span class="info-label">Job Time:</span>
27-
<span class="info-value" id="job-time">00:00</span>
28-
</div>
29-
<div class="info-row">
30-
<span class="info-label">Weight:</span>
31-
<span class="info-value" id="weight">0g</span>
32-
</div>
33-
<div class="info-row">
34-
<span class="info-label">Length:</span>
35-
<span class="info-value" id="length">0m</span>
36-
</div>
37-
</div>
39+
</div>

src/ui/components/job-stats/job-stats.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,29 +36,33 @@ export class JobStatsComponent extends BaseComponent {
3636
public readonly componentId = 'job-stats';
3737

3838
/** HTML template for the component */
39-
public readonly templateHTML = `<div class="panel-header">Job Info</div>
40-
<div class="panel-content">
41-
<div class="info-row">
42-
<span class="info-label">Layer:</span>
43-
<span class="info-value" id="layer-info">0 / 0</span>
44-
</div>
45-
<div class="info-row">
46-
<span class="info-label">ETA:</span>
47-
<span class="info-value" id="eta">--:--</span>
48-
</div>
49-
<div class="info-row">
50-
<span class="info-label">Job Time:</span>
51-
<span class="info-value" id="job-time">00:00</span>
52-
</div>
53-
<div class="info-row">
54-
<span class="info-label">Weight:</span>
55-
<span class="info-value" id="weight">0g</span>
56-
</div>
57-
<div class="info-row">
58-
<span class="info-label">Length:</span>
59-
<span class="info-value" id="length">0m</span>
60-
</div>
61-
</div>`;
39+
public readonly templateHTML = `
40+
<div class="job-stats-container">
41+
<div class="panel-header">Job Info</div>
42+
<div class="panel-content">
43+
<div class="info-display-row">
44+
<span class="info-label">Layer:</span>
45+
<span class="info-value" id="layer-info">0 / 0</span>
46+
</div>
47+
<div class="info-display-row">
48+
<span class="info-label">ETA:</span>
49+
<span class="info-value" id="eta">--:--</span>
50+
</div>
51+
<div class="info-display-row">
52+
<span class="info-label">Job Time:</span>
53+
<span class="info-value" id="job-time">00:00</span>
54+
</div>
55+
<div class="info-display-row">
56+
<span class="info-label">Weight:</span>
57+
<span class="info-value" id="weight">0g</span>
58+
</div>
59+
<div class="info-display-row">
60+
<span class="info-label">Length:</span>
61+
<span class="info-value" id="length">0m</span>
62+
</div>
63+
</div>
64+
</div>
65+
`;
6266

6367
/**
6468
* Creates a new JobStatsComponent instance

src/ui/shared/lucide.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type LucideGlobal = {
1717
readonly icons?: Record<string, unknown>;
1818
};
1919

20-
interface LucideHelpers {
20+
export interface LucideHelpers {
2121
initializeLucideIconsFromGlobal(iconNames: string[], root?: Document | Element | DocumentFragment): void;
2222
}
2323

src/ui/shortcut-config-dialog/shortcut-config-dialog.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616
* @module ui/shortcut-config-dialog/shortcut-config-dialog
1717
*/
1818

19-
import { initializeLucideIconsFromGlobal } from '../shared/lucide';
19+
import type { LucideHelpers } from '../shared/lucide';
20+
21+
declare global {
22+
interface Window {
23+
lucideHelpers?: LucideHelpers;
24+
}
25+
}
26+
27+
export {};
2028

2129
/**
2230
* Response channel for closing dialog
@@ -191,7 +199,7 @@ function updateComponentsList(): void {
191199
listContainer.appendChild(item);
192200

193201
if (iconsToHydrate.length > 0) {
194-
initializeLucideIconsFromGlobal(iconsToHydrate, item);
202+
window.lucideHelpers?.initializeLucideIconsFromGlobal?.(iconsToHydrate, item);
195203
}
196204
});
197205
}

0 commit comments

Comments
 (0)