Add QoL features: preview theme, external resources, shortcuts, mobile layout

- Dark/light preview theme toggle with localStorage persistence and
  dark CSS injection in preview, export, and embed
- External CSS/JS resources modal with per-fiddle persistence in
  options column, injected as link/script tags
- Keyboard shortcuts cheat sheet modal (? button or ? key)
- Mobile-responsive CSS with breakpoints at 768px and 480px
  for both editor and browse pages
This commit is contained in:
root
2026-02-26 15:39:16 -06:00
parent 77f64d2862
commit b18c9c1dc8
8 changed files with 239 additions and 10 deletions

View File

@@ -210,8 +210,8 @@ body.resizing iframe { pointer-events: none; }
/* Dividers */
.divider { background: var(--border); transition: background 0.15s; z-index: 2; }
/* Layout/keybinding selects — match framework select */
#layout-mode, #keybinding-mode {
/* Layout/keybinding/preview-theme selects — match framework select */
#layout-mode, #keybinding-mode, #preview-theme {
background: var(--bg); color: var(--text); border: 1px solid var(--border);
padding: 4px 6px; border-radius: 4px; font-size: 12px; cursor: pointer;
}
@@ -284,3 +284,62 @@ body.resizing iframe { pointer-events: none; }
font-size: 13px; z-index: 999; transition: opacity 0.3s;
}
.toast.hidden { opacity: 0; pointer-events: none; }
/* Resources modal */
.resource-inputs { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.resource-row { display: flex; gap: 6px; align-items: center; }
.resource-row input {
flex: 1; background: var(--bg); border: 1px solid var(--border); color: var(--text);
padding: 5px 8px; border-radius: 4px; font-size: 12px;
}
.resource-row input:focus { border-color: var(--accent); outline: none; }
.resource-list { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow-y: auto; }
.resource-item {
display: flex; align-items: center; justify-content: space-between; gap: 6px;
background: var(--bg); padding: 4px 8px; border-radius: 4px; font-size: 11px;
}
.resource-item .resource-type {
font-size: 9px; font-weight: 700; text-transform: uppercase;
padding: 1px 4px; border-radius: 2px; flex-shrink: 0;
}
.resource-item .resource-type.css { background: #264f78; color: #9cdcfe; }
.resource-item .resource-type.js { background: #4d3b00; color: #dcdcaa; }
.resource-item .resource-url { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-dim); }
.resource-item .resource-remove { cursor: pointer; color: var(--text-dim); background: none; border: none; padding: 0 2px; font-size: 14px; }
.resource-item .resource-remove:hover { color: #f44747; }
/* Shortcuts table */
.shortcuts-table { width: 100%; border-collapse: collapse; text-align: left; }
.shortcuts-table td { padding: 6px 10px; font-size: 13px; border-bottom: 1px solid var(--border); }
.shortcuts-table td:first-child { white-space: nowrap; color: var(--text); }
.shortcuts-table td:last-child { color: var(--text-dim); }
.shortcuts-table kbd {
background: var(--bg); border: 1px solid var(--border); padding: 1px 6px;
border-radius: 3px; font-family: inherit; font-size: 12px;
}
.shortcuts-divider td { font-size: 11px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; padding-top: 12px; border-bottom: none; }
/* Preview dark theme — set iframe bg to match */
#preview-frame.preview-dark { background: #1e1e1e; }
/* Mobile responsive */
@media (max-width: 768px) {
.toolbar { flex-wrap: wrap; height: auto; min-height: var(--toolbar-h); padding: 6px 8px; }
.toolbar-left, .toolbar-right { flex-wrap: wrap; }
.grid {
grid-template-columns: 1fr !important;
grid-template-rows: 1fr 1fr 120px !important;
}
.panel-editor { grid-column: 1 !important; grid-row: 1 !important; }
.panel-preview { grid-column: 1 !important; grid-row: 2 !important; }
.panel-console { grid-column: 1 !important; grid-row: 3 !important; }
.divider-col, .divider-row { display: none !important; }
/* Override all layout variants too */
.layout-top-bottom .panel-editor,
.layout-top-bottom .panel-preview,
.layout-top-bottom .panel-console { grid-column: 1 !important; }
}
@media (max-width: 480px) {
#title-input, .tags-input-wrap { display: none; }
.modal-content { margin: 8px; min-width: unset !important; width: calc(100% - 16px); }
}