Skip to content

Commit 0079a6d

Browse files
feat: clear dialog confirmation.
1 parent d1873ce commit 0079a6d

4 files changed

Lines changed: 166 additions & 11 deletions

File tree

docs/next-steps.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@
22

33
Focused follow-up work for `@knighted/develop`.
44

5-
1. **Grid-first header/layout cleanup**
6-
- Refactor panel header layout to use CSS Grid as the primary layout mechanism.
7-
- Reduce wrapper rows where possible and place controls explicitly in grid areas.
8-
- Preserve existing semantics and accessibility behavior while simplifying structure.
9-
- Validate desktop/mobile breakpoints and keep visual behavior parity.
10-
11-
2. **Style isolation behavior docs**
5+
1. **Style isolation behavior docs**
126
- Document ShadowRoot on/off behavior and how style isolation changes in light DOM mode.
137
- Clarify that light DOM preview can inherit shell styles and include recommendations for scoping.
148

15-
3. **Preview UX polish**
9+
2. **Preview UX polish**
1610
- Keep tooltip affordances for mode-specific behavior.
1711
- Continue tightening panel control alignment and spacing without introducing extra markup.
1812

19-
4. **Theming (light + dark)**
13+
3. **Theming (light + dark)**
2014
- Keep the existing dark mode as the baseline and add a first-class light theme.
2115
- Move key colors to semantic CSS variables and define both theme palettes.
2216
- Ensure component panels, controls, editor chrome, preview shell, and tooltips all have complete light-mode coverage.

src/app.js

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const cssEditor = document.getElementById('css-editor')
1717
const styleWarning = document.getElementById('style-warning')
1818
const cdnLoading = document.getElementById('cdn-loading')
1919
const previewBgColorInput = document.getElementById('preview-bg-color')
20+
const clearConfirmDialog = document.getElementById('clear-confirm-dialog')
21+
const clearConfirmTitle = document.getElementById('clear-confirm-title')
22+
const clearConfirmCopy = document.getElementById('clear-confirm-copy')
2023

2124
jsxEditor.value = defaultJsx
2225
cssEditor.value = defaultCss
@@ -37,6 +40,7 @@ let compiledStylesCache = {
3740
key: null,
3841
value: null,
3942
}
43+
let pendingClearAction = null
4044
let hasCompletedInitialRender = false
4145
let previewBackgroundColor = null
4246
const clipboardSupported = Boolean(navigator.clipboard?.writeText)
@@ -170,18 +174,53 @@ const setCssSource = value => {
170174

171175
const clearComponentSource = () => {
172176
setJsxSource('')
177+
setStatus('Component cleared')
173178
if (!jsxCodeEditor) {
174179
maybeRender()
175180
}
176181
}
177182

178183
const clearStylesSource = () => {
179184
setCssSource('')
185+
setStatus('Styles cleared')
180186
if (!cssCodeEditor) {
181187
maybeRender()
182188
}
183189
}
184190

191+
const confirmClearSource = ({ label, onConfirm }) => {
192+
const supportsModalDialog =
193+
clearConfirmDialog instanceof HTMLDialogElement &&
194+
typeof clearConfirmDialog.showModal === 'function'
195+
196+
if (!supportsModalDialog) {
197+
if (
198+
window.confirm(
199+
`Clear ${label.toLowerCase()} source? This action will remove all text from the editor.`,
200+
)
201+
) {
202+
onConfirm()
203+
}
204+
return
205+
}
206+
207+
if (clearConfirmDialog.open) {
208+
return
209+
}
210+
211+
if (clearConfirmTitle) {
212+
clearConfirmTitle.textContent = `Clear ${label} source?`
213+
}
214+
215+
if (clearConfirmCopy) {
216+
clearConfirmCopy.textContent =
217+
'This action will remove all text from the editor. This cannot be undone.'
218+
}
219+
220+
pendingClearAction = onConfirm
221+
clearConfirmDialog.showModal()
222+
}
223+
185224
const copyTextToClipboard = async text => {
186225
if (!clipboardSupported) {
187226
throw new Error('Clipboard API is not available in this browser context.')
@@ -828,8 +867,28 @@ if (clipboardSupported) {
828867
copyComponentButton.hidden = true
829868
copyStylesButton.hidden = true
830869
}
831-
clearComponentButton.addEventListener('click', clearComponentSource)
832-
clearStylesButton.addEventListener('click', clearStylesSource)
870+
if (clearConfirmDialog instanceof HTMLDialogElement) {
871+
clearConfirmDialog.addEventListener('close', () => {
872+
if (clearConfirmDialog.returnValue === 'confirm') {
873+
pendingClearAction?.()
874+
}
875+
pendingClearAction = null
876+
})
877+
}
878+
879+
clearComponentButton.addEventListener('click', () => {
880+
confirmClearSource({
881+
label: 'Component',
882+
onConfirm: clearComponentSource,
883+
})
884+
})
885+
886+
clearStylesButton.addEventListener('click', () => {
887+
confirmClearSource({
888+
label: 'Styles',
889+
onConfirm: clearStylesSource,
890+
})
891+
})
833892
jsxEditor.addEventListener('input', maybeRender)
834893
cssEditor.addEventListener('input', maybeRender)
835894

src/index.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,28 @@ <h2>Preview</h2>
171171
</div>
172172
</div>
173173

174+
<dialog id="clear-confirm-dialog" class="confirm-dialog">
175+
<form method="dialog" class="confirm-dialog__form">
176+
<h3 id="clear-confirm-title">Clear source?</h3>
177+
<p id="clear-confirm-copy">This action will remove all text from the editor.</p>
178+
<menu class="confirm-dialog__actions">
179+
<button
180+
class="confirm-dialog__button confirm-dialog__button--secondary"
181+
value="cancel"
182+
autofocus
183+
>
184+
Cancel
185+
</button>
186+
<button
187+
class="confirm-dialog__button confirm-dialog__button--danger"
188+
value="confirm"
189+
>
190+
Clear
191+
</button>
192+
</menu>
193+
</form>
194+
</dialog>
195+
174196
<script type="module" src="bootstrap.js"></script>
175197
</body>
176198
</html>

src/styles.css

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,86 @@ textarea:focus {
477477
stroke-linejoin: round;
478478
}
479479

480+
.confirm-dialog {
481+
border: none;
482+
padding: 0;
483+
background: transparent;
484+
color: inherit;
485+
}
486+
487+
.confirm-dialog:modal {
488+
width: min(460px, calc(100vw - 32px));
489+
border: 1px solid rgba(255, 255, 255, 0.14);
490+
border-radius: 14px;
491+
background: rgba(13, 16, 24, 0.97);
492+
color: #e7edf9;
493+
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.45);
494+
}
495+
496+
.confirm-dialog::backdrop {
497+
background: rgba(6, 9, 15, 0.66);
498+
backdrop-filter: blur(2px);
499+
}
500+
501+
.confirm-dialog__form {
502+
margin: 0;
503+
padding: 18px;
504+
}
505+
506+
.confirm-dialog__form h3 {
507+
margin: 0;
508+
font-size: 1.04rem;
509+
}
510+
511+
.confirm-dialog__form p {
512+
margin: 10px 0 0;
513+
color: #b8c3d9;
514+
font-size: 0.9rem;
515+
}
516+
517+
.confirm-dialog__actions {
518+
margin: 18px 0 0;
519+
padding: 0;
520+
list-style: none;
521+
display: flex;
522+
justify-content: flex-end;
523+
gap: 10px;
524+
}
525+
526+
.confirm-dialog__button {
527+
border-radius: 10px;
528+
border: 1px solid transparent;
529+
min-height: 34px;
530+
padding: 6px 14px;
531+
cursor: pointer;
532+
font-weight: 600;
533+
}
534+
535+
.confirm-dialog__button--secondary {
536+
border-color: rgba(255, 255, 255, 0.16);
537+
background: rgba(255, 255, 255, 0.06);
538+
color: #eef3ff;
539+
}
540+
541+
.confirm-dialog__button--secondary:hover {
542+
background: rgba(255, 255, 255, 0.14);
543+
}
544+
545+
.confirm-dialog__button--danger {
546+
border-color: rgba(250, 126, 138, 0.48);
547+
background: rgba(250, 126, 138, 0.2);
548+
color: #ffe7ea;
549+
}
550+
551+
.confirm-dialog__button--danger:hover {
552+
background: rgba(250, 126, 138, 0.32);
553+
}
554+
555+
.confirm-dialog__button:focus-visible {
556+
outline: 2px solid rgba(122, 107, 255, 0.88);
557+
outline-offset: 1px;
558+
}
559+
480560
@media (max-width: 900px) {
481561
.panel-header-main-actions .controls,
482562
.controls--actions {

0 commit comments

Comments
 (0)