feat(ui): botões 'rich' em CSS puro + toolbar mobile em 3 linhas organizadas
Sistema de botões (mesma linguagem do Rich Button do spell.sh — que é React/Tailwind e não se aplica a um app vanilla com CSP script-src 'self'): - gradiente vertical com gloss de vidro (::after), borda e sombra derivadas dos tokens, lift no hover, press no active, focus ring, glow no primário - variantes primary/danger/icon/small, selects e segmented control ricos - 100% via color-mix() + light-dark() sobre os tokens: adapta-se sozinho aos 21 temas (color-scheme declarado em todos, incl. nativos agora) - cores antes fixas (#cfe2fa/#e9e6e2/#dcd7d2/#dbe9fb/#e5effb) tokenizadas Toolbar responsiva (≤760px): - fim do scroll horizontal: quebra em 3 linhas — arquivo+formato+versões / alternador de modo full-width / ferramentas de formatação full-width com flex-wrap de segurança; alvos ≥40px - verificado em 393px (última borda 385) e 320px (311), uma linha de ícones sw.js: CACHE notas-shell-v8; README atualizado
This commit is contained in:
1 parent
cb8feac6ff
commit
ea6b3b915d
3 files changed
+181
-42
No files matched your search
@@ -117,11 +117,20 @@ ocupa a tela inteira; menus e toolbar rolam horizontalmente com botões só de
|
||||
guardado em **cookie HttpOnly/SameSite=Lax** (30 dias). A API também aceita
|
||||
`Authorization: Bearer <token>` para scripts.
|
||||
- **Responsivo para celular** (≤760px): barra lateral vira gaveta com backdrop (☰ fecha ao
|
||||
tocar uma nota), painel de versões ocupa a tela toda, toolbar e menus rolam horizontalmente
|
||||
sem rótulos, **dropdowns dos menus posicionados como `fixed`** (o `overflow-x` da menubar não
|
||||
os corta mais em telas pequenas), alvos de toque ampliados, diálogos em largura total, fonte
|
||||
do editor com mínimo de 16px (evita zoom automático do iOS), altura em `dvh` e
|
||||
`safe-area-inset` para notch.
|
||||
tocar uma nota), painel de versões ocupa a tela toda, **toolbar quebra em 3 linhas
|
||||
organizadas** — ① ações de arquivo + formato + versões, ② alternador de modo em largura
|
||||
total, ③ ferramentas de formatação distribuídas (cabe em 393px **e** 320px sem corte) —,
|
||||
alvos de toque ≥40px, diálogos em largura total, fonte do editor com mínimo de 16px (evita
|
||||
zoom automático do iOS), altura em `dvh` e `safe-area-inset` para notch; **dropdowns dos
|
||||
menus em `position:fixed`** (o `overflow-x` da menubar não os corta mais) e menus rolam
|
||||
horizontalmente sem rótulos.
|
||||
- **Botões "rich"** (linguagem visual do Rich Button/spell.sh, mas em CSS puro — o componente
|
||||
deles é React+Tailwind, incompatível com o build-free + CSP do app): gradiente vertical com
|
||||
brilho de vidro, reflexo interno superior, sombra dupla e glow no primário, micro-interações
|
||||
de hover (eleva) / active (pressiona) / focus ring. Tudo derivado dos tokens com
|
||||
`color-mix()` + `light-dark()`, então **os 21 temas** (claros e escuros) ganham botões
|
||||
coerentes automaticamente; o mesmo vale para o controle segmentado Editar/WYSIWYG/Preview,
|
||||
selects da toolbar e chips.
|
||||
- **Estilo Mousepad**: tema claro Greybird-like, menus nativos (Arquivo/Editar/Exibir/Ajuda),
|
||||
atalhos `Ctrl+S`, `Ctrl+N`, `Ctrl+E/M/R` (edição/wysiwyg/preview), `Ctrl+H` (histórico), `F9`
|
||||
(barra lateral), `Ctrl+B/I/K` (formatação), `Ctrl+,` (preferências), `Alt+W`/`Alt+←/→`/
|
||||
|
||||
+166
-36
@@ -1,6 +1,7 @@
|
||||
/* Notas — tema claro sóbrio inspirado no Mousepad (XFCE/Greybird). */
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #f6f5f4;
|
||||
--panel: #ffffff;
|
||||
--panel-2: #f0eeeb;
|
||||
@@ -119,7 +120,7 @@ code { font-family: var(--mono); font-size: 0.92em; }
|
||||
white-space: nowrap;
|
||||
}
|
||||
.menu-dropdown li:hover { background: var(--accent); color: #fff; }
|
||||
.menu-dropdown li:hover .accel { color: #e5effb; }
|
||||
.menu-dropdown li:hover .accel { color: color-mix(in oklab, var(--accent), white 78%); }
|
||||
.menu-dropdown .accel { color: var(--muted); font-size: 11px; }
|
||||
.menu-sep { height: 0; padding: 0; margin: 4px 8px; border-top: 1px solid var(--border-soft); cursor: default; }
|
||||
.menu-sep:hover { background: none; }
|
||||
@@ -141,49 +142,158 @@ code { font-family: var(--mono); font-size: 0.92em; }
|
||||
.tb-grow { flex: 1; }
|
||||
.tb-label { font-size: 12px; margin-left: 4px; }
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Sistema de botões "rich" (mesma linguagem visual do Rich Button do
|
||||
spell.sh — gradientes, brilho interno, glow e micro-interações — porém 100%
|
||||
CSS puro, sem React/Tailwind, derivado dos tokens de tema via color-mix +
|
||||
light-dark, portanto compatível com os 21 temas e com CSP estrita).
|
||||
--------------------------------------------------------------------------- */
|
||||
.btn {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
color: var(--fg);
|
||||
background: var(--panel-2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 3px 10px;
|
||||
border: 1px solid color-mix(in oklab, var(--border) 70%, var(--fg) 30%);
|
||||
border-radius: 8px;
|
||||
padding: 4px 12px;
|
||||
cursor: pointer;
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
color-mix(in oklab, var(--panel-2), white 55%) 0%,
|
||||
var(--panel-2) 48%,
|
||||
color-mix(in oklab, var(--panel-2), var(--fg) 10%) 100%);
|
||||
box-shadow:
|
||||
inset 0 1px 0 light-dark(rgba(255, 255, 255, .85), rgba(255, 255, 255, .14)),
|
||||
inset 0 -1px 0 color-mix(in oklab, var(--panel-2), var(--fg) 14%),
|
||||
0 1px 2px rgba(0, 0, 0, .12),
|
||||
0 2px 6px -2px rgba(0, 0, 0, .10);
|
||||
text-shadow: 0 1px 0 light-dark(rgba(255, 255, 255, .7), rgba(0, 0, 0, .35));
|
||||
transition: transform .12s ease, box-shadow .16s ease, filter .16s ease;
|
||||
}
|
||||
.btn:hover { background: #e6e2dd; }
|
||||
.btn:active { border-color: var(--accent-dark); }
|
||||
.btn:disabled { opacity: .45; cursor: default; }
|
||||
.btn-icon { display: inline-flex; align-items: center; padding: 3px 8px; }
|
||||
.btn-primary { background: var(--accent); border-color: var(--accent-dark); color: #fff; }
|
||||
.btn-primary:hover { background: var(--accent-dark); }
|
||||
.btn-danger { background: var(--danger); border-color: #9c1720; color: #fff; }
|
||||
.btn-small { font-size: 12px; padding: 2px 8px; }
|
||||
.fmt { min-width: 30px; justify-content: center; font-size: 13px; }
|
||||
.btn::after { /* reflexo superior estilo "vidro" */
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 1px 1px 50% 1px;
|
||||
z-index: -1;
|
||||
border-radius: 7px 7px 10px 10px;
|
||||
background: linear-gradient(180deg, light-dark(rgba(255, 255, 255, .5), rgba(255, 255, 255, .07)), transparent);
|
||||
pointer-events: none;
|
||||
}
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
filter: brightness(1.04) saturate(1.05);
|
||||
box-shadow:
|
||||
inset 0 1px 0 light-dark(rgba(255, 255, 255, .9), rgba(255, 255, 255, .18)),
|
||||
inset 0 -1px 0 color-mix(in oklab, var(--panel-2), var(--fg) 16%),
|
||||
0 3px 8px -1px rgba(0, 0, 0, .18),
|
||||
0 6px 16px -6px rgba(0, 0, 0, .14);
|
||||
}
|
||||
.btn:active {
|
||||
transform: translateY(1px) scale(.98);
|
||||
filter: brightness(.97);
|
||||
box-shadow:
|
||||
inset 0 2px 5px rgba(0, 0, 0, .22),
|
||||
inset 0 -1px 0 light-dark(rgba(255, 255, 255, .5), rgba(255, 255, 255, .08));
|
||||
}
|
||||
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
||||
.btn:disabled {
|
||||
opacity: .45;
|
||||
cursor: default;
|
||||
transform: none;
|
||||
filter: saturate(.4);
|
||||
box-shadow: inset 0 1px 0 light-dark(rgba(255, 255, 255, .6), rgba(255, 255, 255, .1));
|
||||
}
|
||||
.btn-icon { display: inline-flex; align-items: center; justify-content: center; padding: 4px 10px; }
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, .25);
|
||||
border-color: color-mix(in oklab, var(--accent), black 28%);
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
color-mix(in oklab, var(--accent), white 26%) 0%,
|
||||
var(--accent) 48%,
|
||||
color-mix(in oklab, var(--accent), black 14%) 100%);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, .38),
|
||||
inset 0 -1px 0 color-mix(in oklab, var(--accent), black 24%),
|
||||
0 2px 8px -1px color-mix(in oklab, var(--accent) 55%, transparent),
|
||||
0 1px 2px rgba(0, 0, 0, .18);
|
||||
}
|
||||
.btn-primary::after { background: linear-gradient(180deg, rgba(255, 255, 255, .28), transparent); }
|
||||
.btn-primary:hover {
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, .45),
|
||||
inset 0 -1px 0 color-mix(in oklab, var(--accent), black 26%),
|
||||
0 4px 14px -2px color-mix(in oklab, var(--accent) 65%, transparent),
|
||||
0 2px 4px rgba(0, 0, 0, .2);
|
||||
}
|
||||
.btn-danger {
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, .25);
|
||||
border-color: color-mix(in oklab, var(--danger), black 26%);
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
color-mix(in oklab, var(--danger), white 24%) 0%,
|
||||
var(--danger) 48%,
|
||||
color-mix(in oklab, var(--danger), black 12%) 100%);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, .35),
|
||||
inset 0 -1px 0 color-mix(in oklab, var(--danger), black 22%),
|
||||
0 2px 8px -1px color-mix(in oklab, var(--danger) 50%, transparent);
|
||||
}
|
||||
.btn-danger::after { background: linear-gradient(180deg, rgba(255, 255, 255, .25), transparent); }
|
||||
.btn-small { font-size: 12px; padding: 2px 9px; border-radius: 6px; }
|
||||
.fmt { min-width: 32px; justify-content: center; font-size: 13px; }
|
||||
#fmt-tools.disabled { opacity: .45; pointer-events: none; }
|
||||
|
||||
#toolbar select {
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
color: var(--fg);
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 3px 6px;
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
color-mix(in oklab, var(--panel), white 40%) 0%,
|
||||
var(--panel) 50%,
|
||||
color-mix(in oklab, var(--panel), var(--fg) 6%) 100%);
|
||||
border: 1px solid color-mix(in oklab, var(--border) 70%, var(--fg) 30%);
|
||||
border-radius: 8px;
|
||||
padding: 4px 8px;
|
||||
box-shadow: inset 0 1px 0 light-dark(rgba(255, 255, 255, .8), rgba(255, 255, 255, .12)), 0 1px 2px rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.segmented { display: inline-flex; border: 1px solid var(--border); border-radius: 4px; overflow: hidden; }
|
||||
.segmented {
|
||||
display: inline-flex;
|
||||
border: 1px solid color-mix(in oklab, var(--border) 70%, var(--fg) 30%);
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
background: color-mix(in oklab, var(--panel-2), var(--fg) 6%);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .12);
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
.segmented .seg {
|
||||
border: 0;
|
||||
background: var(--panel-2);
|
||||
background: transparent;
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
padding: 4px 12px;
|
||||
padding: 4px 14px;
|
||||
cursor: pointer;
|
||||
color: var(--fg);
|
||||
color: var(--muted);
|
||||
border-radius: 7px;
|
||||
transition: background .15s ease, color .15s ease, box-shadow .15s ease;
|
||||
}
|
||||
.segmented .seg:hover { color: var(--fg); background: color-mix(in oklab, var(--panel), transparent 35%); }
|
||||
.segmented .seg.active {
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
color-mix(in oklab, var(--accent), white 22%) 0%,
|
||||
var(--accent) 55%,
|
||||
color-mix(in oklab, var(--accent), black 10%) 100%);
|
||||
color: #fff;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 1px 4px color-mix(in oklab, var(--accent) 50%, transparent);
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, .25);
|
||||
}
|
||||
.segmented .seg + .seg { border-left: 1px solid var(--border); }
|
||||
.segmented .seg.active { background: var(--accent); color: #fff; }
|
||||
|
||||
/* ---------------------------------------------------------------- layout */
|
||||
#layout { display: flex; flex: 1 1 auto; min-height: 0; }
|
||||
@@ -233,7 +343,7 @@ body.sidebar-off #sidebar { display: none; }
|
||||
.tag-chip:hover { border-color: var(--accent); }
|
||||
.tag-chip.active { background: var(--accent); border-color: var(--accent-dark); color: #fff; }
|
||||
.tag-chip .tag-n { color: var(--muted); margin-left: 3px; font-size: 10px; }
|
||||
.tag-chip.active .tag-n { color: #dbe9fb; }
|
||||
.tag-chip.active .tag-n { color: color-mix(in oklab, var(--accent), white 75%); }
|
||||
|
||||
.side-notes { flex: 1 1 auto; border-bottom: 0; display: flex; flex-direction: column; }
|
||||
.side-listhead { display: flex; justify-content: space-between; align-items: baseline; }
|
||||
@@ -244,8 +354,8 @@ body.sidebar-off #sidebar { display: none; }
|
||||
border-bottom: 1px solid var(--border-soft);
|
||||
cursor: pointer;
|
||||
}
|
||||
#notes-list li:hover { background: #e9e6e2; }
|
||||
#notes-list li.active { background: #cfe2fa; box-shadow: inset 3px 0 0 var(--accent); }
|
||||
#notes-list li:hover { background: color-mix(in oklab, var(--panel-2), var(--fg) 9%); }
|
||||
#notes-list li.active { background: color-mix(in oklab, var(--panel), var(--accent) 24%); box-shadow: inset 3px 0 0 var(--accent); }
|
||||
.n-title { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.n-sub { font-size: 11px; color: var(--muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.n-ext { color: var(--accent-dark); font-family: var(--mono); font-size: 10px; }
|
||||
@@ -415,8 +525,8 @@ body.no-gutter #gutter { display: none; }
|
||||
.panel-head .side-label { margin: 0; }
|
||||
#revisions-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 0 1 40%; }
|
||||
#revisions-list li { padding: 7px 10px; border-bottom: 1px solid var(--border-soft); cursor: pointer; }
|
||||
#revisions-list li:hover { background: #e9e6e2; }
|
||||
#revisions-list li.active { background: #cfe2fa; box-shadow: inset 3px 0 0 var(--accent); }
|
||||
#revisions-list li:hover { background: color-mix(in oklab, var(--panel-2), var(--fg) 9%); }
|
||||
#revisions-list li.active { background: color-mix(in oklab, var(--panel), var(--accent) 24%); box-shadow: inset 3px 0 0 var(--accent); }
|
||||
.rev-top { display: flex; justify-content: space-between; font-size: 12px; gap: 8px; }
|
||||
.rev-hash { font-family: var(--mono); color: var(--accent-dark); font-size: 11px; }
|
||||
.rev-msg { font-size: 12px; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
@@ -594,8 +704,8 @@ body.no-gutter #gutter { display: none; }
|
||||
font-size: 13px;
|
||||
color: var(--fg);
|
||||
}
|
||||
.tree-row:hover { background: #e9e6e2; }
|
||||
.tree-row.active { background: #cfe2fa; box-shadow: inset 3px 0 0 var(--accent); }
|
||||
.tree-row:hover { background: color-mix(in oklab, var(--panel-2), var(--fg) 9%); }
|
||||
.tree-row.active { background: color-mix(in oklab, var(--panel), var(--accent) 24%); box-shadow: inset 3px 0 0 var(--accent); }
|
||||
.tree-caret {
|
||||
border: 0;
|
||||
background: none;
|
||||
@@ -625,7 +735,7 @@ body.no-gutter #gutter { display: none; }
|
||||
visibility: hidden;
|
||||
}
|
||||
.tree-row:hover .tree-menu, .tree-row.active .tree-menu { visibility: visible; }
|
||||
.tree-menu:hover { background: #dcd7d2; color: var(--fg); }
|
||||
.tree-menu:hover { background: color-mix(in oklab, var(--panel-2), var(--fg) 14%); color: var(--fg); }
|
||||
|
||||
/* ------------------------------------------------- popover de categorias */
|
||||
#note-meta { position: relative; }
|
||||
@@ -692,11 +802,28 @@ body.no-gutter #gutter { display: none; }
|
||||
.menu-btn { padding: 0 9px; }
|
||||
.menu-dropdown li { padding: 9px 14px; }
|
||||
|
||||
#toolbar { overflow-x: auto; scrollbar-width: none; padding: 0 6px; }
|
||||
#toolbar::-webkit-scrollbar { display: none; }
|
||||
#toolbar {
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
row-gap: 6px;
|
||||
padding: 6px 8px 8px;
|
||||
overflow: visible;
|
||||
}
|
||||
#toolbar .tb-sep, #toolbar .tb-grow { display: none; }
|
||||
.tb-label, .tb-caption { display: none; }
|
||||
.btn-icon { padding: 6px 9px; min-height: 32px; }
|
||||
.segmented .seg { padding: 7px 12px; }
|
||||
#toolbar .tb-group { display: contents; }
|
||||
#toolbar #fmt-tools { display: flex; } /* grupo de formatação permanece unido */
|
||||
/* linha 1: ações de arquivo, botão de versões e seletor de formato */
|
||||
#btn-new, #btn-save, #btn-export, #btn-versions { min-height: 40px; }
|
||||
#toolbar select { min-height: 40px; }
|
||||
/* linha 2: alternador de modo ocupa a largura toda */
|
||||
#mode-toggle { order: 40; flex: 1 1 100%; }
|
||||
#mode-toggle .seg { flex: 1; min-height: 38px; font-size: 13px; }
|
||||
/* linha 3: ferramentas de formatação distribuídas, alvos de toque */
|
||||
#fmt-tools { order: 50; flex: 1 1 100%; min-width: 0; flex-wrap: wrap; justify-content: space-between; }
|
||||
#fmt-tools .fmt { flex: 1 1 0; min-width: 0; min-height: 40px; margin: 1px; padding: 4px 2px; }
|
||||
|
||||
/* sidebar vira gaveta */
|
||||
#sidebar {
|
||||
@@ -746,6 +873,7 @@ body.no-gutter #gutter { display: none; }
|
||||
|
||||
/* ---------------------------------------------------- temas / esquemas */
|
||||
html[data-theme="escuro"] {
|
||||
color-scheme: dark;
|
||||
--bg: #232323;
|
||||
--panel: #1e1e1e;
|
||||
--panel-2: #262626;
|
||||
@@ -788,6 +916,7 @@ html[data-theme="escuro"] #notes-list li:hover,
|
||||
html[data-theme="escuro"] #revisions-list li:hover { background: #303030; }
|
||||
|
||||
html[data-theme="solar-claro"] {
|
||||
color-scheme: light;
|
||||
--bg: #eee8d5;
|
||||
--panel: #fdf6e3;
|
||||
--panel-2: #f4efdc;
|
||||
@@ -825,6 +954,7 @@ html[data-theme="solar-claro"] {
|
||||
}
|
||||
|
||||
html[data-theme="solar-escuro"] {
|
||||
color-scheme: dark;
|
||||
--bg: #073642;
|
||||
--panel: #002b36;
|
||||
--panel-2: #0a3d4a;
|
||||
|
||||
Reference in new issue
Block a user