Files
crumbs/src/app.css
T
Romain LE DISEZ 5fb0337d03 fix(editor): address PR 67 review feedback
Restore portal dropdown test IDs so the formatting e2e suite can
find heading and link controls again.

Let the mobile formatting toolbar pan horizontally, keep dropdown
portals from drifting by closing them on scroll or resize, and use
visualViewport height for keyboard-aware positioning.

Remove the app-wide maximum-scale lock, keep editor focus targets at
16px on mobile to avoid input auto-zoom, and move toolbar scrollbar
styling to a top-level scoped style block.

Align the remove-link action with the destructive design token, use
the standard 150ms editor slide-up animation, and replace
save/restore body overflow locking with a resilient body class.
2026-07-10 16:19:19 +02:00

256 lines
5.3 KiB
CSS

@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
@import 'tailwindcss';
@plugin '@tailwindcss/typography';
:root {
--bg-base: #f0e6d3;
--bg-surface: #faf5eb;
--primary: #C8860A;
--primary-hover: #E8A020;
--text: #1a1a2e;
--text-muted: #6b6272;
--border: #1a1a2e;
--border-subtle: #d4cabb;
--destructive: #a63d2f;
--error-bg: #f5e0db;
--error-border: #d4a69e;
--error-text: #8b2e1f;
--success-bg: #dce8d4;
--success-text: #3a5a2e;
--card-shadow: 2px 2px 0px var(--border-subtle);
--card-shadow-hover: 3px 3px 0px var(--primary);
--grid-dot: #1a1a2e;
}
[data-theme="dark"] {
--bg-base: #1a1715;
--bg-surface: #2a2520;
--text: #e8dcc8;
--text-muted: #9a8e7e;
--border: #e8dcc8;
--border-subtle: #3a3530;
--destructive: #d4604e;
--error-bg: #3a2020;
--error-border: #5a3030;
--error-text: #e8a090;
--success-bg: #203020;
--success-text: #90c880;
--card-shadow: 2px 2px 0px var(--border-subtle);
--card-shadow-hover: 3px 3px 0px var(--primary);
--grid-dot: #e8dcc8;
}
html, body {
font-family: 'JetBrains Mono', monospace;
accent-color: var(--primary);
overscroll-behavior-y: none;
}
body.editor-scroll-locked {
overflow: hidden;
}
body::before {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
opacity: 0.03;
background-image: repeating-conic-gradient(var(--grid-dot) 0% 25%, transparent 0% 50%);
background-size: 4px 4px;
z-index: 0;
}
/* Editor entrance animations */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes pop-in {
from { opacity: 0; transform: scale(0.95) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
/* Prose overrides for parchment theme */
.prose {
--tw-prose-body: var(--text);
--tw-prose-headings: var(--text);
--tw-prose-links: var(--primary);
--tw-prose-code: var(--text);
--tw-prose-pre-bg: var(--bg-surface);
--tw-prose-pre-code: var(--text);
}
.prose :where(code):not(:where([class~="not-prose"] *)) {
background-color: var(--bg-surface);
border-radius: 2px;
padding: 0.125rem 0.25rem;
}
.prose :where(a):not(:where([class~="not-prose"] *)) {
color: var(--primary);
}
.prose :where(a):not(:where([class~="not-prose"] *)):hover {
color: var(--primary-hover);
}
/* Table styles for TipTap editor */
.tiptap table {
border-collapse: collapse;
width: 100%;
margin: 0.5rem 0;
}
.tiptap th,
.tiptap td {
border: 1px solid var(--border-subtle);
padding: 0.375rem 0.625rem;
text-align: left;
vertical-align: top;
min-width: 4rem;
}
.tiptap th {
font-weight: 600;
background-color: color-mix(in srgb, var(--bg-base) 60%, transparent);
}
.tiptap td p,
.tiptap th p {
margin: 0;
}
.tiptap .selectedCell {
background-color: color-mix(in srgb, var(--primary) 12%, transparent);
}
/* Task list styles — shared between TipTap editor and markdown-it preview */
/* TipTap: ul[data-type="taskList"] | markdown-it: ul.task-list */
.tiptap ul[data-type="taskList"],
.prose ul.task-list {
list-style: none;
padding-left: 0;
margin: 0.25rem 0;
}
.tiptap ul[data-type="taskList"] li,
.prose ul.task-list li {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
gap: 0.375rem;
margin: 0;
padding: 0;
}
/* Nested task lists take full width below the parent item */
.tiptap ul[data-type="taskList"] li > ul[data-type="taskList"],
.prose ul.task-list li > ul.task-list {
flex-basis: 100%;
padding-left: 1.5rem;
}
.tiptap ul[data-type="taskList"] li::marker,
.prose ul.task-list li::marker {
content: none;
}
/* TipTap: checkbox is inside a label */
.tiptap ul[data-type="taskList"] li label {
display: flex;
align-items: center;
flex-shrink: 0;
margin-top: 0.125rem;
}
/* Shared checkbox styles */
.tiptap ul[data-type="taskList"] li label input[type="checkbox"],
.prose ul.task-list .task-checkbox {
cursor: pointer;
margin: 0;
margin-top: 0.2em;
flex-shrink: 0;
}
/* TipTap: text content is in a div>p */
.tiptap ul[data-type="taskList"] li > div {
flex: 1;
min-width: 0;
}
.tiptap ul[data-type="taskList"] li > div p {
margin: 0;
}
/* Checked item styling */
.tiptap ul[data-type="taskList"] li[data-checked="true"] > div {
text-decoration: line-through;
color: var(--text-muted);
}
/* Override prose spacing for task lists */
.prose ul[data-type="taskList"],
.prose ul.task-list {
padding-left: 0;
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.prose ul[data-type="taskList"] li,
.prose ul.task-list li {
padding-left: 0;
margin-top: 0;
margin-bottom: 0;
}
.prose ul.task-list li p {
margin: 0;
}
/* Checklist link styles */
.checklist-link {
color: var(--primary);
text-decoration: underline;
text-underline-offset: 2px;
}
.checklist-link:hover {
color: var(--primary-hover);
}
[data-placeholder]:empty::before {
content: attr(data-placeholder);
color: var(--text-muted);
pointer-events: none;
}
/* Custom tooltips */
.tooltip-popup {
position: fixed;
z-index: 9999;
padding: 0.25rem 0.5rem;
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
line-height: 1.2;
color: var(--bg-surface);
background: var(--text);
border-radius: 2px;
pointer-events: none;
white-space: nowrap;
opacity: 0;
transition: opacity 100ms ease-out;
}
.tooltip-visible {
opacity: 1;
}