diff --git a/changelog.md b/changelog.md
index 321c0be..87afc19 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,14 @@
# Changelog
+## 2026-01-27 - 3.40.0 - feat(dees-tile)
+unify tile badge styling and markup; replace component-specific badge classes with shared tile-badge classes and update related imports/tests
+
+- Add shared badge styles: .tile-badge-corner, .tile-badge-topright, .tile-badge and layout rules in dees-tile-shared/styles.ts
+- Update tile components (audio, video, image, folder, note, pdf) to use new badge markup and remove duplicated badge CSS
+- Shift badge positioning when a tile label is present (.tile-container:has(.tile-label))
+- Remove older per-component badge rules (duration-badge, item-count-badge, dimension-badge, note-language/note-line-indicator, preview-page-indicator) and replace with unified classes
+- Update tests to import dees-contextmenu and dees-dashboardgrid from new 00group-overlay / 00group-layout paths to reflect folder reorganization
+
## 2026-01-27 - 3.39.1 - fix(dees-tile-note)
use horizontal pointer position to scroll note body by computing percentage from clientX and element width instead of clientY and height
diff --git a/test/test.contextmenu-demo.chromium.ts b/test/test.contextmenu-demo.chromium.ts
index 7a362aa..58c358d 100644
--- a/test/test.contextmenu-demo.chromium.ts
+++ b/test/test.contextmenu-demo.chromium.ts
@@ -1,6 +1,6 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
-import { demoFunc } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.demo.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
+import { demoFunc } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.demo.js';
tap.test('should render context menu demo', async () => {
// Create demo container
diff --git a/test/test.contextmenu-nested-close.chromium.ts b/test/test.contextmenu-nested-close.chromium.ts
index d93ab6c..fadca11 100644
--- a/test/test.contextmenu-nested-close.chromium.ts
+++ b/test/test.contextmenu-nested-close.chromium.ts
@@ -1,5 +1,5 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
tap.test('should close all parent menus when clicking action in nested submenu', async () => {
let actionCalled = false;
diff --git a/test/test.contextmenu-shadowdom.chromium.ts b/test/test.contextmenu-shadowdom.chromium.ts
index 0c18630..daca691 100644
--- a/test/test.contextmenu-shadowdom.chromium.ts
+++ b/test/test.contextmenu-shadowdom.chromium.ts
@@ -1,5 +1,5 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
import { DeesElement, customElement, html } from '@design.estate/dees-element';
// Create a test element with shadow DOM
diff --git a/test/test.contextmenu.chromium.ts b/test/test.contextmenu.chromium.ts
index 0e4e151..72a5673 100644
--- a/test/test.contextmenu.chromium.ts
+++ b/test/test.contextmenu.chromium.ts
@@ -1,5 +1,5 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
tap.test('should show context menu with nested submenu', async () => {
// Create a test element with context menu items
diff --git a/test/test.dashboardgrid-layout.node.ts b/test/test.dashboardgrid-layout.node.ts
index fe4ac5a..0b576d5 100644
--- a/test/test.dashboardgrid-layout.node.ts
+++ b/test/test.dashboardgrid-layout.node.ts
@@ -3,8 +3,8 @@ import { tap, expect } from '@git.zone/tstest/tapbundle';
import {
resolveWidgetPlacement,
collectCollisions,
-} from '../ts_web/elements/dees-dashboardgrid/layout.ts';
-import type { DashboardWidget } from '../ts_web/elements/dees-dashboardgrid/types.ts';
+} from '../ts_web/elements/00group-layout/dees-dashboardgrid/layout.ts';
+import type { DashboardWidget } from '../ts_web/elements/00group-layout/dees-dashboardgrid/types.ts';
tap.test('dashboardgrid does not overlap widgets after swap attempt', async () => {
const widgets: DashboardWidget[] = [
diff --git a/test/test.wysiwyg-blocktype-change.chromium.ts b/test/test.wysiwyg-blocktype-change.chromium.ts
index b5f4a5d..ffc279f 100644
--- a/test/test.wysiwyg-blocktype-change.chromium.ts
+++ b/test/test.wysiwyg-blocktype-change.chromium.ts
@@ -1,6 +1,6 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { DeesInputWysiwyg } from '../ts_web/elements/00group-input/dees-input-wysiwyg/dees-input-wysiwyg.js';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
tap.test('should change block type via context menu', async () => {
// Create WYSIWYG editor with a paragraph
diff --git a/test/test.wysiwyg-contextmenu.chromium.ts b/test/test.wysiwyg-contextmenu.chromium.ts
index 5a71a5a..a25f307 100644
--- a/test/test.wysiwyg-contextmenu.chromium.ts
+++ b/test/test.wysiwyg-contextmenu.chromium.ts
@@ -1,6 +1,6 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { DeesInputWysiwyg } from '../ts_web/elements/00group-input/dees-input-wysiwyg/dees-input-wysiwyg.js';
-import { DeesContextmenu } from '../ts_web/elements/dees-contextmenu/dees-contextmenu.js';
+import { DeesContextmenu } from '../ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js';
tap.test('should show context menu on WYSIWYG blocks', async () => {
// Create WYSIWYG editor
diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts
index 1267655..ca6db9f 100644
--- a/ts_web/00_commitinfo_data.ts
+++ b/ts_web/00_commitinfo_data.ts
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@design.estate/dees-catalog',
- version: '3.39.1',
+ version: '3.40.0',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
}
diff --git a/ts_web/elements/00group-media/dees-tile-audio/component.ts b/ts_web/elements/00group-media/dees-tile-audio/component.ts
index c5817a5..357d5c0 100644
--- a/ts_web/elements/00group-media/dees-tile-audio/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-audio/component.ts
@@ -84,20 +84,6 @@ export class DeesTileAudio extends DeesTileBase {
display: block;
}
- .duration-badge {
- position: absolute;
- bottom: 8px;
- right: 8px;
- padding: 3px 8px;
- background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
- color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
- border-radius: 4px;
- font-size: 10px;
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- backdrop-filter: blur(8px);
- z-index: 10;
- }
.play-overlay {
position: absolute;
@@ -177,7 +163,7 @@ export class DeesTileAudio extends DeesTileBase {
${this.duration > 0 ? html`
-
${this.formatTime(this.duration)}
+ ${this.formatTime(this.duration)}
` : ''}
diff --git a/ts_web/elements/00group-media/dees-tile-folder/component.ts b/ts_web/elements/00group-media/dees-tile-folder/component.ts
index d783fa1..6afac57 100644
--- a/ts_web/elements/00group-media/dees-tile-folder/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-folder/component.ts
@@ -109,19 +109,6 @@ export class DeesTileFolder extends DeesTileBase {
background: ${cssManager.bdTheme('hsl(215 15% 96%)', 'hsl(215 20% 16%)')};
}
- .item-count-badge {
- position: absolute;
- bottom: 8px;
- right: 8px;
- padding: 3px 8px;
- background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
- color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
- border-radius: 4px;
- font-size: 10px;
- font-weight: 600;
- backdrop-filter: blur(8px);
- z-index: 10;
- }
`,
] as any;
@@ -158,7 +145,7 @@ export class DeesTileFolder extends DeesTileBase {
-
+
${this.items.length} item${this.items.length !== 1 ? 's' : ''}
diff --git a/ts_web/elements/00group-media/dees-tile-image/component.ts b/ts_web/elements/00group-media/dees-tile-image/component.ts
index b311e1e..93dce48 100644
--- a/ts_web/elements/00group-media/dees-tile-image/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-image/component.ts
@@ -55,24 +55,12 @@ export class DeesTileImage extends DeesTileBase {
opacity: 0;
}
- .dimension-badge {
- position: absolute;
- top: 8px;
- right: 8px;
- padding: 3px 8px;
- background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
- color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
- border-radius: 4px;
- font-size: 10px;
- font-weight: 600;
- backdrop-filter: blur(8px);
- z-index: 15;
- pointer-events: none;
+ .tile-badge-topright.dimension-badge {
opacity: 0;
transition: opacity 0.2s ease;
}
- .tile-container.clickable:hover .dimension-badge {
+ .tile-container.clickable:hover .tile-badge-topright.dimension-badge {
opacity: 1;
}
`,
@@ -110,7 +98,7 @@ export class DeesTileImage extends DeesTileBase {
${this.imageWidth > 0 && this.imageHeight > 0 ? html`
-
+
${this.imageWidth} × ${this.imageHeight}
` : ''}
diff --git a/ts_web/elements/00group-media/dees-tile-note/component.ts b/ts_web/elements/00group-media/dees-tile-note/component.ts
index 187f42d..6bb14c0 100644
--- a/ts_web/elements/00group-media/dees-tile-note/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-note/component.ts
@@ -81,16 +81,10 @@ export class DeesTileNote extends DeesTileBase {
pointer-events: none;
}
- .note-language {
- position: absolute;
- top: 8px;
- right: 8px;
- padding: 2px 6px;
+ .tile-badge-topright.note-language {
background: ${cssManager.bdTheme('hsl(215 20% 92%)', 'hsl(215 20% 88%)')};
color: ${cssManager.bdTheme('hsl(215 16% 50%)', 'hsl(215 16% 40%)')};
- border-radius: 3px;
font-size: 9px;
- font-weight: 600;
text-transform: uppercase;
z-index: 5;
}
@@ -116,21 +110,6 @@ export class DeesTileNote extends DeesTileBase {
padding-right: 6px;
}
- .note-line-indicator {
- position: absolute;
- bottom: 8px;
- right: 8px;
- padding: 3px 8px;
- background: rgba(0, 0, 0, 0.6);
- color: white;
- border-radius: 4px;
- font-size: 9px;
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- backdrop-filter: blur(8px);
- z-index: 10;
- pointer-events: none;
- }
`,
] as any;
@@ -154,7 +133,7 @@ export class DeesTileNote extends DeesTileBase {
return html`
${this.language ? html`
-
${this.language}
+
${this.language}
` : ''}
${this.title ? html`
@@ -169,7 +148,7 @@ export class DeesTileNote extends DeesTileBase {
${this.isHovering && lines.length > 12 ? html`
-
+
Line ${this.getVisibleLineRange(lines.length)}
` : ''}
diff --git a/ts_web/elements/00group-media/dees-tile-pdf/component.ts b/ts_web/elements/00group-media/dees-tile-pdf/component.ts
index f47d14f..78ef637 100644
--- a/ts_web/elements/00group-media/dees-tile-pdf/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-pdf/component.ts
@@ -55,15 +55,14 @@ export class DeesTilePdf extends DeesTileBase {
${this.pageCount > 1 && this.isHovering ? html`
-
+
Page ${this.currentPreviewPage} of ${this.pageCount}
` : ''}
${this.pageCount > 0 && !this.isHovering ? html`
-
-
-
${this.pageCount} page${this.pageCount > 1 ? 's' : ''}
+
+ ${this.pageCount} page${this.pageCount > 1 ? 's' : ''}
` : ''}
diff --git a/ts_web/elements/00group-media/dees-tile-pdf/styles.ts b/ts_web/elements/00group-media/dees-tile-pdf/styles.ts
index 6efbc22..6865e9c 100644
--- a/ts_web/elements/00group-media/dees-tile-pdf/styles.ts
+++ b/ts_web/elements/00group-media/dees-tile-pdf/styles.ts
@@ -35,24 +35,6 @@ export const tilePdfStyles = css`
border-radius: 4px;
}
- .preview-page-indicator {
- position: absolute;
- top: 8px;
- left: 8px;
- right: 8px;
- padding: 5px 8px;
- background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.7)', 'hsl(0 0% 100% / 0.9)')};
- color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
- border-radius: 4px;
- font-size: 11px;
- font-weight: 600;
- text-align: center;
- backdrop-filter: blur(12px);
- z-index: 15;
- pointer-events: none;
- animation: fadeIn 0.2s ease;
- }
-
/* Grid optimizations */
:host([grid-mode]) .preview-canvas {
image-rendering: -webkit-optimize-contrast;
diff --git a/ts_web/elements/00group-media/dees-tile-shared/styles.ts b/ts_web/elements/00group-media/dees-tile-shared/styles.ts
index 17a24ac..6cc0e2c 100644
--- a/ts_web/elements/00group-media/dees-tile-shared/styles.ts
+++ b/ts_web/elements/00group-media/dees-tile-shared/styles.ts
@@ -117,6 +117,46 @@ export const tileBaseStyles = [
animation: fadeIn 0.2s ease;
}
+ .tile-badge-corner {
+ position: absolute;
+ bottom: 8px;
+ right: 8px;
+ padding: 3px 8px;
+ background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
+ color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
+ border-radius: 4px;
+ font-size: 10px;
+ font-weight: 600;
+ font-variant-numeric: tabular-nums;
+ backdrop-filter: blur(8px);
+ z-index: 10;
+ pointer-events: none;
+ }
+
+ .tile-badge-topright {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ padding: 3px 8px;
+ background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
+ color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
+ border-radius: 4px;
+ font-size: 10px;
+ font-weight: 600;
+ backdrop-filter: blur(8px);
+ z-index: 15;
+ pointer-events: none;
+ }
+
+ /* Shift bottom badges up when label is present */
+ .tile-container:has(.tile-label) .tile-badge-corner {
+ bottom: 33px;
+ }
+
+ .tile-container:has(.tile-label) .tile-info {
+ bottom: 33px;
+ }
+
.tile-loading,
.tile-error {
position: absolute;
diff --git a/ts_web/elements/00group-media/dees-tile-video/component.ts b/ts_web/elements/00group-media/dees-tile-video/component.ts
index 9c49058..5c4be35 100644
--- a/ts_web/elements/00group-media/dees-tile-video/component.ts
+++ b/ts_web/elements/00group-media/dees-tile-video/component.ts
@@ -54,20 +54,6 @@ export class DeesTileVideo extends DeesTileBase {
display: block;
}
- .duration-badge {
- position: absolute;
- bottom: 8px;
- right: 8px;
- padding: 3px 8px;
- background: rgba(0, 0, 0, 0.7);
- color: white;
- border-radius: 4px;
- font-size: 10px;
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- backdrop-filter: blur(8px);
- z-index: 10;
- }
.play-overlay {
position: absolute;
@@ -155,7 +141,7 @@ export class DeesTileVideo extends DeesTileBase {
${this.duration > 0 ? html`
-
${this.formatTime(this.duration)}
+
${this.formatTime(this.duration)}
` : ''}
${!this.isHovering ? html`