diff --git a/.playwright-mcp/amber-gold-headers.png b/.playwright-mcp/amber-gold-headers.png
new file mode 100644
index 0000000..beda94f
Binary files /dev/null and b/.playwright-mcp/amber-gold-headers.png differ
diff --git a/.playwright-mcp/amber-gold-hover.png b/.playwright-mcp/amber-gold-hover.png
new file mode 100644
index 0000000..40dc3e3
Binary files /dev/null and b/.playwright-mcp/amber-gold-hover.png differ
diff --git a/.playwright-mcp/filter-after-click.png b/.playwright-mcp/filter-after-click.png
new file mode 100644
index 0000000..3b3031e
Binary files /dev/null and b/.playwright-mcp/filter-after-click.png differ
diff --git a/.playwright-mcp/filter-after-fix.png b/.playwright-mcp/filter-after-fix.png
new file mode 100644
index 0000000..4c7fda0
Binary files /dev/null and b/.playwright-mcp/filter-after-fix.png differ
diff --git a/.playwright-mcp/filter-before-click.png b/.playwright-mcp/filter-before-click.png
new file mode 100644
index 0000000..7c243d9
Binary files /dev/null and b/.playwright-mcp/filter-before-click.png differ
diff --git a/.playwright-mcp/muted-grey-headers.png b/.playwright-mcp/muted-grey-headers.png
new file mode 100644
index 0000000..7bb85e7
Binary files /dev/null and b/.playwright-mcp/muted-grey-headers.png differ
diff --git a/.playwright-mcp/muted-grey-hover.png b/.playwright-mcp/muted-grey-hover.png
new file mode 100644
index 0000000..b93b885
Binary files /dev/null and b/.playwright-mcp/muted-grey-hover.png differ
diff --git a/.playwright-mcp/orange-group-headers.png b/.playwright-mcp/orange-group-headers.png
new file mode 100644
index 0000000..24cdc8c
Binary files /dev/null and b/.playwright-mcp/orange-group-headers.png differ
diff --git a/.playwright-mcp/rose-group-headers.png b/.playwright-mcp/rose-group-headers.png
new file mode 100644
index 0000000..4790317
Binary files /dev/null and b/.playwright-mcp/rose-group-headers.png differ
diff --git a/.playwright-mcp/rose-hover-effect.png b/.playwright-mcp/rose-hover-effect.png
new file mode 100644
index 0000000..7740579
Binary files /dev/null and b/.playwright-mcp/rose-hover-effect.png differ
diff --git a/.playwright-mcp/subtle-warm-grey.png b/.playwright-mcp/subtle-warm-grey.png
new file mode 100644
index 0000000..c654cbb
Binary files /dev/null and b/.playwright-mcp/subtle-warm-grey.png differ
diff --git a/.playwright-mcp/teal-group-headers.png b/.playwright-mcp/teal-group-headers.png
new file mode 100644
index 0000000..0e88c38
Binary files /dev/null and b/.playwright-mcp/teal-group-headers.png differ
diff --git a/.playwright-mcp/teal-hover-effect.png b/.playwright-mcp/teal-hover-effect.png
new file mode 100644
index 0000000..66d80be
Binary files /dev/null and b/.playwright-mcp/teal-hover-effect.png differ
diff --git a/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts b/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts
index 0e4e679..793fa9c 100644
--- a/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts
+++ b/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts
@@ -39,23 +39,28 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
themeDefaultStyles,
cssManager.defaultStyles,
css`
- /* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host {
- color: ${cssManager.bdTheme('#09090b', '#fafafa')};
+ /* CSS Variables aligned with secondary menu */
+ --activitylog-bg: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
+ --activitylog-fg: ${cssManager.bdTheme('#525252', '#a3a3a3')};
+ --activitylog-fg-muted: ${cssManager.bdTheme('#737373', '#737373')};
+ --activitylog-fg-active: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
+ --activitylog-border: ${cssManager.bdTheme('#e5e5e5', '#1a1a1a')};
+ --activitylog-hover: ${cssManager.bdTheme('rgba(0, 0, 0, 0.04)', 'rgba(255, 255, 255, 0.06)')};
+ --activitylog-accent: ${cssManager.bdTheme('#78716c', '#b5a99a')};
+
+ color: var(--activitylog-fg);
position: relative;
display: block;
width: 100%;
max-width: 320px;
height: 100%;
- background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
- font-family: 'Geist Mono', monospace;
- border-left: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
+ background: var(--activitylog-bg);
+ font-family: 'Geist Sans', -apple-system, BlinkMacSystemFont, sans-serif;
+ border-left: 1px solid var(--activitylog-border);
cursor: default;
- box-shadow: ${cssManager.bdTheme(
- '-4px 0 12px rgba(0, 0, 0, 0.02)',
- '-4px 0 12px rgba(0, 0, 0, 0.2)'
- )};
}
+
.maincontainer {
position: absolute;
top: 0px;
@@ -64,35 +69,61 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
width: 100%;
}
+ /* Header with streaming indicator */
.topbar {
position: absolute;
top: 0px;
height: 48px;
width: 100%;
- padding: 0px 16px;
- background: ${cssManager.bdTheme('#ffffff', '#09090b')};
- border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
+ padding: 0px 12px;
+ background: var(--activitylog-bg);
+ border-bottom: 1px solid var(--activitylog-border);
display: flex;
align-items: center;
+ justify-content: space-between;
box-sizing: border-box;
}
.topbar .heading {
font-weight: 600;
font-size: 14px;
- font-family: 'Geist Sans', sans-serif;
- color: ${cssManager.bdTheme('#09090b', '#fafafa')};
+ color: var(--activitylog-fg-active);
}
+ .live-indicator {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 10px;
+ font-weight: 500;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--activitylog-fg-muted);
+ }
+
+ .live-indicator .dot {
+ width: 6px;
+ height: 6px;
+ background: ${cssManager.bdTheme('#22c55e', '#22c55e')};
+ border-radius: 50%;
+ animation: pulse 2s ease-in-out infinite;
+ }
+
+ @keyframes pulse {
+ 0%, 100% { opacity: 0.5; transform: scale(0.9); }
+ 50% { opacity: 1; transform: scale(1.1); }
+ }
+
+ /* Activity container */
.activityContainer {
position: absolute;
top: 48px;
bottom: 48px;
width: 100%;
- padding: 12px 0px;
+ padding: 8px 0;
overflow-y: auto;
scrollbar-width: thin;
- scrollbar-color: ${cssManager.bdTheme('#e5e7eb', '#27272a')} transparent;
+ scrollbar-color: ${cssManager.bdTheme('#d4d4d4', '#333333')} transparent;
}
.activityContainer::-webkit-scrollbar {
@@ -104,82 +135,53 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
}
.activityContainer::-webkit-scrollbar-thumb {
- background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
+ background: ${cssManager.bdTheme('#d4d4d4', '#333333')};
border-radius: 3px;
}
.activityContainer::-webkit-scrollbar-thumb:hover {
- background: ${cssManager.bdTheme('#d4d4d8', '#3f3f46')};
+ background: ${cssManager.bdTheme('#a3a3a3', '#525252')};
}
.empty-state {
font-size: 13px;
text-align: center;
- padding: 32px 16px;
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
- font-family: 'Geist Sans', sans-serif;
- }
-
- .streamingIndicator {
- font-size: 11px;
- text-align: center;
- padding: 16px;
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
- font-family: 'Geist Sans', sans-serif;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- font-weight: 500;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- }
-
- .streamingIndicator::before {
- content: '';
- width: 6px;
- height: 6px;
- background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
- border-radius: 50%;
- animation: pulse 2s ease-in-out infinite;
- }
-
- @keyframes pulse {
- 0%, 100% { opacity: 0.4; transform: scale(0.8); }
- 50% { opacity: 1; transform: scale(1.2); }
+ padding: 40px 16px;
+ color: var(--activitylog-fg-muted);
}
+ /* Date separator - warm taupe styling */
.date-separator {
- padding: 12px 16px 8px;
- font-size: 11px;
+ padding: 12px 12px 6px;
+ font-size: 10px;
font-weight: 600;
text-transform: uppercase;
- letter-spacing: 0.05em;
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
- background: ${cssManager.bdTheme('#f9fafb', '#09090b')};
- border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#18181b')};
+ letter-spacing: 0.5px;
+ color: var(--activitylog-accent);
position: sticky;
top: 0;
z-index: 1;
+ background: var(--activitylog-bg);
}
+ /* Activity entry - modern stacked layout */
.activityentry {
- min-height: 36px;
- font-size: 13px;
- padding: 10px 16px;
- border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#18181b')};
- transition: all 0.15s ease;
+ font-size: 12px;
+ padding: 8px 12px;
+ margin: 2px 4px;
+ border-radius: 6px;
+ transition: background 0.15s ease;
display: flex;
- align-items: center;
- gap: 8px;
+ align-items: flex-start;
+ gap: 10px;
line-height: 1.4;
- animation: fadeIn 0.3s ease-out;
+ animation: fadeIn 0.2s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
- transform: translateY(-4px);
+ transform: translateY(-2px);
}
to {
opacity: 1;
@@ -187,88 +189,109 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
}
}
- .activityentry:last-of-type {
- border-bottom: none;
- }
-
.activityentry:hover {
- background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
- }
-
- .timestamp {
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
- font-weight: 500;
- font-size: 12px;
- font-variant-numeric: tabular-nums;
- flex-shrink: 0;
- min-width: 45px;
+ background: var(--activitylog-hover);
}
.activity-icon {
width: 28px;
height: 28px;
border-radius: 6px;
- background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.04)', 'rgba(255, 255, 255, 0.06)')};
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
- font-size: 14px;
+ font-size: 13px;
+ color: var(--activitylog-fg-muted);
+ margin-top: 1px;
}
.activity-icon.login {
- background: ${cssManager.bdTheme('rgba(34, 197, 94, 0.1)', 'rgba(34, 197, 94, 0.1)')};
- color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
+ background: ${cssManager.bdTheme('rgba(34, 197, 94, 0.08)', 'rgba(34, 197, 94, 0.12)')};
+ color: ${cssManager.bdTheme('#16a34a', '#4ade80')};
}
.activity-icon.logout {
- background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.1)', 'rgba(239, 68, 68, 0.1)')};
- color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.08)', 'rgba(239, 68, 68, 0.12)')};
+ color: ${cssManager.bdTheme('#dc2626', '#f87171')};
}
.activity-icon.view {
- background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
- color: ${cssManager.bdTheme('#2563eb', '#3b82f6')};
+ background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.08)', 'rgba(59, 130, 246, 0.12)')};
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
}
.activity-icon.create {
- background: ${cssManager.bdTheme('rgba(168, 85, 247, 0.1)', 'rgba(168, 85, 247, 0.1)')};
- color: ${cssManager.bdTheme('#9333ea', '#a855f7')};
+ background: ${cssManager.bdTheme('rgba(168, 85, 247, 0.08)', 'rgba(168, 85, 247, 0.12)')};
+ color: ${cssManager.bdTheme('#9333ea', '#c084fc')};
}
.activity-icon.update {
- background: ${cssManager.bdTheme('rgba(251, 146, 60, 0.1)', 'rgba(251, 146, 60, 0.1)')};
+ background: ${cssManager.bdTheme('rgba(251, 146, 60, 0.08)', 'rgba(251, 146, 60, 0.12)')};
color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
}
.activity-icon.delete {
- background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.1)', 'rgba(239, 68, 68, 0.1)')};
- color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.08)', 'rgba(239, 68, 68, 0.12)')};
+ color: ${cssManager.bdTheme('#dc2626', '#f87171')};
}
.activity-icon.custom {
- background: ${cssManager.bdTheme('rgba(100, 116, 139, 0.1)', 'rgba(100, 116, 139, 0.1)')};
+ background: ${cssManager.bdTheme('rgba(100, 116, 139, 0.08)', 'rgba(100, 116, 139, 0.12)')};
color: ${cssManager.bdTheme('#475569', '#94a3b8')};
}
- .activity-text {
+ .activity-content {
flex: 1;
- color: ${cssManager.bdTheme('#18181b', '#e4e4e7')};
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
+
+ .activity-header {
+ display: flex;
+ align-items: center;
+ gap: 6px;
}
.activity-user {
font-weight: 600;
- color: ${cssManager.bdTheme('#09090b', '#fafafa')};
+ font-size: 12px;
+ color: var(--activitylog-fg-active);
}
+ .activity-separator {
+ color: var(--activitylog-fg-muted);
+ font-size: 10px;
+ }
+
+ .timestamp {
+ color: var(--activitylog-fg-muted);
+ font-weight: 400;
+ font-size: 11px;
+ font-variant-numeric: tabular-nums;
+ font-family: 'Geist Mono', monospace;
+ }
+
+ .activity-message {
+ color: var(--activitylog-fg);
+ font-size: 12px;
+ line-height: 1.5;
+ word-break: break-word;
+ }
+
+ /* Search box - refined styling */
.searchbox {
position: absolute;
bottom: 0px;
width: 100%;
height: 48px;
- background: ${cssManager.bdTheme('#ffffff', '#09090b')};
- border-top: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
- padding: 8px;
+ background: var(--activitylog-bg);
+ border-top: 1px solid var(--activitylog-border);
+ padding: 8px 12px;
+ box-sizing: border-box;
}
.search-wrapper {
@@ -282,64 +305,37 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
left: 10px;
top: 50%;
transform: translateY(-50%);
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
- font-size: 14px;
+ color: var(--activitylog-fg-muted);
+ font-size: 13px;
pointer-events: none;
transition: color 0.15s ease;
}
.searchbox input {
- color: ${cssManager.bdTheme('#09090b', '#fafafa')};
- background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
+ color: var(--activitylog-fg-active);
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.03)', 'rgba(255, 255, 255, 0.04)')};
width: 100%;
height: 100%;
- border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
+ border: 1px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.08)')};
border-radius: 6px;
- padding: 0 12px 0 36px;
+ padding: 0 12px 0 34px;
font-family: 'Geist Sans', sans-serif;
- font-size: 13px;
+ font-size: 12px;
transition: all 0.15s ease;
}
.searchbox input::placeholder {
- color: ${cssManager.bdTheme('#71717a', '#71717a')};
+ color: var(--activitylog-fg-muted);
}
.searchbox input:focus {
outline: none;
- border-color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
- box-shadow: 0 0 0 3px ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
+ border-color: ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(255, 255, 255, 0.15)')};
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.02)', 'rgba(255, 255, 255, 0.06)')};
}
- .searchbox input:focus ~ .search-icon,
.search-wrapper:has(input:focus) .search-icon {
- color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
- }
-
- .bottomShadow {
- position: absolute;
- width: 100%;
- height: 24px;
- bottom: 48px;
- background: ${cssManager.bdTheme(
- 'linear-gradient(180deg, transparent 0%, #fafafa 100%)',
- 'linear-gradient(180deg, transparent 0%, #0a0a0a 100%)'
- )};
- pointer-events: none;
- opacity: 0.8;
- }
-
- .topShadow {
- position: absolute;
- width: 100%;
- height: 24px;
- top: 48px;
- background: ${cssManager.bdTheme(
- 'linear-gradient(0deg, transparent 0%, #fafafa 100%)',
- 'linear-gradient(0deg, transparent 0%, #0a0a0a 100%)'
- )};
- pointer-events: none;
- opacity: 0.8;
+ color: var(--activitylog-fg);
}
`,
];
@@ -355,12 +351,11 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
Activity Log
+ ${filteredEntries.length > 0
+ ? html`
Live
`
+ : ''}
- ${filteredEntries.length > 0
- ? html`
Live Updates
`
- : ''}
-
${filteredEntries.length === 0
? html`
No activity entries
`
: groupedEntries.map(
@@ -381,8 +376,6 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
/>
-
-
`;
}
@@ -397,12 +390,16 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
class="activityentry"
@contextmenu=${(e: MouseEvent) => this.handleContextMenu(e, entry)}
>
- ${timeStr}
-
-
${entry.user} ${entry.message}
+
`;
diff --git a/ts_web/elements/00group-appui/dees-appui-appbar/component.ts b/ts_web/elements/00group-appui/dees-appui-appbar/component.ts
index b4ce173..3d024e3 100644
--- a/ts_web/elements/00group-appui/dees-appui-appbar/component.ts
+++ b/ts_web/elements/00group-appui/dees-appui-appbar/component.ts
@@ -57,6 +57,16 @@ export class DeesAppuiBar extends DeesElement {
@property({ type: Boolean })
accessor showSearch: boolean = false;
+ // Activity log toggle
+ @property({ type: Boolean })
+ accessor showActivityLogToggle: boolean = false;
+
+ @property({ type: Number })
+ accessor activityLogCount: number = 0;
+
+ @property({ type: Boolean })
+ accessor activityLogActive: boolean = false;
+
// STATE
@state()
accessor activeMenu: string | null = null;
@@ -177,8 +187,8 @@ export class DeesAppuiBar extends DeesElement {
public renderAccountSection(): TemplateResult {
return html`
${this.showSearch ? html`
-
@@ -206,6 +216,18 @@ export class DeesAppuiBar extends DeesElement {
>
` : ''}
+ ${this.showActivityLogToggle ? html`
+
+
+ ${this.activityLogCount > 0 ? html`
+ ${this.activityLogCount > 99 ? '99+' : this.activityLogCount}
+ ` : ''}
+
+ ` : ''}
`;
}
@@ -304,9 +326,16 @@ export class DeesAppuiBar extends DeesElement {
}
private handleSearchClick() {
- this.dispatchEvent(new CustomEvent('search-click', {
+ this.dispatchEvent(new CustomEvent('search-click', {
bubbles: true,
- composed: true
+ composed: true
+ }));
+ }
+
+ private handleActivityToggle() {
+ this.dispatchEvent(new CustomEvent('activity-toggle', {
+ bubbles: true,
+ composed: true
}));
}
diff --git a/ts_web/elements/00group-appui/dees-appui-appbar/styles.ts b/ts_web/elements/00group-appui/dees-appui-appbar/styles.ts
index 790b190..c157b74 100644
--- a/ts_web/elements/00group-appui/dees-appui-appbar/styles.ts
+++ b/ts_web/elements/00group-appui/dees-appui-appbar/styles.ts
@@ -17,7 +17,7 @@ export const appuiAppbarStyles = [
color: ${cssManager.bdTheme('#00000080', '#ffffff80')};
font-size: var(--appbar-font-size);
display: grid;
- grid-template-columns: ${cssManager.cssGridColumns(3, 20)};
+ grid-template-columns: auto 1fr auto;
-webkit-app-region: drag;
user-select: none;
}
@@ -233,6 +233,54 @@ export const appuiAppbarStyles = [
.user-status.away {
background: #ff9800;
}
+
+ /* Activity log toggle button */
+ .activity-toggle {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ height: 28px;
+ padding: 0 8px;
+ border-radius: 6px;
+ cursor: default;
+ -webkit-app-region: no-drag;
+ color: ${cssManager.bdTheme('#00000060', '#ffffff60')};
+ border: 1px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
+ transition: all 0.15s ease;
+ }
+
+ .activity-toggle:hover {
+ background: ${cssManager.bdTheme('#00000010', '#ffffff15')};
+ color: ${cssManager.bdTheme('#000000', '#ffffff')};
+ border-color: transparent;
+ }
+
+ .activity-toggle.active {
+ background: ${cssManager.bdTheme('#00000015', '#ffffff20')};
+ color: ${cssManager.bdTheme('#000000', '#ffffff')};
+ border-color: transparent;
+ }
+
+ .activity-toggle dees-icon {
+ font-size: 14px;
+ }
+
+ .activity-badge {
+ position: relative;
+ margin-left: 4px;
+ min-width: 16px;
+ height: 16px;
+ padding: 0 4px;
+ background: ${cssManager.bdTheme('#525252', '#525252')};
+ color: #fafafa;
+ font-size: 10px;
+ font-weight: 600;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+ }
`,
];
diff --git a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.demo.ts b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.demo.ts
index 8206ddc..41c8b46 100644
--- a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.demo.ts
+++ b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.demo.ts
@@ -12,41 +12,102 @@ export const demoFunc = () => html`
.demo-secondarymenu-container .spacer {
flex: 1;
background: #0f0f0f;
+ padding: 20px;
+ color: #a3a3a3;
+ font-family: 'Geist Sans', sans-serif;
+ }
+ .demo-secondarymenu-container .spacer h3 {
+ color: #fafafa;
+ margin-top: 0;
+ }
+ .demo-secondarymenu-container .spacer code {
+ background: #27272a;
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-size: 12px;
+ }
+ .demo-secondarymenu-container .spacer ul {
+ line-height: 1.8;
}
`;
diff --git a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts
index 1122b3e..2285dd3 100644
--- a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts
+++ b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts
@@ -19,7 +19,16 @@ import { themeDefaultStyles } from '../../00theme.js';
/**
* Secondary navigation menu for sub-navigation within MainMenu views
- * Supports collapsible groups, badges, and dynamic headings
+ *
+ * Supports 8 item types:
+ * 1. Tab - selectable, stays highlighted (default)
+ * 2. Action - executes without selection (blue)
+ * 3. Danger Action - red styling with optional confirmation
+ * 4. Filter - checkbox toggle
+ * 5. Multi-Filter - collapsible box with multiple checkboxes
+ * 6. Divider - visual separator
+ * 7. Header - non-interactive label
+ * 8. Link - opens URL
*/
@customElement('dees-appui-secondarymenu')
export class DeesAppuiSecondarymenu extends DeesElement {
@@ -31,22 +40,30 @@ export class DeesAppuiSecondarymenu extends DeesElement {
@property({ type: String })
accessor heading: string = 'Menu';
- /** Grouped items with collapse support */
+ /** Grouped items with collapse support - supports new ISecondaryMenuGroup */
@property({ type: Array })
- accessor groups: interfaces.IMenuGroup[] = [];
+ accessor groups: interfaces.ISecondaryMenuGroup[] = [];
/** Legacy flat list support for backward compatibility */
@property({ type: Array })
accessor selectionOptions: (interfaces.IMenuItem | { divider: true })[] = [];
- /** Currently selected item */
+ /** Currently selected tab item */
@property({ type: Object })
- accessor selectedItem: interfaces.IMenuItem | null = null;
+ accessor selectedItem: interfaces.ISecondaryMenuItemTab | null = null;
/** Internal state for collapsed groups */
@state()
accessor collapsedGroups: Set = new Set();
+ /** Internal state for collapsed multi-filters */
+ @state()
+ accessor collapsedMultiFilters: Set = new Set();
+
+ /** Render counter to force re-renders when items are mutated */
+ @state()
+ private accessor renderCounter: number = 0;
+
/** Horizontal collapse state */
@property({ type: Boolean, reflect: true })
accessor collapsed: boolean = false;
@@ -80,6 +97,12 @@ export class DeesAppuiSecondarymenu extends DeesElement {
--badge-error-bg: ${cssManager.bdTheme('#fee2e2', '#450a0a')};
--badge-error-fg: ${cssManager.bdTheme('#991b1b', '#f87171')};
+ /* Action colors */
+ --action-primary: ${cssManager.bdTheme('#2563eb', '#3b82f6')};
+ --action-primary-hover: ${cssManager.bdTheme('#1d4ed8', '#60a5fa')};
+ --action-danger: ${cssManager.bdTheme('#dc2626', '#ef4444')};
+ --action-danger-hover: ${cssManager.bdTheme('#b91c1c', '#f87171')};
+
position: relative;
display: block;
height: 100%;
@@ -220,7 +243,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
}
.groupHeader:hover {
- background: var(--sidebar-hover);
+ background: ${cssManager.bdTheme('rgba(140, 120, 100, 0.06)', 'rgba(180, 160, 140, 0.08)')};
}
.groupHeader .groupTitle {
@@ -229,7 +252,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
gap: 8px;
font-size: 11px;
font-weight: 600;
- color: var(--sidebar-fg-muted);
+ color: ${cssManager.bdTheme('#78716c', '#b5a99a')};
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
@@ -238,13 +261,13 @@ export class DeesAppuiSecondarymenu extends DeesElement {
.groupHeader .groupTitle dees-icon {
font-size: 14px;
- opacity: 0.7;
+ color: ${cssManager.bdTheme('#78716c', '#b5a99a')};
}
.groupHeader .chevron {
font-size: 12px;
transition: transform 0.2s ease;
- color: var(--sidebar-fg-muted);
+ color: ${cssManager.bdTheme('#78716c', '#b5a99a')};
}
.groupHeader.collapsed .chevron {
@@ -264,7 +287,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
.groupItems {
overflow: hidden;
transition: max-height 0.25s ease, opacity 0.2s ease;
- max-height: 500px;
+ max-height: 1000px;
opacity: 1;
}
@@ -279,7 +302,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
opacity: 1;
}
- /* Menu Item */
+ /* Menu Item Base */
.menuItem {
position: relative;
display: flex;
@@ -304,6 +327,12 @@ export class DeesAppuiSecondarymenu extends DeesElement {
background: var(--sidebar-active);
}
+ .menuItem.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ pointer-events: none;
+ }
+
.menuItem.selected {
background: var(--sidebar-active);
color: var(--sidebar-fg-active);
@@ -340,6 +369,208 @@ export class DeesAppuiSecondarymenu extends DeesElement {
transition: opacity 0.2s ease, width 0.25s ease;
}
+ /* Action Item Styles */
+ .menuItem.action-primary {
+ color: var(--action-primary);
+ }
+
+ .menuItem.action-primary:hover {
+ color: var(--action-primary-hover);
+ background: ${cssManager.bdTheme('rgba(37, 99, 235, 0.08)', 'rgba(59, 130, 246, 0.12)')};
+ }
+
+ .menuItem.action-primary dees-icon {
+ opacity: 1;
+ }
+
+ .menuItem.action-danger {
+ color: var(--action-danger);
+ }
+
+ .menuItem.action-danger:hover {
+ color: var(--action-danger-hover);
+ background: ${cssManager.bdTheme('rgba(220, 38, 38, 0.08)', 'rgba(239, 68, 68, 0.12)')};
+ }
+
+ .menuItem.action-danger dees-icon {
+ opacity: 1;
+ }
+
+ /* Filter Item Styles */
+ .menuItem.filter {
+ justify-content: space-between;
+ }
+
+ .menuItem.filter .filter-checkbox {
+ width: 16px;
+ height: 16px;
+ border: 2px solid ${cssManager.bdTheme('#d4d4d4', '#525252')};
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.15s ease;
+ flex-shrink: 0;
+ }
+
+ .menuItem.filter .filter-checkbox.checked {
+ background: var(--sidebar-accent);
+ border-color: var(--sidebar-accent);
+ }
+
+ .menuItem.filter .filter-checkbox dees-icon {
+ font-size: 12px;
+ color: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
+ opacity: 1;
+ }
+
+ .menuItem.filter.active {
+ color: var(--sidebar-fg-active);
+ }
+
+ /* Multi-Filter Container */
+ .multiFilter {
+ margin: 4px 0;
+ border: 1px solid var(--sidebar-border);
+ border-radius: 8px;
+ overflow: hidden;
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.02)', 'rgba(255, 255, 255, 0.02)')};
+ }
+
+ .multiFilter-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 12px;
+ cursor: pointer;
+ transition: background 0.15s ease;
+ }
+
+ .multiFilter-header:hover {
+ background: var(--sidebar-hover);
+ }
+
+ .multiFilter-header .multiFilter-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--sidebar-fg-active);
+ }
+
+ .multiFilter-header .multiFilter-title dees-icon {
+ font-size: 16px;
+ opacity: 0.7;
+ }
+
+ .multiFilter-header .multiFilter-count {
+ font-size: 11px;
+ color: var(--sidebar-fg-muted);
+ background: var(--badge-default-bg);
+ padding: 2px 6px;
+ border-radius: 4px;
+ }
+
+ .multiFilter-header .chevron {
+ font-size: 12px;
+ transition: transform 0.2s ease;
+ color: var(--sidebar-fg-muted);
+ }
+
+ .multiFilter-header.collapsed .chevron {
+ transform: rotate(-90deg);
+ }
+
+ .multiFilter-options {
+ border-top: 1px solid var(--sidebar-border);
+ overflow: hidden;
+ transition: max-height 0.25s ease, opacity 0.2s ease;
+ max-height: 500px;
+ opacity: 1;
+ }
+
+ .multiFilter-options.collapsed {
+ max-height: 0;
+ opacity: 0;
+ border-top: none;
+ }
+
+ .multiFilter-option {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 12px;
+ cursor: pointer;
+ transition: background 0.15s ease;
+ font-size: 13px;
+ color: var(--sidebar-fg);
+ }
+
+ .multiFilter-option:hover {
+ background: var(--sidebar-hover);
+ color: var(--sidebar-fg-active);
+ }
+
+ .multiFilter-option .option-checkbox {
+ width: 16px;
+ height: 16px;
+ border: 2px solid ${cssManager.bdTheme('#d4d4d4', '#525252')};
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.15s ease;
+ flex-shrink: 0;
+ }
+
+ .multiFilter-option .option-checkbox.checked {
+ background: var(--sidebar-accent);
+ border-color: var(--sidebar-accent);
+ }
+
+ .multiFilter-option .option-checkbox dees-icon {
+ font-size: 12px;
+ color: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
+ }
+
+ .multiFilter-option dees-icon.option-icon {
+ font-size: 14px;
+ opacity: 0.7;
+ }
+
+ /* Divider */
+ .menuDivider {
+ height: 1px;
+ background: var(--sidebar-border);
+ margin: 8px 12px;
+ }
+
+ :host([collapsed]) .menuDivider {
+ margin: 8px 4px;
+ }
+
+ /* Header/Label */
+ .menuHeader {
+ padding: 12px 12px 4px 12px;
+ font-size: 10px;
+ font-weight: 600;
+ color: var(--sidebar-fg-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ :host([collapsed]) .menuHeader {
+ display: none;
+ }
+
+ /* Link Item */
+ .menuItem.link .external-icon {
+ font-size: 12px;
+ opacity: 0.5;
+ margin-left: auto;
+ }
+
/* Collapsed menu item styles */
:host([collapsed]) .menuItem {
justify-content: center;
@@ -357,6 +588,15 @@ export class DeesAppuiSecondarymenu extends DeesElement {
left: -4px;
}
+ :host([collapsed]) .menuItem .filter-checkbox,
+ :host([collapsed]) .menuItem .external-icon {
+ display: none;
+ }
+
+ :host([collapsed]) .multiFilter {
+ display: none;
+ }
+
/* Tooltip for collapsed state */
.item-tooltip {
position: absolute;
@@ -431,17 +671,17 @@ export class DeesAppuiSecondarymenu extends DeesElement {
display: none;
}
- /* Divider */
+ /* Legacy options container */
+ .legacyOptions {
+ padding: 0 8px;
+ }
+
+ /* Divider (legacy) */
.divider {
height: 1px;
background: var(--sidebar-border);
margin: 8px 12px;
}
-
- /* Legacy options container */
- .legacyOptions {
- padding: 0 8px;
- }
`,
];
@@ -472,28 +712,58 @@ export class DeesAppuiSecondarymenu extends DeesElement {
@click="${() => this.toggleGroup(group.name)}"
>
- ${group.iconName ? html`` : ''}
+ ${group.iconName ? html`` : ''}
${group.name}
- ${group.items.map((item) => this.renderMenuItem(item, group))}
+ ${group.items.map((item) => this.renderItem(item, group))}
`)}
`;
}
- private renderMenuItem(item: interfaces.IMenuItem, group?: interfaces.IMenuGroup): TemplateResult {
+ private renderItem(item: interfaces.ISecondaryMenuItem, group?: interfaces.ISecondaryMenuGroup): TemplateResult {
+ // Check for hidden items
+ if ('hidden' in item && item.hidden) {
+ return html``;
+ }
+
+ // Determine item type
+ const itemType = 'type' in item ? item.type : 'tab';
+
+ switch (itemType) {
+ case 'action':
+ return this.renderActionItem(item as interfaces.ISecondaryMenuItemAction);
+ case 'filter':
+ return this.renderFilterItem(item as interfaces.ISecondaryMenuItemFilter);
+ case 'multiFilter':
+ return this.renderMultiFilterItem(item as interfaces.ISecondaryMenuItemMultiFilter);
+ case 'divider':
+ return this.renderDivider();
+ case 'header':
+ return this.renderHeader(item as interfaces.ISecondaryMenuItemHeader);
+ case 'link':
+ return this.renderLinkItem(item as interfaces.ISecondaryMenuItemLink);
+ case 'tab':
+ default:
+ return this.renderTabItem(item as interfaces.ISecondaryMenuItemTab, group);
+ }
+ }
+
+ private renderTabItem(item: interfaces.ISecondaryMenuItemTab, group?: interfaces.ISecondaryMenuGroup): TemplateResult {
const isSelected = this.selectedItem?.key === item.key;
+ const isDisabled = item.disabled === true;
+
return html`