External links were indistinguishable from body text under the default theme because Tailwind preflight resets anchors. Add brand-green underline styles for ProseMirror (Web, mobile web, Android, iOS) while leaving note/attachment chips unchanged. Closes the styling half of #193; Notion-style link cards remain deferred per #192.
457 lines
10 KiB
CSS
457 lines
10 KiB
CSS
:root {
|
|
color-scheme: light dark;
|
|
--accent: #19ac73;
|
|
--text: #0f172a;
|
|
--muted: #64748b;
|
|
--border: #f1f5f9;
|
|
--toolbar-bg: #ffffff;
|
|
--toolbar-fg: #64748b;
|
|
--toolbar-active-bg: #ecfdf5;
|
|
--toolbar-active-border: #bbf7d0;
|
|
--toolbar-active-fg: #047857;
|
|
--code-bg: color-mix(in srgb, CanvasText 7%, transparent);
|
|
--placeholder: #94a3b8;
|
|
}
|
|
|
|
html[data-theme="dark"] {
|
|
--text: #f8fafc;
|
|
--muted: #cbd5e1;
|
|
--border: #334155;
|
|
--toolbar-bg: #0f172a;
|
|
--toolbar-fg: #cbd5e1;
|
|
--toolbar-active-bg: #14532d;
|
|
--toolbar-active-border: #166534;
|
|
--toolbar-active-fg: #86efac;
|
|
--placeholder: #64748b;
|
|
}
|
|
|
|
/* Android LocalTiptapEditor shell: column flex, toolbar fixed top, body scrolls. */
|
|
html,
|
|
body {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
min-width: 0;
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
color: var(--text);
|
|
-webkit-text-size-adjust: 100%;
|
|
}
|
|
|
|
html[data-theme="dark"],
|
|
html[data-theme="dark"] body {
|
|
background: #0f172a;
|
|
}
|
|
|
|
/* Full-height column; never let sticky/fixed fight the keyboard visual viewport. */
|
|
#shell {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
min-width: 0;
|
|
height: 100%;
|
|
min-height: 100%;
|
|
overflow: hidden;
|
|
background: inherit;
|
|
}
|
|
|
|
/*
|
|
* Formatting toolbar — always pinned under the native meta row / top of the WebView.
|
|
* Do NOT use position:sticky/fixed here: WKWebView + software keyboard reparents the
|
|
* visual viewport and sticky toolbars jump to the bottom-right (what the user hit).
|
|
*/
|
|
#toolbar {
|
|
display: none;
|
|
flex: 0 0 auto;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 4px;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
min-height: 38px;
|
|
box-sizing: border-box;
|
|
padding: 6px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
background: var(--toolbar-bg);
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
-webkit-overflow-scrolling: touch;
|
|
scrollbar-width: none;
|
|
position: relative;
|
|
z-index: 5;
|
|
}
|
|
|
|
#toolbar::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
#toolbar.editor-mode {
|
|
display: flex;
|
|
}
|
|
|
|
#toolbar button {
|
|
display: inline-flex;
|
|
flex: 0 0 auto;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 36px;
|
|
min-height: 32px;
|
|
margin: 0;
|
|
padding: 0;
|
|
border: 1px solid transparent;
|
|
border-radius: 999px;
|
|
background: transparent;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
line-height: 1;
|
|
color: var(--toolbar-fg);
|
|
}
|
|
|
|
#toolbar button:active,
|
|
#toolbar button.is-active {
|
|
border-color: var(--toolbar-active-border);
|
|
background: var(--toolbar-active-bg);
|
|
color: var(--toolbar-active-fg);
|
|
}
|
|
|
|
/* Scrollable editor body — only this region pans, toolbar stays put. */
|
|
#editor {
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
min-width: 0;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
/* TipTap mounts .ProseMirror inside #editor */
|
|
.edgeever-prose,
|
|
.tiptap,
|
|
.ProseMirror {
|
|
outline: none;
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
min-width: 0;
|
|
min-height: 100%;
|
|
padding: 12px 16px 48px;
|
|
line-height: 1.55;
|
|
word-break: break-word;
|
|
caret-color: #0f766e;
|
|
}
|
|
|
|
.edgeever-prose p.is-editor-empty:first-child::before,
|
|
.ProseMirror p.is-editor-empty:first-child::before {
|
|
color: var(--placeholder);
|
|
content: attr(data-placeholder);
|
|
float: left;
|
|
height: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.edgeever-prose img,
|
|
.ProseMirror img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
border-radius: 8px;
|
|
display: block;
|
|
margin: 12px 0;
|
|
}
|
|
|
|
/* Android-parity image node: figure + ⋯ actions + size presets.
|
|
* Width % is applied on the figure so the layout box shrinks with the image.
|
|
* Do not leave the figure at 100% while only scaling the <img> — that leaves
|
|
* an empty full-width slot (the pale selection wash users see). */
|
|
.edgeever-image-node {
|
|
position: relative;
|
|
display: block;
|
|
box-sizing: border-box;
|
|
width: var(--ee-image-width, 100%);
|
|
max-width: 100%;
|
|
margin: 14px auto;
|
|
line-height: 0;
|
|
/* Prevent WebKit contenteditable from painting a full-line selection wash */
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
background: transparent;
|
|
}
|
|
.edgeever-image-node.has-width {
|
|
/* Reinforced by inline style; class helps when attrs rehydrate */
|
|
max-width: min(100%, var(--ee-image-width, 100%));
|
|
}
|
|
.edgeever-image-node.is-loading,
|
|
.edgeever-image-node.is-failed {
|
|
min-height: 120px;
|
|
overflow: hidden;
|
|
border-radius: 10px;
|
|
background: #f1f5f9;
|
|
}
|
|
.edgeever-image-loading {
|
|
display: flex;
|
|
min-height: 120px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
padding: 16px;
|
|
color: #64748b;
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
line-height: 1.3;
|
|
}
|
|
.edgeever-image-loading[hidden] {
|
|
display: none;
|
|
}
|
|
.edgeever-image-loading-label {
|
|
text-align: center;
|
|
}
|
|
.edgeever-image-node > img {
|
|
display: block;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
height: auto;
|
|
margin: 0 !important;
|
|
border-radius: 10px;
|
|
vertical-align: top;
|
|
}
|
|
.edgeever-image-node > img[hidden] {
|
|
display: none;
|
|
}
|
|
/* Outline the figure box (matches actual occupied width), not a full-width wash */
|
|
.edgeever-image-node.is-selected,
|
|
.edgeever-image-node.ProseMirror-selectednode {
|
|
outline: 2px solid #0f766e;
|
|
outline-offset: 3px;
|
|
background: transparent !important;
|
|
box-shadow: none !important;
|
|
}
|
|
.edgeever-image-node.is-selected > img,
|
|
.edgeever-image-node.ProseMirror-selectednode > img {
|
|
outline: none;
|
|
}
|
|
/* Kill native selection fill that WebKit paints across the whole content line */
|
|
.ProseMirror-selectednode {
|
|
background: transparent !important;
|
|
}
|
|
.edgeever-image-node::selection,
|
|
.edgeever-image-node *::selection {
|
|
background: transparent;
|
|
}
|
|
.edgeever-image-actions {
|
|
position: absolute;
|
|
right: 8px;
|
|
bottom: 8px;
|
|
z-index: 5;
|
|
display: inline-flex;
|
|
width: 42px;
|
|
height: 42px;
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 1px solid #cbd5e1;
|
|
border-radius: 999px;
|
|
background: rgba(255, 255, 255, 0.92);
|
|
color: #334155;
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
line-height: 1;
|
|
box-shadow: 0 3px 12px rgba(15, 23, 42, 0.2);
|
|
padding: 0;
|
|
pointer-events: auto;
|
|
touch-action: manipulation;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
-webkit-touch-callout: none;
|
|
}
|
|
.edgeever-image-actions[hidden] {
|
|
display: none;
|
|
}
|
|
.edgeever-image-size-controls {
|
|
position: absolute;
|
|
top: 8px;
|
|
left: 50%;
|
|
z-index: 5;
|
|
display: flex;
|
|
width: max-content;
|
|
max-width: calc(100% - 16px);
|
|
align-items: center;
|
|
gap: 3px;
|
|
transform: translateX(-50%);
|
|
border: 1px solid #bbf7d0;
|
|
border-radius: 9px;
|
|
padding: 4px;
|
|
background: rgba(255, 255, 255, 0.96);
|
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.2);
|
|
line-height: 1.15;
|
|
pointer-events: auto;
|
|
touch-action: manipulation;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
}
|
|
.edgeever-image-size-controls[hidden] {
|
|
display: none !important;
|
|
}
|
|
.edgeever-image-size-button {
|
|
display: inline-flex;
|
|
min-width: 52px;
|
|
min-height: 38px;
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 0;
|
|
border-radius: 7px;
|
|
padding: 4px 7px;
|
|
background: transparent;
|
|
color: #475569;
|
|
font: inherit;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
pointer-events: auto;
|
|
touch-action: manipulation;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
-webkit-touch-callout: none;
|
|
cursor: pointer;
|
|
}
|
|
.edgeever-image-size-button.is-active {
|
|
background: #ccfbf1;
|
|
color: #0f766e;
|
|
}
|
|
.edgeever-image-upload-spinner {
|
|
width: 18px;
|
|
height: 18px;
|
|
border: 2px solid #cbd5e1;
|
|
border-top-color: #0f766e;
|
|
border-radius: 999px;
|
|
animation: edgeever-image-upload-spin 0.8s linear infinite;
|
|
}
|
|
@keyframes edgeever-image-upload-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
html[data-theme="dark"] .edgeever-image-node.is-loading,
|
|
html[data-theme="dark"] .edgeever-image-node.is-failed {
|
|
background: #1e293b;
|
|
}
|
|
html[data-theme="dark"] .edgeever-image-actions {
|
|
border-color: #475569;
|
|
background: rgba(15, 23, 42, 0.9);
|
|
color: #e2e8f0;
|
|
}
|
|
html[data-theme="dark"] .edgeever-image-size-controls {
|
|
border-color: #475569;
|
|
background: rgba(15, 23, 42, 0.96);
|
|
}
|
|
html[data-theme="dark"] .edgeever-image-size-button {
|
|
color: #cbd5e1;
|
|
}
|
|
html[data-theme="dark"] .edgeever-image-size-button.is-active {
|
|
background: #134e4a;
|
|
color: #99f6e4;
|
|
}
|
|
|
|
.edgeever-prose pre,
|
|
.ProseMirror pre {
|
|
background: var(--code-bg);
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
/* External hyperlinks — match Web/Android default styling. */
|
|
.edgeever-prose a,
|
|
.ProseMirror a {
|
|
color: #00751f;
|
|
font-weight: 500;
|
|
text-decoration: underline;
|
|
text-decoration-color: rgba(0, 117, 31, 0.45);
|
|
text-underline-offset: 2px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.edgeever-prose a:active,
|
|
.ProseMirror a:active {
|
|
color: #00a82d;
|
|
text-decoration-color: #00a82d;
|
|
}
|
|
|
|
html[data-theme="dark"] .edgeever-prose a,
|
|
html[data-theme="dark"] .ProseMirror a {
|
|
color: #86efac;
|
|
text-decoration-color: rgba(134, 239, 172, 0.45);
|
|
}
|
|
|
|
html[data-theme="dark"] .edgeever-prose a:active,
|
|
html[data-theme="dark"] .ProseMirror a:active {
|
|
color: #4ade80;
|
|
text-decoration-color: #4ade80;
|
|
}
|
|
|
|
.edgeever-prose a.edgeever-attachment-link,
|
|
.ProseMirror a.edgeever-attachment-link,
|
|
.edgeever-prose a[href*="/api/v1/resources/"],
|
|
.ProseMirror a[href*="/api/v1/resources/"] {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.edgeever-prose blockquote,
|
|
.ProseMirror blockquote {
|
|
margin: 0.5em 0;
|
|
padding-left: 12px;
|
|
border-left: 3px solid var(--accent);
|
|
color: var(--muted);
|
|
}
|
|
|
|
.edgeever-prose table,
|
|
.ProseMirror table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.edgeever-prose th,
|
|
.edgeever-prose td,
|
|
.ProseMirror th,
|
|
.ProseMirror td {
|
|
border: 1px solid var(--border);
|
|
padding: 6px 8px;
|
|
}
|
|
|
|
.edgeever-prose h1,
|
|
.edgeever-prose h2,
|
|
.edgeever-prose h3,
|
|
.ProseMirror h1,
|
|
.ProseMirror h2,
|
|
.ProseMirror h3 {
|
|
line-height: 1.25;
|
|
}
|
|
|
|
.edgeever-mermaid {
|
|
overflow-x: auto;
|
|
margin: 12px 0;
|
|
padding: 8px;
|
|
border-radius: 8px;
|
|
background: var(--code-bg);
|
|
}
|
|
|
|
.edgeever-mermaid svg {
|
|
max-width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
/* Viewer: no toolbar band, full-area scroll still via #editor */
|
|
body.viewer-mode #toolbar {
|
|
display: none !important;
|
|
}
|