Skip to content

Commit 8563cb3

Browse files
refactor: dirty styles.
1 parent bb2704b commit 8563cb3

6 files changed

Lines changed: 68 additions & 13 deletions

File tree

playwright/workspace-tabs.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ test('editing a synced tab marks it dirty', async ({ page }) => {
282282
const componentTab = page
283283
.getByRole('listitem', { name: 'Workspace tab App.tsx' })
284284
.first()
285-
await expect(componentTab).toContainText('Dirty')
285+
await expect(componentTab.locator('.workspace-tab__dirty-indicator')).toBeVisible()
286+
await expect(page.locator('#component-dirty-status')).toHaveText('Edited')
286287
})
287288

288289
test('removed default styles tab stays removed after reload', async ({ page }) => {

src/app.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,14 @@ const componentPrSyncIcon = document.getElementById('component-pr-sync-icon')
135135
const componentPrSyncIconPath = document.getElementById('component-pr-sync-icon-path')
136136
const stylesPrSyncIcon = document.getElementById('styles-pr-sync-icon')
137137
const stylesPrSyncIconPath = document.getElementById('styles-pr-sync-icon-path')
138-
const componentEditorHeaderLabel = document.querySelector('#editor-header-component span')
139-
const stylesEditorHeaderLabel = document.querySelector('#editor-header-styles span')
138+
const componentEditorHeaderLabel = document.querySelector(
139+
'#editor-header-component [data-editor-header-label]',
140+
)
141+
const stylesEditorHeaderLabel = document.querySelector(
142+
'#editor-header-styles [data-editor-header-label]',
143+
)
144+
const componentEditorDirtyStatus = document.getElementById('component-dirty-status')
145+
const stylesEditorDirtyStatus = document.getElementById('styles-dirty-status')
140146
const aiControlsToggle = document.getElementById('ai-controls-toggle')
141147
const appThemeButtons = document.querySelectorAll('[data-app-theme]')
142148
const workspaceTabsShell = document.getElementById('workspace-tabs-shell')
@@ -194,6 +200,10 @@ const editorHeaderLabelByKind = {
194200
component: componentEditorHeaderLabel,
195201
styles: stylesEditorHeaderLabel,
196202
}
203+
const editorHeaderDirtyStatusByKind = {
204+
component: componentEditorDirtyStatus,
205+
styles: stylesEditorDirtyStatus,
206+
}
197207
const defaultTabNameByKind = {
198208
component: defaultComponentTabName,
199209
styles: defaultStylesTabName,
@@ -499,6 +509,7 @@ const {
499509
editorKinds,
500510
editorPanelsByKind,
501511
editorHeaderLabelByKind,
512+
editorHeaderDirtyStatusByKind,
502513
defaultTabNameByKind,
503514
toNonEmptyWorkspaceText,
504515
getLoadedStylesTabId: () => loadedStylesTabId,

src/index.html

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,15 @@ <h1>
376376
>
377377
<div class="panel-header panel-header--grid">
378378
<h2 id="editor-header-component" class="panel-header__title-with-status">
379-
<span>Component</span>
379+
<span data-editor-header-label>Component</span>
380+
<span
381+
class="panel-header__status panel-header__status--dirty"
382+
id="component-dirty-status"
383+
aria-hidden="true"
384+
hidden
385+
>
386+
Edited
387+
</span>
380388
<svg
381389
class="panel-header__sync-icon"
382390
id="component-pr-sync-icon"
@@ -500,7 +508,15 @@ <h2 id="editor-header-component" class="panel-header__title-with-status">
500508
>
501509
<div class="panel-header panel-header--grid">
502510
<h2 id="editor-header-styles" class="panel-header__title-with-status">
503-
<span>Styles</span>
511+
<span data-editor-header-label>Styles</span>
512+
<span
513+
class="panel-header__status panel-header__status--dirty"
514+
id="styles-dirty-status"
515+
aria-hidden="true"
516+
hidden
517+
>
518+
Edited
519+
</span>
504520
<svg
505521
class="panel-header__sync-icon"
506522
id="styles-pr-sync-icon"

src/modules/app-core/workspace-editor-helpers.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const createWorkspaceEditorHelpers = ({
44
editorKinds,
55
editorPanelsByKind,
66
editorHeaderLabelByKind,
7+
editorHeaderDirtyStatusByKind,
78
defaultTabNameByKind,
89
toNonEmptyWorkspaceText,
910
getLoadedStylesTabId,
@@ -45,11 +46,22 @@ const createWorkspaceEditorHelpers = ({
4546
: (workspaceTabsState.getTab(getLoadedComponentTabId()) ??
4647
getWorkspaceTabByKind('component'))
4748
const headerLabel = editorHeaderLabelByKind[editorKind]
49+
const dirtyStatusLabel = editorHeaderDirtyStatusByKind[editorKind]
4850

4951
if (headerLabel) {
5052
headerLabel.textContent =
5153
toNonEmptyWorkspaceText(tab?.name) || defaultTabNameByKind[editorKind]
5254
}
55+
56+
if (dirtyStatusLabel instanceof HTMLElement) {
57+
const isDirty = Boolean(tab?.isDirty)
58+
dirtyStatusLabel.hidden = !isDirty
59+
if (isDirty) {
60+
dirtyStatusLabel.removeAttribute('aria-hidden')
61+
} else {
62+
dirtyStatusLabel.setAttribute('aria-hidden', 'true')
63+
}
64+
}
5365
}
5466
}
5567

src/modules/app-core/workspace-tabs-renderer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ const createWorkspaceTabsRenderer = ({
228228

229229
if (tab.isDirty) {
230230
const dirtyBadge = document.createElement('span')
231-
dirtyBadge.className = 'workspace-tab__meta workspace-tab__meta--dirty'
232-
dirtyBadge.textContent = 'Dirty'
231+
dirtyBadge.className = 'workspace-tab__dirty-indicator'
232+
dirtyBadge.setAttribute('aria-hidden', 'true')
233233
tabContainer.append(dirtyBadge)
234234
}
235235

src/styles/panels-editor.css

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
font-size: 1rem;
2929
}
3030

31-
#editor-header-component span,
32-
#editor-header-styles span {
31+
#editor-header-component [data-editor-header-label],
32+
#editor-header-styles [data-editor-header-label] {
3333
display: inline-block;
3434
max-width: min(42vw, 420px);
3535
overflow: hidden;
@@ -40,12 +40,24 @@
4040

4141
.panel-header__title-with-status {
4242
display: inline-flex;
43-
align-items: center;
43+
align-items: baseline;
4444
gap: 8px;
4545
}
4646

47+
.panel-header__status {
48+
flex: none;
49+
font-size: 0.72rem;
50+
font-weight: 600;
51+
line-height: 1;
52+
}
53+
54+
.panel-header__status--dirty {
55+
color: var(--warning);
56+
}
57+
4758
.panel-header__sync-icon {
4859
display: none;
60+
align-self: center;
4961
width: 14px;
5062
height: 14px;
5163
fill: color-mix(in srgb, var(--focus-ring) 78%, var(--panel-text));
@@ -390,10 +402,13 @@
390402
flex: none;
391403
}
392404

393-
.workspace-tab__meta--dirty {
405+
.workspace-tab__dirty-indicator {
406+
width: 7px;
407+
height: 7px;
408+
border-radius: 999px;
394409
color: var(--warning);
395-
font-weight: 600;
396-
opacity: 1;
410+
background: currentColor;
411+
flex: none;
397412
}
398413

399414
.workspace-tab-add {

0 commit comments

Comments
 (0)