mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-19 01:24:19 +00:00
Merge ec40abdd43 into 9a6109bd1d
This commit is contained in:
commit
df4a338675
28 changed files with 2717 additions and 0 deletions
61
src/static/skins/margin/README.md
Normal file
61
src/static/skins/margin/README.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# margin — Etherpad skin
|
||||
|
||||
A standalone drop-in skin with six themes and an orthogonal Light/Dark toggle:
|
||||
|
||||
| Theme | Light | Dark | Natural mode |
|
||||
| --- | --- | --- | --- |
|
||||
| `colibris` | ✓ | — | light (no dark palette) |
|
||||
| `editorial` | ✓ | ✓ | light |
|
||||
| `brutalist` | ✓ | ✓ | light |
|
||||
| `paper` | ✓ | ✓ | light |
|
||||
| `crt` | ✓ | ✓ | dark |
|
||||
| `industrial` | ✓ | ✓ | dark |
|
||||
|
||||
The current `data-theme` and `data-mode` attributes live on `<html>`. Mode is paired with theme in CSS via `[data-theme="X"][data-mode="light|dark"]`.
|
||||
|
||||
No external dependency on colibris — all component partials are vendored under `src/`.
|
||||
|
||||
## Install
|
||||
|
||||
1. Copy this `margin/` folder into `src/static/skins/`.
|
||||
2. In `settings.json`, set:
|
||||
```json
|
||||
"skinName": "margin"
|
||||
```
|
||||
|
||||
No template edits are required. The skin applies the user's saved theme + mode on load (defaulting to `colibris` + the theme's natural mode), the Google Fonts stylesheet is `@import`-ed from `pad.css` / `index.css`, and a **Theme** dropdown plus a **Dark mode** checkbox are injected into both the User Settings and Pad-wide Settings columns of the Settings popup.
|
||||
|
||||
## Switch themes at runtime
|
||||
|
||||
The Settings popup (gear icon in the toolbar) has:
|
||||
- a **Theme** dropdown with the six themes,
|
||||
- a **Dark mode** checkbox (orthogonal — flips light↔dark for any theme that has a dark palette).
|
||||
|
||||
Choices persist in `localStorage` under `marginTheme` + `marginMode` and propagate across the pad and the lobby.
|
||||
|
||||
Programmatically, from DevTools:
|
||||
|
||||
```js
|
||||
document.documentElement.dataset.theme = 'crt';
|
||||
document.documentElement.dataset.mode = 'dark';
|
||||
```
|
||||
|
||||
## Folder layout
|
||||
|
||||
```
|
||||
margin/
|
||||
├─ index.css lobby / pad-list themes
|
||||
├─ index.js lobby JS (early theme bootstrap)
|
||||
├─ pad.css pad themes + component imports
|
||||
├─ pad.js pad JS hooks (theme bootstrap, Settings dropdown,
|
||||
│ iframe theme propagation)
|
||||
├─ timeslider.css version timeline
|
||||
├─ timeslider.js timeslider JS
|
||||
├─ src/
|
||||
│ ├─ general.css, layout.css, pad-editor.css, pad-variants.css
|
||||
│ ├─ components/ toolbar, chat, popups, users, gritter, scrollbars, …
|
||||
│ └─ plugins/ comments, color picker, tables, …
|
||||
└─ README.md
|
||||
```
|
||||
|
||||
The `src/` partials are vendored from upstream colibris so this skin is fully self-contained — themes layer on top via `data-theme="…"` overrides in `pad.css` and `index.css`, and inherit the same CSS-variable contract (`--primary-color`, `--bg-color`, `--main-font-family`, `--editor-horizontal-padding`, …) that colibris exposes.
|
||||
43
src/static/skins/margin/index.css
Normal file
43
src/static/skins/margin/index.css
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* margin / index.css — lobby + pad-list page
|
||||
* Styles the home / pad-list using the same data-theme system as pad.css.
|
||||
* Drop alongside pad.css in src/static/skins/margin/. */
|
||||
|
||||
@import url("//fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..700;1,6..72,300..700&family=Instrument+Serif:ital@0;1&family=Lora:ital,wght@0,400..700;1,400..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&family=VT323&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700&display=swap");
|
||||
|
||||
/* Theme definitions are mirrored from pad.css so the lobby themes too.
|
||||
* Both light and dark variants of each named theme are defined so the
|
||||
* Settings popup's Theme dropdown can apply consistently across pages. */
|
||||
[data-theme="colibris"] { --m-bg:#f2f3f4; --m-fg:#485365; --m-soft:#576273; --m-accent:#64d29b; --m-panel:#fff; --m-rule:#dadada; --m-radius:3px; --m-shadow:0 2px 8px rgba(68,68,68,.08); --m-font:Quicksand, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; --m-ui-style:normal; --m-ui-case:none; }
|
||||
[data-theme="editorial"][data-mode="light"] { --m-bg:#f5f0e8; --m-fg:#1c1916; --m-soft:#5a534a; --m-accent:#a8442b; --m-panel:#fbf8f2; --m-rule:rgba(28,25,22,.12); --m-radius:2px; --m-shadow:0 12px 36px -18px rgba(28,25,22,.20); --m-font:"Newsreader",Georgia,serif; --m-ui-style:italic; --m-ui-case:none; }
|
||||
[data-theme="editorial"][data-mode="dark"] { color-scheme:dark; --m-bg:#16130f; --m-fg:#f0eadd; --m-soft:#a8a098; --m-accent:#d27047; --m-panel:#1c1916; --m-rule:rgba(240,234,221,.12); --m-radius:2px; --m-shadow:0 12px 36px -18px rgba(0,0,0,.6); --m-font:"Newsreader",Georgia,serif; --m-ui-style:italic; --m-ui-case:none; }
|
||||
[data-theme="brutalist"][data-mode="light"] { --m-bg:#f3f3f0; --m-fg:#000; --m-soft:#222; --m-accent:#ff3b00; --m-panel:#fff; --m-rule:#000; --m-radius:0; --m-shadow:4px 4px 0 #000; --m-font:"Space Mono",ui-monospace,monospace; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
[data-theme="brutalist"][data-mode="dark"] { color-scheme:dark; --m-bg:#0c0c09; --m-fg:#fff; --m-soft:#ddd; --m-accent:#ff3b00; --m-panel:#000; --m-rule:#fff; --m-radius:0; --m-shadow:4px 4px 0 #fff; --m-font:"Space Mono",ui-monospace,monospace; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
[data-theme="paper"][data-mode="light"] { --m-bg:#f6f1e8; --m-fg:#2a2520; --m-soft:#6b6259; --m-accent:#b87333; --m-panel:#fbf6ec; --m-rule:rgba(42,37,32,.08); --m-radius:12px; --m-shadow:0 14px 40px -16px rgba(42,37,32,.18); --m-font:"Lora",Georgia,serif; --m-ui-style:normal; --m-ui-case:none; }
|
||||
[data-theme="paper"][data-mode="dark"] { color-scheme:dark; --m-bg:#231e19; --m-fg:#efe7d4; --m-soft:#a89e8d; --m-accent:#d99560; --m-panel:#2a2520; --m-rule:rgba(239,231,212,.10); --m-radius:12px; --m-shadow:0 14px 40px -16px rgba(0,0,0,.6); --m-font:"Lora",Georgia,serif; --m-ui-style:normal; --m-ui-case:none; }
|
||||
[data-theme="crt"][data-mode="light"] { --m-bg:#edf6ee; --m-fg:#04200d; --m-soft:#1c4a2b; --m-accent:#006b3f; --m-panel:#e9f5ed; --m-rule:rgba(0,107,63,.20); --m-radius:0; --m-shadow:0 0 0 1px rgba(0,107,63,.25); --m-font:"IBM Plex Mono",ui-monospace,monospace; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
[data-theme="crt"][data-mode="dark"] { color-scheme:dark; --m-bg:#04140a; --m-fg:#7fffae; --m-soft:#4ed188; --m-accent:#ffb84d; --m-panel:#08200f; --m-rule:rgba(127,255,174,.20); --m-radius:0; --m-shadow:0 0 24px rgba(127,255,174,.10); --m-font:"IBM Plex Mono",ui-monospace,monospace; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
[data-theme="industrial"][data-mode="light"] { --m-bg:#f0f1f4; --m-fg:#14171c; --m-soft:#525965; --m-accent:#cc9900; --m-panel:#f5f6f8; --m-rule:rgba(20,23,28,.08); --m-radius:3px; --m-shadow:0 12px 32px rgba(20,23,28,.10); --m-font:"IBM Plex Sans",ui-sans-serif,system-ui,sans-serif; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
[data-theme="industrial"][data-mode="dark"] { color-scheme:dark; --m-bg:#0d0f12; --m-fg:#e6e8eb; --m-soft:#9aa0a8; --m-accent:#ffcc00; --m-panel:#14171c; --m-rule:rgba(255,255,255,.08); --m-radius:3px; --m-shadow:0 12px 32px rgba(0,0,0,.4); --m-font:"IBM Plex Sans",ui-sans-serif,system-ui,sans-serif; --m-ui-style:normal; --m-ui-case:uppercase; }
|
||||
|
||||
[data-theme] body, [data-theme] .body { background: var(--m-bg) !important; color: var(--m-fg); font-family: var(--m-font); }
|
||||
[data-theme] body nav { border-bottom: 1px solid var(--m-rule); }
|
||||
[data-theme] .logo-box { background: var(--m-accent); border-radius: var(--m-radius); }
|
||||
[data-theme] #wrapper, [data-theme] .pad-datalist {
|
||||
background: var(--m-panel); border: 1px solid var(--m-rule);
|
||||
border-radius: var(--m-radius); box-shadow: var(--m-shadow);
|
||||
}
|
||||
[data-theme] .mission-statement h2 { color: var(--m-fg); text-transform: var(--m-ui-case); font-style: var(--m-ui-style); }
|
||||
[data-theme] .mission-statement p { color: var(--m-soft); }
|
||||
[data-theme] #padname { background: var(--m-panel); color: var(--m-fg); border-color: var(--m-rule); border-radius: var(--m-radius); }
|
||||
[data-theme] #go2Name [type="submit"], [data-theme] #transferSessionButton {
|
||||
background: var(--m-accent); border-radius: var(--m-radius);
|
||||
text-transform: var(--m-ui-case);
|
||||
}
|
||||
[data-theme] #button { background: var(--m-panel); color: var(--m-fg); border: 1px solid var(--m-rule); border-radius: var(--m-radius); }
|
||||
[data-theme] .pad-datalist h2 { border-bottom-color: var(--m-rule); color: var(--m-fg); }
|
||||
[data-theme] .recent-pad:hover a { color: var(--m-accent); }
|
||||
|
||||
[data-theme="brutalist"] #wrapper, [data-theme="brutalist"] .pad-datalist,
|
||||
[data-theme="brutalist"] #button, [data-theme="brutalist"] #go2Name [type="submit"] {
|
||||
border: 2px solid #000 !important; box-shadow: 4px 4px 0 #000;
|
||||
}
|
||||
173
src/static/skins/margin/index.js
Normal file
173
src/static/skins/margin/index.js
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
'use strict';
|
||||
|
||||
// Apply the user's saved theme + light/dark mode as early as possible so the
|
||||
// lobby paints in the same theme as the last pad they visited. The controls
|
||||
// that write these localStorage keys live in the pad's Settings popup
|
||||
// (see pad.js).
|
||||
const MARGIN_THEME_KEY = 'marginTheme';
|
||||
const MARGIN_MODE_KEY = 'marginMode';
|
||||
const MARGIN_THEME_DEFAULT = 'colibris';
|
||||
const MARGIN_MODE_DEFAULTS = {
|
||||
colibris: 'light', editorial: 'light', brutalist: 'light',
|
||||
paper: 'light', crt: 'dark', industrial: 'dark',
|
||||
};
|
||||
try {
|
||||
const theme = localStorage.getItem(MARGIN_THEME_KEY) || MARGIN_THEME_DEFAULT;
|
||||
const mode = localStorage.getItem(MARGIN_MODE_KEY) || MARGIN_MODE_DEFAULTS[theme] || 'light';
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
document.documentElement.setAttribute('data-mode', mode);
|
||||
} catch (_) {
|
||||
document.documentElement.setAttribute('data-theme', MARGIN_THEME_DEFAULT);
|
||||
document.documentElement.setAttribute('data-mode', MARGIN_MODE_DEFAULTS[MARGIN_THEME_DEFAULT]);
|
||||
}
|
||||
|
||||
window.addEventListener('pageshow', (event) => {
|
||||
if (event.persisted) {
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
window.customStart();
|
||||
} else {
|
||||
window.addEventListener('DOMContentLoaded', window.customStart, {once: true});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.customStart = () => {
|
||||
const recentPadList = document.getElementById('recent-pads');
|
||||
if (recentPadList) {
|
||||
recentPadList.replaceChildren();
|
||||
}
|
||||
// define your javascript here
|
||||
// jquery is available - except index.js
|
||||
// you can load extra scripts with $.getScript http://api.jquery.com/jQuery.getScript/
|
||||
const divHoldingPlaceHolderLabel = document
|
||||
.querySelector('[data-l10n-id="index.placeholderPadEnter"]');
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
document.querySelector('#go2Name input')
|
||||
.setAttribute('placeholder', divHoldingPlaceHolderLabel.textContent);
|
||||
});
|
||||
|
||||
observer
|
||||
.observe(divHoldingPlaceHolderLabel, {childList: true, subtree: true, characterData: true});
|
||||
|
||||
|
||||
const recentPadListHeading = document.querySelector('[data-l10n-id="index.recentPads"]');
|
||||
// localStorage may be unavailable (private mode, disabled cookies) and the
|
||||
// stored value may be malformed if another tab corrupted it. Either case
|
||||
// would throw out of customStart() and break the rest of the lobby init,
|
||||
// so swallow both and fall back to an empty list.
|
||||
let recentPadListData = [];
|
||||
try {
|
||||
const recentPadsFromLocalStorage = localStorage.getItem('recentPads');
|
||||
if (recentPadsFromLocalStorage != null) {
|
||||
const parsed = JSON.parse(recentPadsFromLocalStorage);
|
||||
if (Array.isArray(parsed)) {
|
||||
recentPadListData = parsed.filter(
|
||||
(p) => p && typeof p === 'object' && typeof p.name === 'string');
|
||||
}
|
||||
}
|
||||
} catch (_) { /* private mode / corrupted entry */ }
|
||||
|
||||
// Remove duplicates based on pad name and sort by timestamp
|
||||
recentPadListData = recentPadListData.filter(
|
||||
(pad, index, self) => index === self.findIndex((p) => p.name === pad.name)
|
||||
).sort((a, b) => new Date(a.timestamp) > new Date(b.timestamp) ? -1 : 1);
|
||||
|
||||
if (recentPadList && recentPadListData.length === 0) {
|
||||
const parentStyle = recentPadList.parentElement.style;
|
||||
recentPadListHeading.setAttribute('data-l10n-id', 'index.recentPadsEmpty');
|
||||
parentStyle.display = 'flex';
|
||||
parentStyle.justifyContent = 'center';
|
||||
parentStyle.alignItems = 'center';
|
||||
parentStyle.maxHeight = '100%';
|
||||
recentPadList.remove();
|
||||
} else if (recentPadList) {
|
||||
/**
|
||||
* @typedef {Object} Pad
|
||||
* @property {string} name
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Pad} pad
|
||||
*/
|
||||
|
||||
const arrowIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-right w-4 h-4 text-gray-400"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg>';
|
||||
const clockIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clock w-3 h-3"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>';
|
||||
const personalIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users w-3 h-3"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>';
|
||||
recentPadListData.forEach((pad) => {
|
||||
const li = document.createElement('li');
|
||||
|
||||
|
||||
li.style.cursor = 'pointer';
|
||||
|
||||
li.className = 'recent-pad';
|
||||
// Use new URL() so a trailing slash, query string, or hash on
|
||||
// window.location.href doesn't produce a broken link, and so pad
|
||||
// names with characters that need encoding still resolve.
|
||||
const padPath = new URL(`p/${encodeURIComponent(pad.name)}`,
|
||||
window.location.href).href;
|
||||
const link = document.createElement('a');
|
||||
link.style.textDecoration = 'none';
|
||||
|
||||
link.href = padPath;
|
||||
link.innerText = pad.name;
|
||||
li.appendChild(link);
|
||||
|
||||
|
||||
const arrowIconElement = document.createElement('span');
|
||||
arrowIconElement.className = 'recent-pad-arrow';
|
||||
arrowIconElement.innerHTML = arrowIcon;
|
||||
li.appendChild(arrowIconElement);
|
||||
|
||||
const nextRow = document.createElement('div');
|
||||
|
||||
nextRow.style.display = 'flex';
|
||||
nextRow.style.gap = '10px';
|
||||
nextRow.style.marginTop = '10px';
|
||||
|
||||
const clockIconElement = document.createElement('span');
|
||||
clockIconElement.className = 'recent-pad-clock';
|
||||
clockIconElement.innerHTML = clockIcon;
|
||||
|
||||
nextRow.appendChild(clockIconElement);
|
||||
|
||||
const time = new Date(pad.timestamp);
|
||||
const userLocale = navigator.language || 'en-US';
|
||||
|
||||
const formattedTime = time.toLocaleDateString(userLocale, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
const timeElement = document.createElement('span');
|
||||
timeElement.className = 'recent-pad-time';
|
||||
timeElement.innerText = formattedTime;
|
||||
|
||||
nextRow.appendChild(timeElement);
|
||||
|
||||
const personalIconElement = document.createElement('span');
|
||||
personalIconElement.className = 'recent-pad-personal';
|
||||
personalIconElement.innerHTML = personalIcon;
|
||||
|
||||
personalIconElement.style.marginLeft = '5px';
|
||||
|
||||
const members = document.createElement('span');
|
||||
members.className = 'recent-pad-members';
|
||||
members.innerText = pad.members;
|
||||
|
||||
|
||||
nextRow.appendChild(personalIconElement);
|
||||
nextRow.appendChild(members);
|
||||
li.appendChild(nextRow);
|
||||
|
||||
li.addEventListener('click', () => {
|
||||
window.location.href = padPath;
|
||||
});
|
||||
|
||||
// https://v0.dev/chat/etherpad-design-clone-qZnwOrVRXxH
|
||||
recentPadList.appendChild(li);
|
||||
});
|
||||
}
|
||||
};
|
||||
416
src/static/skins/margin/pad.css
Normal file
416
src/static/skins/margin/pad.css
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/* ════════════════════════════════════════════════════════════════════════
|
||||
* margin / pad.css — a standalone Etherpad skin with 5 themes.
|
||||
*
|
||||
* Drop the entire `margin/` folder into src/static/skins/, then in
|
||||
* settings.json set:
|
||||
*
|
||||
* "skinName": "margin"
|
||||
*
|
||||
* Choose a theme by setting data-theme on <html> in src/templates/pad.html:
|
||||
*
|
||||
* <html data-theme="editorial">
|
||||
*
|
||||
* Themes: editorial · brutalist · paper · crt · industrial
|
||||
*
|
||||
* Switch live in devtools: document.documentElement.dataset.theme='crt'
|
||||
*
|
||||
* This file inherits the same variable contract colibris uses
|
||||
* (--primary-color, --text-color, --bg-color, --main-font-family, …) so
|
||||
* Etherpad's built-in components pick up the theme automatically.
|
||||
* ════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Google Fonts powering the five themed type stacks (Newsreader/Editorial,
|
||||
* Space Mono/Brutalist, Lora/Paper, IBM Plex Mono+VT323/CRT, IBM Plex
|
||||
* Sans/Industrial, plus Instrument Serif for display H1/H2). */
|
||||
@import url("//fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..700;1,6..72,300..700&family=Instrument+Serif:ital@0;1&family=Lora:ital,wght@0,400..700;1,400..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&family=VT323&family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700&display=swap");
|
||||
|
||||
/* Component partials — vendored from colibris so this skin is standalone. */
|
||||
@import url("src/general.css");
|
||||
@import url("src/layout.css");
|
||||
@import url("src/pad-editor.css");
|
||||
@import url("src/components/scrollbars.css");
|
||||
@import url("src/components/buttons.css");
|
||||
@import url("src/components/popup.css");
|
||||
@import url("src/components/chat.css");
|
||||
@import url("src/components/sidediv.css");
|
||||
@import url("src/components/gritter.css");
|
||||
@import url("src/components/table-of-content.css");
|
||||
@import url("src/components/toolbar.css");
|
||||
@import url("src/components/users.css");
|
||||
@import url("src/components/form.css");
|
||||
@import url("src/components/import-export.css");
|
||||
@import url("src/plugins/brightcolorpicker.css");
|
||||
@import url("src/plugins/font_color.css");
|
||||
@import url("src/plugins/tables2.css");
|
||||
@import url("src/plugins/set_title_on_pad.css");
|
||||
@import url("src/plugins/author_hover.css");
|
||||
@import url("src/plugins/comments.css");
|
||||
|
||||
/* Default theme if data-theme isn't set */
|
||||
:root { color-scheme: light; }
|
||||
html:not([data-theme]) { /* fallback */ }
|
||||
|
||||
/* Mirror colibris's narrow-viewport behavior: the per-theme blocks below
|
||||
* each set --editor-horizontal-padding (40-64px) so the editor frame has
|
||||
* room to breathe on desktop. Below 1000px (matching the layout.css media
|
||||
* query that drops `max-width: 900px` on the iframe), zero them so the
|
||||
* editor surface fills the available container width. */
|
||||
@media (max-width: 1000px) {
|
||||
[data-theme] {
|
||||
--editor-horizontal-padding: 0px !important;
|
||||
--editor-vertical-padding: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── 1. EDITORIAL ───────────────────────────────────────────────────── */
|
||||
[data-theme="editorial"][data-mode="light"] {
|
||||
--super-dark-color:#1c1916; --dark-color:#5a534a;
|
||||
--primary-color:#a8442b; --middle-color:rgba(28,25,22,.18);
|
||||
--light-color:#f0eadd; --super-light-color:#fbf8f2;
|
||||
--text-color:#1c1916; --text-soft-color:#5a534a;
|
||||
--border-color:rgba(28,25,22,.18);
|
||||
--bg-soft-color:#f0eadd; --bg-color:#fbf8f2;
|
||||
--toolbar-border:1px solid rgba(28,25,22,.12);
|
||||
--main-font-family:"Newsreader",Georgia,serif;
|
||||
--editor-horizontal-padding:64px; --editor-vertical-padding:40px;
|
||||
--m-bg:#f5f0e8; --m-rule:rgba(28,25,22,.12);
|
||||
--m-radius:2px; --m-shadow:0 12px 36px -18px rgba(28,25,22,.20);
|
||||
--m-ui-style:italic; --m-ui-case:none; --m-ui-track:.04em;
|
||||
}
|
||||
|
||||
/* ─── 2. BRUTALIST ──────────────────────────────────────────────────── */
|
||||
[data-theme="brutalist"][data-mode="light"] {
|
||||
--super-dark-color:#000; --dark-color:#222;
|
||||
--primary-color:#ff3b00; --middle-color:#000;
|
||||
--light-color:#f3f3f0; --super-light-color:#fff;
|
||||
--text-color:#000; --text-soft-color:#222;
|
||||
--border-color:#000;
|
||||
--bg-soft-color:#f3f3f0; --bg-color:#fff;
|
||||
--toolbar-border:2px solid #000;
|
||||
--main-font-family:"Space Mono",ui-monospace,monospace;
|
||||
--editor-horizontal-padding:48px; --editor-vertical-padding:32px;
|
||||
--m-bg:#f3f3f0; --m-rule:#000;
|
||||
--m-radius:0; --m-shadow:4px 4px 0 #000;
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.06em;
|
||||
}
|
||||
|
||||
/* ─── 3. PAPER ──────────────────────────────────────────────────────── */
|
||||
[data-theme="paper"][data-mode="light"] {
|
||||
--super-dark-color:#2a2520; --dark-color:#6b6259;
|
||||
--primary-color:#b87333; --middle-color:rgba(42,37,32,.18);
|
||||
--light-color:#efe7d4; --super-light-color:#fbf6ec;
|
||||
--text-color:#2a2520; --text-soft-color:#6b6259;
|
||||
--border-color:rgba(42,37,32,.18);
|
||||
--bg-soft-color:#efe7d4; --bg-color:#fbf6ec;
|
||||
--toolbar-border:1px solid rgba(42,37,32,.08);
|
||||
--main-font-family:"Lora",Georgia,serif;
|
||||
--editor-horizontal-padding:56px; --editor-vertical-padding:40px;
|
||||
--m-bg:#f6f1e8; --m-rule:rgba(42,37,32,.08);
|
||||
--m-radius:10px; --m-shadow:0 14px 40px -16px rgba(42,37,32,.18);
|
||||
--m-ui-style:normal; --m-ui-case:none; --m-ui-track:0;
|
||||
--m-display-font:"Instrument Serif",Georgia,serif;
|
||||
}
|
||||
|
||||
/* ─── 4. CRT TERMINAL ───────────────────────────────────────────────── */
|
||||
[data-theme="crt"][data-mode="dark"] {
|
||||
color-scheme: dark;
|
||||
--super-dark-color:#7fffae; --dark-color:#4ed188;
|
||||
--primary-color:#ffb84d; --middle-color:rgba(127,255,174,.45);
|
||||
--light-color:#0c2a14; --super-light-color:#08200f;
|
||||
--text-color:#7fffae; --text-soft-color:#4ed188;
|
||||
--border-color:rgba(127,255,174,.45);
|
||||
--bg-soft-color:#0c2a14; --bg-color:#08200f;
|
||||
--toolbar-border:1px solid rgba(127,255,174,.45);
|
||||
--main-font-family:"IBM Plex Mono",ui-monospace,monospace;
|
||||
--editor-horizontal-padding:48px; --editor-vertical-padding:32px;
|
||||
--m-bg:#04140a; --m-rule:rgba(127,255,174,.20);
|
||||
--m-radius:0; --m-shadow:0 0 0 1px rgba(127,255,174,.25),0 0 24px rgba(127,255,174,.10);
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.10em;
|
||||
--m-display-font:"VT323",ui-monospace,monospace;
|
||||
}
|
||||
|
||||
/* ─── 5. INDUSTRIAL ─────────────────────────────────────────────────── */
|
||||
[data-theme="industrial"][data-mode="dark"] {
|
||||
color-scheme: dark;
|
||||
--super-dark-color:#e6e8eb; --dark-color:#9aa0a8;
|
||||
--primary-color:#ffcc00; --middle-color:rgba(255,255,255,.18);
|
||||
--light-color:#1c2027; --super-light-color:#14171c;
|
||||
--text-color:#e6e8eb; --text-soft-color:#9aa0a8;
|
||||
--border-color:rgba(255,255,255,.18);
|
||||
--bg-soft-color:#1c2027; --bg-color:#14171c;
|
||||
--toolbar-border:1px solid rgba(255,255,255,.08);
|
||||
--main-font-family:"IBM Plex Sans",ui-sans-serif,system-ui,sans-serif;
|
||||
--editor-horizontal-padding:56px; --editor-vertical-padding:36px;
|
||||
--m-bg:#0d0f12; --m-rule:rgba(255,255,255,.08);
|
||||
--m-radius:3px; --m-shadow:0 12px 32px rgba(0,0,0,.4);
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.08em;
|
||||
}
|
||||
|
||||
/* ─── 0. COLIBRIS (default, mirrors colibris/pad.css) ──────────────── */
|
||||
[data-theme="colibris"] {
|
||||
--super-dark-color:#485365; --dark-color:#576273;
|
||||
--primary-color:#64d29b; --middle-color:#dadada;
|
||||
--light-color:#f2f3f4; --super-light-color:#ffffff;
|
||||
--text-color:#485365; --text-soft-color:#576273;
|
||||
--border-color:#dadada;
|
||||
--bg-soft-color:#f2f3f4; --bg-color:#ffffff;
|
||||
--toolbar-border:none;
|
||||
--main-font-family:Quicksand, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
--editor-horizontal-padding:40px; --editor-vertical-padding:25px;
|
||||
--m-bg:#f2f3f4; --m-rule:#dadada;
|
||||
--m-radius:3px; --m-shadow:0 2px 8px rgba(68,68,68,.08);
|
||||
--m-ui-style:normal; --m-ui-case:none; --m-ui-track:0;
|
||||
}
|
||||
|
||||
/* ─── 1b. EDITORIAL — DARK ─────────────────────────────────────────── */
|
||||
[data-theme="editorial"][data-mode="dark"] {
|
||||
color-scheme:dark;
|
||||
--super-dark-color:#f0eadd; --dark-color:#a8a098;
|
||||
--primary-color:#d27047; --middle-color:rgba(240,234,221,.18);
|
||||
--light-color:#221e1a; --super-light-color:#1c1916;
|
||||
--text-color:#f0eadd; --text-soft-color:#a8a098;
|
||||
--border-color:rgba(240,234,221,.18);
|
||||
--bg-soft-color:#221e1a; --bg-color:#1c1916;
|
||||
--toolbar-border:1px solid rgba(240,234,221,.12);
|
||||
--main-font-family:"Newsreader",Georgia,serif;
|
||||
--editor-horizontal-padding:64px; --editor-vertical-padding:40px;
|
||||
--m-bg:#16130f; --m-rule:rgba(240,234,221,.12);
|
||||
--m-radius:2px; --m-shadow:0 12px 36px -18px rgba(0,0,0,.6);
|
||||
--m-ui-style:italic; --m-ui-case:none; --m-ui-track:.04em;
|
||||
}
|
||||
|
||||
/* ─── 2b. BRUTALIST — DARK ─────────────────────────────────────────── */
|
||||
[data-theme="brutalist"][data-mode="dark"] {
|
||||
color-scheme:dark;
|
||||
--super-dark-color:#fff; --dark-color:#ddd;
|
||||
--primary-color:#ff3b00; --middle-color:#fff;
|
||||
--light-color:#111; --super-light-color:#000;
|
||||
--text-color:#fff; --text-soft-color:#ddd;
|
||||
--border-color:#fff;
|
||||
--bg-soft-color:#111; --bg-color:#000;
|
||||
--toolbar-border:2px solid #fff;
|
||||
--main-font-family:"Space Mono",ui-monospace,monospace;
|
||||
--editor-horizontal-padding:48px; --editor-vertical-padding:32px;
|
||||
--m-bg:#0c0c09; --m-rule:#fff;
|
||||
--m-radius:0; --m-shadow:4px 4px 0 #fff;
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.06em;
|
||||
}
|
||||
|
||||
/* ─── 3b. PAPER — DARK ─────────────────────────────────────────────── */
|
||||
[data-theme="paper"][data-mode="dark"] {
|
||||
color-scheme:dark;
|
||||
--super-dark-color:#efe7d4; --dark-color:#a89e8d;
|
||||
--primary-color:#d99560; --middle-color:rgba(239,231,212,.18);
|
||||
--light-color:#332c25; --super-light-color:#2a2520;
|
||||
--text-color:#efe7d4; --text-soft-color:#a89e8d;
|
||||
--border-color:rgba(239,231,212,.18);
|
||||
--bg-soft-color:#332c25; --bg-color:#2a2520;
|
||||
--toolbar-border:1px solid rgba(239,231,212,.10);
|
||||
--main-font-family:"Lora",Georgia,serif;
|
||||
--editor-horizontal-padding:56px; --editor-vertical-padding:40px;
|
||||
--m-bg:#231e19; --m-rule:rgba(239,231,212,.10);
|
||||
--m-radius:10px; --m-shadow:0 14px 40px -16px rgba(0,0,0,.6);
|
||||
--m-ui-style:normal; --m-ui-case:none; --m-ui-track:0;
|
||||
--m-display-font:"Instrument Serif",Georgia,serif;
|
||||
}
|
||||
|
||||
/* ─── 4b. CRT — LIGHT (paper-terminal, less iconic but readable) ──── */
|
||||
[data-theme="crt"][data-mode="light"] {
|
||||
--super-dark-color:#04200d; --dark-color:#1c4a2b;
|
||||
--primary-color:#006b3f; --middle-color:rgba(0,107,63,.30);
|
||||
--light-color:#dfeee2; --super-light-color:#e9f5ed;
|
||||
--text-color:#04200d; --text-soft-color:#1c4a2b;
|
||||
--border-color:rgba(0,107,63,.30);
|
||||
--bg-soft-color:#dfeee2; --bg-color:#e9f5ed;
|
||||
--toolbar-border:1px solid rgba(0,107,63,.30);
|
||||
--main-font-family:"IBM Plex Mono",ui-monospace,monospace;
|
||||
--editor-horizontal-padding:48px; --editor-vertical-padding:32px;
|
||||
--m-bg:#edf6ee; --m-rule:rgba(0,107,63,.20);
|
||||
--m-radius:0; --m-shadow:0 0 0 1px rgba(0,107,63,.25);
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.10em;
|
||||
--m-display-font:"VT323",ui-monospace,monospace;
|
||||
}
|
||||
|
||||
/* ─── 5b. INDUSTRIAL — LIGHT ──────────────────────────────────────── */
|
||||
[data-theme="industrial"][data-mode="light"] {
|
||||
--super-dark-color:#14171c; --dark-color:#525965;
|
||||
--primary-color:#cc9900; --middle-color:rgba(20,23,28,.18);
|
||||
--light-color:#e6e8eb; --super-light-color:#f5f6f8;
|
||||
--text-color:#14171c; --text-soft-color:#525965;
|
||||
--border-color:rgba(20,23,28,.18);
|
||||
--bg-soft-color:#e6e8eb; --bg-color:#f5f6f8;
|
||||
--toolbar-border:1px solid rgba(20,23,28,.08);
|
||||
--main-font-family:"IBM Plex Sans",ui-sans-serif,system-ui,sans-serif;
|
||||
--editor-horizontal-padding:56px; --editor-vertical-padding:36px;
|
||||
--m-bg:#f0f1f4; --m-rule:rgba(20,23,28,.08);
|
||||
--m-radius:3px; --m-shadow:0 12px 32px rgba(20,23,28,.10);
|
||||
--m-ui-style:normal; --m-ui-case:uppercase; --m-ui-track:.08em;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════════════════════════════════
|
||||
* Cross-theme overrides (apply to anything under [data-theme])
|
||||
* ════════════════════════════════════════════════════════════════════ */
|
||||
[data-theme] body { background: var(--m-bg); color: var(--text-color); }
|
||||
[data-theme] #editorcontainerbox,
|
||||
[data-theme] #editorcontainer,
|
||||
[data-theme] #padeditor,
|
||||
[data-theme] #outerdocbody,
|
||||
[data-theme] iframe[name="ace_outer"],
|
||||
[data-theme] iframe[name="ace_inner"] { background: var(--m-bg) !important; }
|
||||
|
||||
/* Editor frame outline — gives the pad surface a visible edge against
|
||||
* the page background when both share dark/light tones. */
|
||||
[data-theme] iframe[name="ace_outer"] {
|
||||
border: 1px solid var(--border-color) !important;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,.04);
|
||||
}
|
||||
[data-theme="brutalist"] iframe[name="ace_outer"] { border-radius: 0; border-width: 2px !important; box-shadow: var(--m-shadow); border-color: var(--m-rule) !important; }
|
||||
[data-theme="crt"][data-mode="dark"] iframe[name="ace_outer"] { box-shadow: 0 0 0 1px var(--border-color), 0 0 18px rgba(127,255,174,.18) inset; }
|
||||
[data-theme="crt"][data-mode="light"] iframe[name="ace_outer"] { box-shadow: 0 0 0 1px var(--border-color); }
|
||||
|
||||
/* Show-users / chat / share buttons in the menu_right have hard-coded
|
||||
* background colors in upstream — force them to follow the theme.
|
||||
* No left-borders: keep the right-side icons visually flush like the left. */
|
||||
[data-theme] .toolbar .menu_right li a,
|
||||
[data-theme] #chaticon,
|
||||
[data-theme] #chaticon a {
|
||||
background: transparent !important;
|
||||
color: var(--text-color) !important;
|
||||
border-left: 0 !important;
|
||||
}
|
||||
[data-theme] #chaticon .chatlabel { color: var(--text-color) !important; }
|
||||
[data-theme] .toolbar ul li[data-key=showusers] > a {
|
||||
background: var(--primary-color) !important;
|
||||
color: var(--bg-color) !important;
|
||||
}
|
||||
|
||||
/* Normalize <select> chrome inside popups so Font type / Language / Theme
|
||||
* align with the rest of the form fields. line-height matches height so the
|
||||
* selected option text sits on the vertical centerline. */
|
||||
[data-theme] .popup-content select,
|
||||
[data-theme] #settings select,
|
||||
[data-theme] #users select {
|
||||
height: 32px;
|
||||
line-height: 30px;
|
||||
padding: 0 26px 0 10px;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
|
||||
linear-gradient(135deg, currentColor 50%, transparent 50%);
|
||||
background-position: calc(100% - 14px) 14px, calc(100% - 9px) 14px;
|
||||
background-size: 5px 5px, 5px 5px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* In the toolbar the .nice-select widget is a flex child of its <li>, which
|
||||
* stretches it past the natural inline-block centering the popups get. Pin
|
||||
* .current to the vertical centerline with flex alignment so the selected
|
||||
* text reads right regardless of the row line-height. */
|
||||
[data-theme] .toolbar .nice-select {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
[data-theme] .toolbar .nice-select .current {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* Cap every open dropdown list (toolbar AND popups) — long font-family
|
||||
* / heading / theme labels would otherwise stretch the <ul> to fit the
|
||||
* widest <li> and could run a long way across the viewport. Truncate
|
||||
* overflowing option labels with ellipsis. */
|
||||
[data-theme] .nice-select .list {
|
||||
max-width: 220px;
|
||||
}
|
||||
[data-theme] .nice-select .option {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* ep_comments_page hard-codes #ffffff / #f9f9f9 / #eeeeed on the sidebar
|
||||
* + popup wrappers, which clashes with dark themes (crt, industrial) and
|
||||
* out-of-palette light themes (paper, editorial). Pull them onto the
|
||||
* margin variable palette so the comment UI reads against any theme. */
|
||||
[data-theme] .full-display-content,
|
||||
[data-theme] .comment-modal-comment .full-display-content {
|
||||
background: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
box-shadow: var(--m-shadow);
|
||||
}
|
||||
[data-theme] .compact-display-content {
|
||||
background: var(--bg-soft-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
[data-theme] .comment-reply {
|
||||
background: var(--bg-soft-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
[data-theme] .new-comment textarea,
|
||||
[data-theme] .new-comment input[type="text"],
|
||||
[data-theme] .comment-edit-form textarea {
|
||||
background: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
[data-theme] .toolbar { background: var(--bg-color); border-bottom: var(--toolbar-border); font-family: var(--main-font-family); }
|
||||
[data-theme] .toolbar ul li a {
|
||||
border-radius: var(--m-radius) !important;
|
||||
letter-spacing: var(--m-ui-track);
|
||||
text-transform: var(--m-ui-case);
|
||||
font-style: var(--m-ui-style);
|
||||
}
|
||||
[data-theme] .toolbar ul li a:hover,
|
||||
[data-theme] .toolbar ul li a.selected { background: var(--bg-soft-color); color: var(--text-color); }
|
||||
[data-theme] .toolbar ul li a.pressed { color: var(--primary-color); }
|
||||
[data-theme] .toolbar ul li.separator { background: var(--border-color); }
|
||||
|
||||
[data-theme] .popup, [data-theme] #chatbox {
|
||||
background: var(--bg-color); color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--m-radius); box-shadow: var(--m-shadow);
|
||||
font-family: var(--main-font-family);
|
||||
}
|
||||
[data-theme] #chatbox #titlebar { background: var(--bg-soft-color); border-bottom: 1px solid var(--border-color); }
|
||||
[data-theme] #chattext, [data-theme] #chatinput { background: var(--bg-color); color: var(--text-color); border-color: var(--border-color); }
|
||||
|
||||
[data-theme] button, [data-theme] input[type="text"], [data-theme] input[type="submit"], [data-theme] select {
|
||||
font-family: var(--main-font-family); border-radius: var(--m-radius);
|
||||
}
|
||||
|
||||
/* ─── per-theme touches ──────────────────────────────────────────── */
|
||||
[data-theme="editorial"] .toolbar { font-style: italic; }
|
||||
[data-theme="editorial"] iframe[name="ace_outer"] {
|
||||
background:
|
||||
repeating-linear-gradient(transparent, transparent calc(1.65em - 1px),
|
||||
rgba(28,25,22,.025) calc(1.65em - 1px), rgba(28,25,22,.025) 1.65em),
|
||||
var(--m-bg) !important;
|
||||
}
|
||||
|
||||
[data-theme="brutalist"] .toolbar, [data-theme="brutalist"] #editbar { border-bottom: 2px solid var(--m-rule) !important; }
|
||||
[data-theme="brutalist"] .popup { box-shadow: var(--m-shadow); border: 2px solid var(--m-rule) !important; }
|
||||
[data-theme="brutalist"] button { box-shadow: none; border: 0 !important; }
|
||||
|
||||
[data-theme="paper"] .popup, [data-theme="paper"] button { border-radius: 12px; }
|
||||
|
||||
[data-theme="crt"][data-mode="dark"] body::before {
|
||||
content:""; position:fixed; inset:0; pointer-events:none; z-index:9998;
|
||||
background: repeating-linear-gradient(to bottom, transparent 0, transparent 2px, rgba(0,0,0,.18) 2px, rgba(0,0,0,.18) 3px);
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
[data-theme="crt"][data-mode="dark"] body::after {
|
||||
content:""; position:fixed; inset:0; pointer-events:none; z-index:9997;
|
||||
background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,.55) 100%);
|
||||
}
|
||||
[data-theme="crt"][data-mode="dark"] h1, [data-theme="crt"][data-mode="dark"] h2 { font-family: var(--m-display-font); text-shadow: 0 0 6px rgba(127,255,174,.55); }
|
||||
[data-theme="crt"][data-mode="light"] h1, [data-theme="crt"][data-mode="light"] h2 { font-family: var(--m-display-font); }
|
||||
|
||||
[data-theme="industrial"] .toolbar ul li a.pressed,
|
||||
[data-theme="industrial"] .toolbar ul li a.selected { box-shadow: inset 0 -2px 0 var(--primary-color); }
|
||||
253
src/static/skins/margin/pad.js
Normal file
253
src/static/skins/margin/pad.js
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
'use strict';
|
||||
|
||||
const MAX_PADS_IN_HISTORY = 3;
|
||||
// Selectable themes — orthogonal to light/dark mode. `value` is the
|
||||
// data-theme attribute slug used in pad.css [data-theme="…"] selectors;
|
||||
// `label` is the dropdown option text. Colibris is the default.
|
||||
const MARGIN_THEMES = [
|
||||
{value: 'colibris', label: 'Colibris'},
|
||||
{value: 'editorial', label: 'Editorial'},
|
||||
{value: 'brutalist', label: 'Brutalist'},
|
||||
{value: 'paper', label: 'Paper'},
|
||||
{value: 'crt', label: 'CRT'},
|
||||
{value: 'industrial', label: 'Industrial'},
|
||||
];
|
||||
const MARGIN_THEME_VALUES = MARGIN_THEMES.map((t) => t.value);
|
||||
const MARGIN_THEME_DEFAULT = 'colibris';
|
||||
const MARGIN_THEME_KEY = 'marginTheme';
|
||||
|
||||
// Light/dark mode is orthogonal — paired with the theme in CSS via
|
||||
// [data-theme="X"][data-mode="light|dark"]. Colibris has only a light palette;
|
||||
// the others define both. Each theme has a "natural" default mode used when
|
||||
// the user hasn't expressed a preference (CRT/Industrial start dark, the
|
||||
// rest start light).
|
||||
const MARGIN_MODE_KEY = 'marginMode';
|
||||
const MARGIN_MODE_DEFAULTS = {
|
||||
colibris: 'light',
|
||||
editorial: 'light',
|
||||
brutalist: 'light',
|
||||
paper: 'light',
|
||||
crt: 'dark',
|
||||
industrial: 'dark',
|
||||
};
|
||||
|
||||
const applyMarginTheme = (theme) => {
|
||||
if (!MARGIN_THEME_VALUES.includes(theme)) theme = MARGIN_THEME_DEFAULT;
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
try { localStorage.setItem(MARGIN_THEME_KEY, theme); } catch (_) { /* private mode */ }
|
||||
};
|
||||
|
||||
const applyMarginMode = (mode) => {
|
||||
if (mode !== 'light' && mode !== 'dark') mode = 'light';
|
||||
document.documentElement.setAttribute('data-mode', mode);
|
||||
try { localStorage.setItem(MARGIN_MODE_KEY, mode); } catch (_) { /* private mode */ }
|
||||
};
|
||||
|
||||
// Apply saved or default theme + mode as early as possible so first paint
|
||||
// matches the user's last choice. If no mode is saved, fall back to the
|
||||
// natural default for the selected theme.
|
||||
let initialTheme = MARGIN_THEME_DEFAULT;
|
||||
let initialMode = MARGIN_MODE_DEFAULTS[MARGIN_THEME_DEFAULT];
|
||||
try {
|
||||
initialTheme = localStorage.getItem(MARGIN_THEME_KEY) || initialTheme;
|
||||
initialMode = localStorage.getItem(MARGIN_MODE_KEY) || MARGIN_MODE_DEFAULTS[initialTheme] || 'light';
|
||||
} catch (_) { /* private mode */ }
|
||||
applyMarginTheme(initialTheme);
|
||||
applyMarginMode(initialMode);
|
||||
|
||||
// Build a single dropdown-line row mirroring the markup used by the built-in
|
||||
// Font type / Language rows so margin's Theme picker inherits the same
|
||||
// styling. `selectId` keeps the user-settings vs pad-settings copies distinct.
|
||||
const buildThemeRow = (selectId) => {
|
||||
const row = document.createElement('p');
|
||||
row.className = 'dropdown-line margin-theme-row';
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = selectId;
|
||||
// Match the colon convention used by the built-in "Font type:" / "Language:"
|
||||
// rows so the field reads consistently in the Settings popup.
|
||||
label.textContent = 'Theme:';
|
||||
// popup.css sets `.popup .dropdowns-container label { width: 120px;
|
||||
// display: inline-block }`, but apply it inline too so the select's
|
||||
// left edge sits at exactly the same x as the Font type / Language
|
||||
// selects regardless of stylesheet load order.
|
||||
label.style.cssText = 'width: 120px; display: inline-block;';
|
||||
const select = document.createElement('select');
|
||||
select.id = selectId;
|
||||
MARGIN_THEMES.forEach(({value, label: optLabel}) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = value;
|
||||
opt.textContent = optLabel;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
select.value = document.documentElement.getAttribute('data-theme') || MARGIN_THEME_DEFAULT;
|
||||
// nice-select wraps <select> and dispatches change via $().trigger('change'),
|
||||
// which only fires jQuery-bound handlers — not native addEventListener. Bind
|
||||
// through jQuery so the widget actually drives applyMarginTheme.
|
||||
$(select).on('change', () => {
|
||||
applyMarginTheme(select.value);
|
||||
// Mirror to the sibling select (user-settings ↔ pad-settings).
|
||||
$('.margin-theme-row select').each(function () {
|
||||
if (this !== select) this.value = select.value;
|
||||
});
|
||||
if ($.fn.niceSelect) $('.margin-theme-row select').niceSelect('update');
|
||||
});
|
||||
row.appendChild(label);
|
||||
row.appendChild(select);
|
||||
return row;
|
||||
};
|
||||
|
||||
// Build the Dark mode toggle row. Same checkbox-on-label pattern as the
|
||||
// existing "Disable Chat" / "Show line numbers" rows in pad.html so margin's
|
||||
// form.css picks up identical chrome.
|
||||
const buildDarkModeRow = (checkboxId) => {
|
||||
const row = document.createElement('p');
|
||||
row.className = 'margin-mode-row';
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = checkboxId;
|
||||
checkbox.checked = document.documentElement.getAttribute('data-mode') === 'dark';
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = checkboxId;
|
||||
label.textContent = 'Dark mode';
|
||||
$(checkbox).on('change', () => {
|
||||
applyMarginMode(checkbox.checked ? 'dark' : 'light');
|
||||
$('.margin-mode-row input[type="checkbox"]').each(function () {
|
||||
if (this !== checkbox) this.checked = checkbox.checked;
|
||||
});
|
||||
});
|
||||
row.appendChild(checkbox);
|
||||
row.appendChild(label);
|
||||
return row;
|
||||
};
|
||||
|
||||
const injectThemeSelector = () => {
|
||||
// Two .dropdowns-container blocks exist: user settings + pad-wide settings.
|
||||
// Mirror the Theme dropdown into both and the Dark mode toggle into the
|
||||
// section the column lives in (so the row sits next to other checkboxes).
|
||||
const sections = [
|
||||
{
|
||||
sectionId: 'user-settings-section',
|
||||
dropdownId: 'margin-theme-user',
|
||||
checkboxId: 'margin-mode-user',
|
||||
},
|
||||
{
|
||||
sectionId: 'pad-settings-section',
|
||||
dropdownId: 'margin-theme-pad',
|
||||
checkboxId: 'margin-mode-pad',
|
||||
},
|
||||
];
|
||||
let injectedAny = false;
|
||||
let allDone = true;
|
||||
let injectedThisCall = false;
|
||||
sections.forEach(({sectionId, dropdownId, checkboxId}) => {
|
||||
const section = document.getElementById(sectionId);
|
||||
if (!section) { allDone = false; return; }
|
||||
const dropdownsContainer = section.querySelector('.dropdowns-container');
|
||||
if (!dropdownsContainer) { allDone = false; return; }
|
||||
if (!document.getElementById(dropdownId)) {
|
||||
dropdownsContainer.appendChild(buildThemeRow(dropdownId));
|
||||
injectedThisCall = true;
|
||||
}
|
||||
if (!document.getElementById(checkboxId)) {
|
||||
// Place the Dark mode checkbox among the section's other checkboxes,
|
||||
// before the dropdowns container so it reads in toggle-then-pickers
|
||||
// order — matching the natural top-to-bottom flow of the section.
|
||||
section.insertBefore(buildDarkModeRow(checkboxId), dropdownsContainer);
|
||||
}
|
||||
injectedAny = true;
|
||||
});
|
||||
// Etherpad runs $('select').niceSelect() once at pad-init (pad_editbar.ts),
|
||||
// so a freshly appended <select> is still native chrome. Wrap ours now so
|
||||
// it matches the Font type / Language widgets visually.
|
||||
if (injectedThisCall && window.$ && $.fn.niceSelect) {
|
||||
$('.margin-theme-row select').niceSelect();
|
||||
}
|
||||
return injectedAny && allDone;
|
||||
};
|
||||
|
||||
// Propagate data-theme + data-mode from the host page into the editor iframes
|
||||
// so [data-theme="X"][data-mode="Y"] rules in pad-editor.css apply inside.
|
||||
const propagateTheme = () => {
|
||||
try {
|
||||
const theme = document.documentElement.getAttribute('data-theme');
|
||||
const mode = document.documentElement.getAttribute('data-mode');
|
||||
if (!theme) return;
|
||||
const setOn = (doc) => {
|
||||
if (!doc) return;
|
||||
const apply = (el) => {
|
||||
if (!el) return;
|
||||
el.setAttribute('data-theme', theme);
|
||||
if (mode) el.setAttribute('data-mode', mode);
|
||||
};
|
||||
apply(doc.documentElement);
|
||||
apply(doc.getElementById && doc.getElementById('outerdocbody'));
|
||||
apply(doc.getElementById && doc.getElementById('innerdocbody'));
|
||||
};
|
||||
const outer = document.querySelector('iframe[name="ace_outer"]');
|
||||
if (!outer) return;
|
||||
setOn(outer.contentDocument);
|
||||
const inner = outer.contentDocument && outer.contentDocument.querySelector('iframe[name="ace_inner"]');
|
||||
if (inner) setOn(inner.contentDocument);
|
||||
} catch (_) { /* iframe not ready yet */ }
|
||||
};
|
||||
|
||||
window.customStart = () => {
|
||||
$('#pad_title').show();
|
||||
$('.buttonicon').on('mousedown', function () { $(this).parent().addClass('pressed'); });
|
||||
$('.buttonicon').on('mouseup', function () { $(this).parent().removeClass('pressed'); });
|
||||
|
||||
// Inject the Theme selector into Settings → user-settings section.
|
||||
// Retry until the popup DOM is mounted (it's rendered eagerly in pad.html
|
||||
// but we keep a short poll for safety).
|
||||
let injectAttempts = 0;
|
||||
const injectTick = setInterval(() => {
|
||||
if (injectThemeSelector() || ++injectAttempts > 40) clearInterval(injectTick);
|
||||
}, 250);
|
||||
|
||||
// Try repeatedly until iframes have mounted.
|
||||
let attempts = 0;
|
||||
const tick = setInterval(() => {
|
||||
propagateTheme();
|
||||
if (++attempts > 40) clearInterval(tick); // ~10s
|
||||
}, 250);
|
||||
// Also re-apply if theme/mode is changed at runtime
|
||||
new MutationObserver(propagateTheme).observe(document.documentElement, {
|
||||
attributes: true, attributeFilter: ['data-theme', 'data-mode'],
|
||||
});
|
||||
|
||||
const pathSegments = window.location.pathname.split('/');
|
||||
const padName = pathSegments[pathSegments.length - 1];
|
||||
// localStorage access and JSON.parse can both throw (private mode,
|
||||
// restricted storage, corrupted value). Treat any failure as "no recent
|
||||
// pads yet" rather than aborting customStart().
|
||||
let recentPadsList = [];
|
||||
try {
|
||||
const raw = localStorage.getItem('recentPads');
|
||||
if (raw != null) {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (Array.isArray(parsed)) {
|
||||
recentPadsList = parsed.filter(
|
||||
(p) => p && typeof p === 'object' && typeof p.name === 'string');
|
||||
}
|
||||
}
|
||||
} catch (_) { /* private mode / corrupted entry */ }
|
||||
if (!recentPadsList.some((pad) => pad.name === padName)) {
|
||||
if (recentPadsList.length >= MAX_PADS_IN_HISTORY) {
|
||||
recentPadsList.shift(); // Remove the oldest pad if we have more than 10
|
||||
}
|
||||
recentPadsList.push({
|
||||
name: padName,
|
||||
timestamp: new Date().toISOString(), // Store the timestamp for sorting
|
||||
members: 1,
|
||||
});
|
||||
} else {
|
||||
// Update the timestamp if the pad already exists
|
||||
const existingPad = recentPadsList.find((pad) => pad.name === padName);
|
||||
if (existingPad) {
|
||||
existingPad.timestamp = new Date().toISOString();
|
||||
}
|
||||
}
|
||||
try {
|
||||
localStorage.setItem('recentPads', JSON.stringify(recentPadsList));
|
||||
} catch (_) { /* quota / private mode — skip silently */ }
|
||||
};
|
||||
74
src/static/skins/margin/src/components/buttons.css
Normal file
74
src/static/skins/margin/src/components/buttons.css
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
button, .btn
|
||||
{
|
||||
padding: 5px 20px;
|
||||
border-radius: 4px;
|
||||
line-height: 1.5;
|
||||
width: auto;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-primary
|
||||
{
|
||||
background-color: #64d29b;
|
||||
background-color: var(--primary-color);
|
||||
color: #ffffff;
|
||||
color: var(--bg-color);
|
||||
}
|
||||
.btn-default {
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* Sekundär (outlined) */
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: #1f8a3e;
|
||||
border: 2px solid #1f8a3e;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.active-btn {
|
||||
text-underline-offset: 10px;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: solid;
|
||||
text-decoration-thickness: 2px;
|
||||
text-decoration-color: #1f8a3e;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #1f8a3e;
|
||||
color: #fff;
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 1px 2px rgba(0,0,0,0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary:disabled {
|
||||
background: transparent;
|
||||
color: #aaa;
|
||||
border-color: #aaa;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #d1242f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #b71c26;
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 1px 2px rgba(0,0,0,0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-danger:disabled {
|
||||
background: #aaa;
|
||||
color: #fff;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
91
src/static/skins/margin/src/components/chat.css
Normal file
91
src/static/skins/margin/src/components/chat.css
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#chatbox {
|
||||
background-color: transparent !important;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.chat-content {
|
||||
background: none;
|
||||
padding: 0;
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
|
||||
.chat-content, #chaticon {
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
border: none;
|
||||
}
|
||||
|
||||
#chaticon {
|
||||
padding: 10px 20px;
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
right: 30px;
|
||||
}
|
||||
|
||||
#chatbox.stickyChat .chat-content {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
|
||||
#titlebar {
|
||||
bottom: 0;
|
||||
line-height: 44px;
|
||||
height: 44px;
|
||||
padding: 0 7px;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#titlelabel, #chatlabel {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#titlebar #titlelabel { font-size: 16px; }
|
||||
#chatlabel { margin-right: 15px; }
|
||||
|
||||
#chattext {
|
||||
padding: 0;
|
||||
border-top: 1px solid #ffffff;
|
||||
border-top: 1px solid var(--bg-color);
|
||||
border-bottom: 1px solid #ffffff;
|
||||
border-bottom: 1px solid var(--bg-color);
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
#chattext p {
|
||||
padding: 4px 10px;
|
||||
}
|
||||
#chattext:not(.authorColors) p:first-child {
|
||||
padding-top: 10px;
|
||||
}
|
||||
#chattext:not(.authorColors) p:last-child {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#chatinputbox {
|
||||
padding: 8px;
|
||||
}
|
||||
#chatinputbox #chatinput {
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.chat-content {
|
||||
transform: scale(1);
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
#chaticon {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.stick-to-screen-btn { display: none; }
|
||||
}
|
||||
122
src/static/skins/margin/src/components/form.css
Normal file
122
src/static/skins/margin/src/components/form.css
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
input[type="text"], select, textarea, .nice-select {
|
||||
border-radius: 3px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input[type="text"], textarea {
|
||||
padding: 8px 10px;
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
border: none;
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
input[type="text"]::placeholder, textarea::placeholder {
|
||||
color: #576273;
|
||||
color: var(--text-soft-color);
|
||||
}
|
||||
select, .nice-select {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
border: 1px solid var(--bg-soft-color);
|
||||
/* Zero vertical padding so the line-height fully owns the widget's
|
||||
* inner height; the inherited box is 28px (border-box) and we want the
|
||||
* line-box centered on its content. */
|
||||
padding: 0 25px 0 10px;
|
||||
font-weight: bold;
|
||||
line-height: 20px;
|
||||
}
|
||||
select:hover, .nice-select:hover {
|
||||
border-color: var(--bg-soft-color)
|
||||
}
|
||||
.nice-select .list {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
.nice-select .option:hover,.nice-select .option.focus,.nice-select .option.selected.focus {
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
.nice-select .option {
|
||||
padding: 0 15px;
|
||||
}
|
||||
.popup .nice-select .list {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
|
||||
/* Checkboxes
|
||||
========================================================================== */
|
||||
/* Remove default checkbox */
|
||||
[type="checkbox"]:not(:checked),
|
||||
[type="checkbox"]:checked {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[type="checkbox"] + label {
|
||||
position: relative;
|
||||
padding-left: 2.5rem;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 1.4rem;
|
||||
line-height: 1.4rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
[type="checkbox"] + label:before,
|
||||
[type="checkbox"] + label:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
margin-top: 4px;
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
|
||||
/* BEFORE, the container*/
|
||||
[type="checkbox"] + label:before {
|
||||
width: 24px;
|
||||
height: 14px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 6px;
|
||||
border: 2px solid #576273;
|
||||
border: 2px solid var(--text-soft-color);
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
opacity: .7;
|
||||
}
|
||||
[type="checkbox"]:checked + label:before {
|
||||
background-color: transparent;
|
||||
border-color: #64d29b;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* AFTER, the circle moving */
|
||||
[type="checkbox"] + label:after {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: #576273;
|
||||
background-color: var(--text-soft-color);
|
||||
top: -1px;
|
||||
left: -3px;
|
||||
}
|
||||
[type="checkbox"]:checked + label:after {
|
||||
background-color: #64d29b;
|
||||
background-color: var(--primary-color);
|
||||
transform: translateX(14px);
|
||||
}
|
||||
|
||||
/* Apply to any disabled checkbox (checked or unchecked), not just checked
|
||||
ones, so dependent toggles like "Chat always on screen" visibly grey out
|
||||
when "Disable chat" is ticked. Fixes #7592. */
|
||||
[type="checkbox"]:disabled + label,
|
||||
[type="checkbox"]:disabled + label:before,
|
||||
[type="checkbox"]:disabled + label:after {
|
||||
cursor: not-allowed;
|
||||
opacity: .4;
|
||||
}
|
||||
82
src/static/skins/margin/src/components/gritter.css
Normal file
82
src/static/skins/margin/src/components/gritter.css
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
.gritter-item:not(.error) .popup-content{
|
||||
background-color: #64d29b;
|
||||
background-color: var(--primary-color);
|
||||
color: #ffffff;
|
||||
color: var(--super-light-color);
|
||||
}
|
||||
.gritter-item .popup-content {
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
}
|
||||
#gritter-container.bottom .gritter-item .popup-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#gritter-container.top .gritter-item .popup-content {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.gritter-item p {
|
||||
margin: 0 !important;
|
||||
}
|
||||
.gritter-item .gritter-title {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.gritter-item .gritter-close {
|
||||
margin-left: 15px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
.gritter-item:not(.error) .gritter-close .buttonicon {
|
||||
color: #ffffff;
|
||||
color: var(--super-light-color);
|
||||
}
|
||||
|
||||
/* CHAT GRIITER ITEM */
|
||||
.gritter-item.chat-gritter-msg:not(.error) .popup-content {
|
||||
background-color: white;
|
||||
background-color: var(--bg-color);
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.gritter-item.chat-gritter-msg .gritter-content {
|
||||
text-align: left;
|
||||
}
|
||||
.gritter-item.chat-gritter-msg .author-name {
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.gritter-item.chat-gritter-msg:not(.error) .gritter-close .buttonicon {
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.gritter-item.saved-revision {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
#gritter-container.top .gritter-item.popup > .popup-content {
|
||||
transform: scale(0.8) translateY(-100px);
|
||||
}
|
||||
#gritter-container.bottom .gritter-item.popup > .popup-content {
|
||||
transform: scale(0.8) translateY(0px);
|
||||
}
|
||||
|
||||
.gritter-item.popup.popup-show > .popup-content {
|
||||
transform: scale(1) translateY(0) !important;
|
||||
transition: all 0.4s cubic-bezier(0.74, -0.05, 0.27, 1.75) !important;
|
||||
}
|
||||
@media (prefers-reduced-motion) {
|
||||
#gritter-container.top .gritter-item.popup > .popup-content {
|
||||
transform: scale(1) translateY(0px) !important;
|
||||
}
|
||||
#gritter-container.bottom .gritter-item.popup > .popup-content {
|
||||
transform: scale(1) translateY(0px) !important;
|
||||
}
|
||||
.gritter-item.popup.popup-show > .popup-content {
|
||||
transform: scale(1) translateY(0px) !important;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* for ep_deleted_after_delay */
|
||||
.gritter-item #close_expiration_notif {
|
||||
display: none;
|
||||
}
|
||||
5
src/static/skins/margin/src/components/import-export.css
Normal file
5
src/static/skins/margin/src/components/import-export.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#importmessagefail {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#importsubmitinput[disabled] { opacity: .6; }
|
||||
177
src/static/skins/margin/src/components/popup.css
Normal file
177
src/static/skins/margin/src/components/popup.css
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
.popup-content {
|
||||
border-radius: 5px;
|
||||
padding: 25px;
|
||||
background: none;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
color: #576273;
|
||||
color: var(--text-soft-color);
|
||||
border: none;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
}
|
||||
|
||||
#mycolorpicker, #users {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.popup h1 {
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.popup h2 {
|
||||
margin-bottom: 15px;
|
||||
margin-top: 20px;
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.settings-sections {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
margin-bottom: 20px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#settings .settings-section > h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.popup:not(.comment-modal) p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.popup .dropdowns-container .dropdown-line {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.popup .dropdowns-container label {
|
||||
width: 120px;
|
||||
display: inline-block;
|
||||
}
|
||||
.popup .dropdowns-container .nice-select {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.settings-notice {
|
||||
color: var(--text-color);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.4;
|
||||
border-left: 3px solid var(--primary-color);
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 1100px) {
|
||||
.settings-sections.has-pad-settings {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.popup>.popup-content {
|
||||
transform: scale(1);
|
||||
transition: none;
|
||||
}
|
||||
.nice-select .list {
|
||||
transform: scale(1) translateY(0px);
|
||||
-webkit-transform: scale(1) translateY(0px);
|
||||
-ms-transform: scale(1) translateY(0px);
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.popup-content {
|
||||
padding: 1rem;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), -1px 1px 16px 3px rgba(27, 39, 51, 0.12);
|
||||
}
|
||||
.popup .dropdowns-container select {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SKIN Variants Popup */
|
||||
#skin-variants {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: auto;
|
||||
}
|
||||
#skin-variants .popup-content > p {
|
||||
margin-top: 25px;
|
||||
}
|
||||
#skin-variants-result{
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
.skin-variant-container {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
#delete-pad {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
/* Pad deletion-token modal + delete-with-token disclosure (GDPR PR1) */
|
||||
#deletiontoken-modal .popup-content {
|
||||
max-width: 32rem;
|
||||
}
|
||||
|
||||
#deletiontoken-modal .deletiontoken-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#deletiontoken-modal #deletiontoken-copy {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#deletiontoken-modal #deletiontoken-value {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
padding: 0.4rem;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
#delete-pad-with-token {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
#delete-pad-with-token summary {
|
||||
display: inline-block;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
padding: 5px 20px;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
background: #d1242f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#delete-pad-with-token summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#delete-pad-with-token summary:hover {
|
||||
background: #b71c26;
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 1px 2px rgba(0,0,0,0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
#delete-pad-with-token label {
|
||||
display: block;
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
#delete-pad-with-token input {
|
||||
margin: 0.5rem 0;
|
||||
width: 100%;
|
||||
font-family: monospace;
|
||||
padding: 0.4rem;
|
||||
}
|
||||
41
src/static/skins/margin/src/components/scrollbars.css
Normal file
41
src/static/skins/margin/src/components/scrollbars.css
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
@media (min-width: 721px) {
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: white;
|
||||
background-color: var(--scrollbar-track);
|
||||
border-radius: 10px;
|
||||
border: 7px solid #f2f3f4;
|
||||
border: 7px solid var(--scrollbar-bg);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
min-height: 40px;
|
||||
border-radius: 10px;
|
||||
background-color: #576273;
|
||||
background-color: var(--scrollbar-thumb);
|
||||
border: 7px solid #f2f3f4;
|
||||
border: 7px solid var(--scrollbar-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.thin-scrollbar::-webkit-scrollbar-track {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.thin-scrollbar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.thin-scrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 0px;
|
||||
min-height: 40px;
|
||||
background-color: #d2d2d2;
|
||||
background-color: var(--middle-color);
|
||||
border: none;
|
||||
}
|
||||
31
src/static/skins/margin/src/components/sidediv.css
Normal file
31
src/static/skins/margin/src/components/sidediv.css
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#sidediv {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
#sidedivinner>div:before {
|
||||
font-family: var(--main-font-family); /* the parent div have font-family monospace (line number) */
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#sidedivinner>div .line-number {
|
||||
line-height: inherit;
|
||||
font-family: RobotoMono;
|
||||
display: inline-block;
|
||||
color: #576273;
|
||||
color: var(--text-soft-color);
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#sidedivinner>div .line-number:hover {
|
||||
background-color: var(--bg-soft-color);
|
||||
border-radius: 5px 0 0 5px;
|
||||
font-weight: bold;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.plugin-ep_author_neat #sidedivinner>div .line-number:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
21
src/static/skins/margin/src/components/table-of-content.css
Normal file
21
src/static/skins/margin/src/components/table-of-content.css
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#toc {
|
||||
padding: 20px 20px 10px 10px !important;
|
||||
min-width: 146px !important;
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
order: -2;
|
||||
}
|
||||
|
||||
#tocItems {
|
||||
line-height: 40px !important;
|
||||
}
|
||||
|
||||
.plugin-ep_resizable_bars #toc {
|
||||
min-width: 186px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
#toc {
|
||||
padding-top: 10px !important
|
||||
}
|
||||
}
|
||||
154
src/static/skins/margin/src/components/toolbar.css
Normal file
154
src/static/skins/margin/src/components/toolbar.css
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
.toolbar {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
color: #576273;
|
||||
color: var(--text-soft-color);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#editbar.editor-scrolled {
|
||||
border-bottom: 1px solid #d2d2d2;
|
||||
border-bottom: var(--toolbar-border);
|
||||
}
|
||||
|
||||
.toolbar ul {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toolbar ul.menu_left {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.toolbar ul li {
|
||||
margin: 7px 1px;
|
||||
}
|
||||
|
||||
.toolbar ul li a, .toolbar .buttonicon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.toolbar .buttonicon {
|
||||
background-color: transparent;
|
||||
font-size: 15px;
|
||||
}
|
||||
.buttonicon-insertorderedlist:before,
|
||||
.buttonicon-insertunorderedlist:before,
|
||||
.buttonicon-indent:before,
|
||||
.buttonicon-outdent:before {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.toolbar ul li.separator {
|
||||
visibility: hidden;
|
||||
width: 1px;
|
||||
margin: 0 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toolbar.condensed ul li {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.toolbar.condensed ul li.separator {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.toolbar ul li a {
|
||||
background-color: transparent;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 3px !important;
|
||||
transition: background-color .1s;
|
||||
}
|
||||
|
||||
.toolbar ul li a:hover, .toolbar ul li select:hover {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.toolbar ul li a.selected {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
.toolbar ul li a.pressed,
|
||||
.toolbar ul li select:active {
|
||||
color: #64d29b;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.toolbar ul li select:active option {
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
color: #576273;
|
||||
color: var(--text-soft-color);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.toolbar .menu_right li a.selected {
|
||||
background-color: #576273;
|
||||
background-color: var(--text-soft-color);
|
||||
color: #ffffff;
|
||||
color: var(--bg-color);
|
||||
}
|
||||
|
||||
.toolbar ul li[data-key=showusers] {
|
||||
margin: 0;
|
||||
margin-left: 15px;
|
||||
width: 45px;
|
||||
height: 100%;
|
||||
}
|
||||
.toolbar ul li[data-key=showusers] > a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.toolbar .menu_right .separator {
|
||||
display: none;
|
||||
}
|
||||
.toolbar .menu_right li {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.toolbar.cropped .menu_left {
|
||||
height: 39px;
|
||||
padding-top: 1px;
|
||||
}
|
||||
.toolbar .show-more-icon-btn {
|
||||
font-size: 1.8rem;
|
||||
color: #64d29b;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.toolbar ul li.separator {
|
||||
margin: 0 5px;
|
||||
background: none;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-layout .toolbar ul li {
|
||||
margin: 5px 2px;
|
||||
}
|
||||
.mobile-layout .toolbar ul li.separator {
|
||||
margin: 0 5px;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
.mobile-layout .toolbar ul li.separator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.mobile-layout .toolbar .menu_right {
|
||||
border-top: 1px solid #d2d2d2;
|
||||
border-top: var(--toolbar-border);
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
padding: 0;
|
||||
}
|
||||
.mobile-layout .toolbar ul li a:hover {
|
||||
/* background-color: transparent; */
|
||||
}
|
||||
65
src/static/skins/margin/src/components/users.css
Normal file
65
src/static/skins/margin/src/components/users.css
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
table#otheruserstable {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clicking a row in the user list opens chat and prefills "@<name> ".
|
||||
* The pointer cursor on the name cell makes the affordance visible —
|
||||
* the swatch keeps its own (color-picker) click semantics, so leave
|
||||
* its cursor alone.
|
||||
*/
|
||||
#otheruserstable tr[data-authorId] .usertdname {
|
||||
cursor: pointer;
|
||||
}
|
||||
#otheruserstable tr[data-authorId]:hover .usertdname {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.popup#users.chatAndUsers > .popup-content {
|
||||
padding: 20px 10px;
|
||||
height: 250px;
|
||||
border-left: none;
|
||||
transition: none;
|
||||
border-bottom-color: #d2d2d2;
|
||||
border-bottom-color: var(--border-color);
|
||||
}
|
||||
.popup#users.chatAndUsers #mycolorpicker.popup {
|
||||
right: calc(100% + 30px);
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
#otheruserstable .swatch {
|
||||
border: none !important;
|
||||
border-radius: 50%;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
margin-left: 1px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
#myusernameform {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
input#myusernameedit {
|
||||
min-width: 110px;
|
||||
border: none !important;
|
||||
background-color: transparent !important;
|
||||
border-bottom: 1px solid #d2d2d2 !important;
|
||||
border-bottom: 1px solid var(--border-color) !important;
|
||||
border-radius: 0;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#myswatch {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#colorpicker {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
#mycolorpickerpreview {
|
||||
border-radius: 50%;
|
||||
}
|
||||
11
src/static/skins/margin/src/general.css
Normal file
11
src/static/skins/margin/src/general.css
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
body {
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
font-family: Quicksand, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
font-family: var(--main-font-family);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #64d29b;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
48
src/static/skins/margin/src/layout.css
Normal file
48
src/static/skins/margin/src/layout.css
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#outerdocbody {
|
||||
margin: 0 auto;
|
||||
padding-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#editorcontainerbox {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
#editorcontainerbox .sticky-container {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#outerdocbody iframe, #outerdocbody > #innerdocbody {
|
||||
max-width: 900px;
|
||||
padding: 40px 55px;
|
||||
padding-left: var(--editor-horizontal-padding);
|
||||
padding-right: var(--editor-horizontal-padding);
|
||||
padding-top: var(--editor-vertical-padding);
|
||||
padding-bottom: var(--editor-vertical-padding);
|
||||
box-shadow: none;
|
||||
border: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
#sidediv {
|
||||
/* Padding must be the same than editor, otherwise it creates problem */
|
||||
padding-top: 40px; /* = #innerdocbody iframe vertical padding */
|
||||
padding-bottom: 40px;
|
||||
padding-top: calc(var(--editor-vertical-padding) + 15px);
|
||||
padding-bottom: calc(var(--editor-vertical-padding) + 15px);
|
||||
}
|
||||
|
||||
@media (max-width:1000px) {
|
||||
#outerdocbody {
|
||||
padding-top: 0;
|
||||
}
|
||||
#outerdocbody iframe, #outerdocbody > #innerdocbody {
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
48
src/static/skins/margin/src/pad-editor.css
Normal file
48
src/static/skins/margin/src/pad-editor.css
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* pad-editor.css — loaded INSIDE the inner editor iframe by Etherpad.
|
||||
* Defines theme tokens here too, since CSS from the parent document
|
||||
* doesn't cascade into iframes. The data-theme attribute is propagated
|
||||
* onto html/#innerdocbody by pad.js. */
|
||||
|
||||
#innerdocbody {
|
||||
background: transparent;
|
||||
color: var(--text-color, #485365);
|
||||
}
|
||||
|
||||
[data-theme="editorial"] { --text-color:#1c1916; --bg-color:#fbf8f2; --m-bg:#f5f0e8; }
|
||||
[data-theme="brutalist"] { --text-color:#000; --bg-color:#fff; --m-bg:#f3f3f0; }
|
||||
[data-theme="paper"] { --text-color:#2a2520; --bg-color:#fbf6ec; --m-bg:#f6f1e8; }
|
||||
[data-theme="crt"] { --text-color:#7fffae; --bg-color:#08200f; --m-bg:#04140a; }
|
||||
[data-theme="industrial"] { --text-color:#e6e8eb; --bg-color:#14171c; --m-bg:#0d0f12; }
|
||||
|
||||
[data-theme] #innerdocbody,
|
||||
[data-theme] body { background: var(--m-bg) !important; color: var(--text-color) !important; }
|
||||
[data-theme] #innerdocbody a { color: var(--text-color); }
|
||||
|
||||
[data-theme="crt"] #innerdocbody { text-shadow: 0 0 6px rgba(127,255,174,.45); font-family: "IBM Plex Mono", ui-monospace, monospace; }
|
||||
|
||||
/* Comment highlights in the editor — upstream forces #fffacc + dark text,
|
||||
* which looks like a white slab on dark themes. Replace with a tinted
|
||||
* underline-ish highlight that adapts to the current theme. */
|
||||
[data-theme] #innerdocbody .ace-line .comment {
|
||||
background-color: color-mix(in srgb, var(--accent, #f5d76e) 22%, transparent) !important;
|
||||
color: inherit !important;
|
||||
box-shadow: inset 0 -2px 0 0 var(--accent, #f5d76e);
|
||||
border-radius: 1px;
|
||||
}
|
||||
[data-theme="editorial"] { --accent:#b8451f; }
|
||||
[data-theme="brutalist"] { --accent:#ff3b00; }
|
||||
[data-theme="paper"] { --accent:#7a5a2f; }
|
||||
[data-theme="crt"] { --accent:#f5d76e; }
|
||||
[data-theme="industrial"] { --accent:#ff8a3d; }
|
||||
|
||||
/* CRT drop-cap on the very first line of the pad. Etherpad wraps each line
|
||||
* in a <div>, so target the first child block of #innerdocbody. */
|
||||
[data-theme="crt"] #innerdocbody > div:first-child::first-letter {
|
||||
font-family: "VT323", "IBM Plex Mono", monospace;
|
||||
font-size: 3.2em;
|
||||
line-height: 0.85;
|
||||
float: left;
|
||||
padding: 0.05em 0.12em 0 0;
|
||||
color: #f5d76e;
|
||||
text-shadow: 0 0 10px rgba(245,215,110,.7), 0 0 22px rgba(245,215,110,.35);
|
||||
}
|
||||
228
src/static/skins/margin/src/pad-variants.css
Normal file
228
src/static/skins/margin/src/pad-variants.css
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/* =========================== */
|
||||
/* === Super Light Toolbar === */
|
||||
/* =========================== */
|
||||
.super-light-toolbar .toolbar, .super-light-toolbar .popup-content, .super-light-toolbar #pad_title {
|
||||
--text-color: var(--super-dark-color);
|
||||
--text-soft-color: var(--dark-color);
|
||||
--border-color: #e4e6e9;
|
||||
--bg-soft-color: var(--light-color);
|
||||
--bg-color: var(--super-light-color);
|
||||
}
|
||||
/* ===================== */
|
||||
/* === Light Toolbar === */
|
||||
/* ===================== */
|
||||
.light-toolbar .toolbar, .light-toolbar .popup-content, .light-toolbar #pad_title {
|
||||
--text-color: var(--super-dark-color);
|
||||
--text-soft-color: var(--dark-color);
|
||||
--border-color: var(--middle-color);
|
||||
--bg-soft-color: var(--super-light-color);
|
||||
--bg-color: var(--light-color);
|
||||
}
|
||||
/* ========================== */
|
||||
/* === Super Dark Toolbar === */
|
||||
/* ========================== */
|
||||
.super-dark-toolbar .toolbar, .super-dark-toolbar .popup-content, .super-dark-toolbar #pad_title {
|
||||
--text-color: var(--super-light-color);
|
||||
--text-soft-color: var(--light-color);
|
||||
--border-color: var(--dark-color);
|
||||
--bg-soft-color: var(--dark-color);
|
||||
--bg-color: var(--super-dark-color);
|
||||
}
|
||||
.super-dark-toolbar.super-dark-editor .popup-content {
|
||||
border: 1px solid var(--dark-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
/* ==================== */
|
||||
/* === Dark Toolbar === */
|
||||
/* ==================== */
|
||||
.dark-toolbar .toolbar, .dark-toolbar .popup-content, .dark-toolbar #pad_title {
|
||||
--text-color: var(--super-light-color);
|
||||
--text-soft-color: var(--light-color);
|
||||
--border-color: var(--super-dark-color);
|
||||
--bg-soft-color: var(--super-dark-color);
|
||||
--bg-color: var(--dark-color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ============================ */
|
||||
/* == Super Light Background == */
|
||||
/* ============================ */
|
||||
.super-light-background #editorcontainerbox, .super-light-background #sidediv,
|
||||
.super-light-background #chatbox, .super-light-background #outerdocbody, .super-light-background {
|
||||
--text-color: var(--super-dark-color);
|
||||
--text-soft-color: var(--dark-color);
|
||||
--border-color: #e4e6e9;
|
||||
--bg-soft-color: var(--light-color);
|
||||
--bg-color: var(--super-light-color);
|
||||
}
|
||||
.super-light-background body, .full-width-editor.super-light-editor body:not(.comments-active) {
|
||||
--scrollbar-bg: var(--super-light-color);
|
||||
--scrollbar-track: var(--light-color);
|
||||
--scrollbar-thumb: var(--dark-color);
|
||||
}
|
||||
.super-light-background .compact-display-content {
|
||||
background-color: var(--super-light-color);
|
||||
}
|
||||
/* ====================== */
|
||||
/* == Light Background == */
|
||||
/* ====================== */
|
||||
.light-background #editorcontainerbox, .light-background #sidediv,
|
||||
.light-background #chatbox, .light-background #outerdocbody, .light-background {
|
||||
--text-color: var(--super-dark-color);
|
||||
--text-soft-color: var(--dark-color);
|
||||
--border-color: var(--middle-color);
|
||||
--bg-soft-color: var(--super-light-color);
|
||||
--bg-color: var(--light-color);
|
||||
}
|
||||
.light-background body, .full-width-editor.light-editor body:not(.comments-active) {
|
||||
--scrollbar-bg: var(--light-color);
|
||||
--scrollbar-track: var(--super-light-color);
|
||||
--scrollbar-thumb: var(--dark-color);
|
||||
}
|
||||
.light-background .compact-display-content {
|
||||
background-color: var(--light-color);
|
||||
}
|
||||
/* =========================== */
|
||||
/* == Super Dark Background == */
|
||||
/* =========================== */
|
||||
.super-dark-background #editorcontainerbox, .super-dark-background #sidediv,
|
||||
.super-dark-background #chatbox, .super-dark-background #outerdocbody, .super-dark-background {
|
||||
--text-color: var(--super-light-color);
|
||||
--text-soft-color: var(--light-color);
|
||||
--border-color: var(--dark-color);
|
||||
--bg-soft-color: var(--dark-color);
|
||||
--bg-color: var(--super-dark-color);
|
||||
}
|
||||
.super-dark-background body, .full-width-editor.super-dark-editor body:not(.comments-active) {
|
||||
--scrollbar-bg: var(--super-dark-color);
|
||||
--scrollbar-track: var(--dark-color);
|
||||
--scrollbar-thumb: var(--light-color);
|
||||
}
|
||||
.super-dark-background .compact-display-content {
|
||||
background-color: var(--super-dark-color);
|
||||
}
|
||||
/* Special combinaison with toolbar */
|
||||
.super-dark-background.super-dark-toolbar .popup-content {
|
||||
border: 1px solid var(--dark-color);
|
||||
box-shadow: none;
|
||||
}
|
||||
/* ===================== */
|
||||
/* == Dark Background == */
|
||||
/* ===================== */
|
||||
.dark-background #editorcontainerbox, .dark-background #sidediv,
|
||||
.dark-background #chatbox, .dark-background #outerdocbody, .dark-background {
|
||||
--text-color: var(--super-light-color);
|
||||
--text-soft-color: var(--light-color);
|
||||
--border-color: var(--super-dark-color);
|
||||
--bg-soft-color: var(--super-dark-color);
|
||||
--bg-color: var(--dark-color);
|
||||
}
|
||||
.dark-background body, .full-width-editor.dark-editor body:not(.comments-active) {
|
||||
--scrollbar-bg: var(--dark-color);
|
||||
--scrollbar-track: var(--super-dark-color);
|
||||
--scrollbar-thumb: var(--light-color);
|
||||
}
|
||||
.dark-background .compact-display-content {
|
||||
background-color: var(--dark-color);
|
||||
}
|
||||
/* Special combinaison with toolbar */
|
||||
.dark-background.dark-toolbar .popup-content, .dark-editor.dark-toolbar .popup-content {
|
||||
box-shadow: 0 0 14px 0px var(--super-dark-color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ======================== */
|
||||
/* == Super Light Editor == */
|
||||
/* ======================== */
|
||||
.super-light-editor #outerdocbody iframe, .super-light-editor #outerdocbody > #innerdocbody {
|
||||
--bg-color: var(--super-light-color);
|
||||
}
|
||||
.super-light-editor #innerdocbody {
|
||||
--text-color: var(--super-dark-color);
|
||||
}
|
||||
/* ================== */
|
||||
/* == Light Editor == */
|
||||
/* ================== */
|
||||
.light-editor #outerdocbody iframe, .light-editor #outerdocbody > #innerdocbody {
|
||||
--bg-color: var(--light-color);
|
||||
}
|
||||
.light-editor #innerdocbody {
|
||||
--text-color: var(--super-dark-color);
|
||||
}
|
||||
/* ======================= */
|
||||
/* == Super Dark Editor == */
|
||||
/* ======================= */
|
||||
.super-dark-editor #outerdocbody iframe, .super-dark-editor #outerdocbody > #innerdocbody {
|
||||
--bg-color: var(--super-dark-color);
|
||||
}
|
||||
.super-dark-editor #innerdocbody {
|
||||
--text-color: var(--super-light-color);
|
||||
}
|
||||
/* ================= */
|
||||
/* == Dark Editor == */
|
||||
/* ================= */
|
||||
.dark-editor #outerdocbody iframe, .dark-editor #outerdocbody > #innerdocbody {
|
||||
--bg-color: var(--dark-color);
|
||||
}
|
||||
.dark-editor #innerdocbody {
|
||||
--text-color: var(--super-light-color);
|
||||
}
|
||||
|
||||
|
||||
/* ======================================== */
|
||||
/* == Combinaison with background/editor == */
|
||||
/* ======================================== */
|
||||
.super-light-editor.super-light-background #outerdocbody,
|
||||
.light-editor.light-background #outerdocbody,
|
||||
.super-dark-editor.super-dark-background #outerdocbody,
|
||||
.dark-editor.dark-background #outerdocbody {
|
||||
padding-top: 0;
|
||||
}
|
||||
@media (min-width: 1001px) {
|
||||
.super-light-editor.super-light-background,
|
||||
.light-editor.light-background,
|
||||
.super-dark-editor.super-dark-background,
|
||||
.dark-editor.dark-background {
|
||||
--editor-horizontal-padding: 20px;
|
||||
--editor-vertical-padding: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================================== */
|
||||
/* == Combinaison with toolbar/editor == */
|
||||
/* ===================================== */
|
||||
.super-light-editor.super-light-toolbar .toolbar,
|
||||
.light-editor.light-toolbar .toolbar,
|
||||
.super-dark-editor.super-dark-toolbar .toolbar,
|
||||
.dark-editor.dark-toolbar .toolbar {
|
||||
--toolbar-border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
|
||||
/* ======================= */
|
||||
/* == Full Width Editor == */
|
||||
/* ======================= */
|
||||
.full-width-editor #outerdocbody iframe, .full-width-editor #outerdocbody > #innerdocbody {
|
||||
max-width: none !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
.full-width-editor #outerdocbody {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
@media (min-width: 1001px) {
|
||||
.full-width-editor {
|
||||
--editor-horizontal-padding: 20px !important;
|
||||
--editor-vertical-padding: 5px !important;
|
||||
}
|
||||
}
|
||||
.full-width-editor ::-webkit-scrollbar-track,
|
||||
.full-width-editor ::-webkit-scrollbar-thumb {
|
||||
border-radius: 0px;
|
||||
}
|
||||
10
src/static/skins/margin/src/plugins/author_hover.css
Normal file
10
src/static/skins/margin/src/plugins/author_hover.css
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
.authortooltip {
|
||||
opacity: 1!important;
|
||||
border-radius: 2px;
|
||||
padding: 4px 10px 3px!important;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px!important;
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
background-color: rgba(255, 255, 255, 0.85) !important;
|
||||
}
|
||||
14
src/static/skins/margin/src/plugins/brightcolorpicker.css
Normal file
14
src/static/skins/margin/src/plugins/brightcolorpicker.css
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#colorpicker a.brightColorPicker-cancelButton {
|
||||
background: none;
|
||||
padding: 0;
|
||||
padding-top: 10px;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.brightColorPicker-colorPanel {
|
||||
background-color: white !important;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08) !important;
|
||||
border-radius: 3px !important;
|
||||
padding: 15px !important;
|
||||
}
|
||||
112
src/static/skins/margin/src/plugins/comments.css
Normal file
112
src/static/skins/margin/src/plugins/comments.css
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
.sidebar-comment .btn {
|
||||
margin-top: 10px;
|
||||
padding: 3px 8px;
|
||||
font-size: .9rem;
|
||||
margin: 10px 0 5px 0;
|
||||
}
|
||||
.sidebar-comment .btn.btn-primary:not(#comment-create-btn) {
|
||||
background-color: #576273;
|
||||
background-color: var(--text-soft-color);
|
||||
}
|
||||
.sidebar-comment .suggestion-create {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.suggestion-display .from-value, .suggestion-display .to-value {
|
||||
color: #64d29b;
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
.suggestion-display .from-value {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.comment-actions-wrapper .buttonicon {
|
||||
opacity: .8;
|
||||
}
|
||||
.comment-actions-wrapper .buttonicon:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.comment-actions-wrapper .comment-edit {
|
||||
margin-right: 5px;
|
||||
}
|
||||
[type="checkbox"] + label.label-suggestion-checkbox {
|
||||
margin-left: 5px;
|
||||
padding-left: 2.4rem;
|
||||
}
|
||||
.sidebar-comment .full-display-content {
|
||||
margin-left: -10px;
|
||||
box-shadow: none;
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
border: 1px solid #ffffff;
|
||||
border: 1px solid var(--bg-color);
|
||||
}
|
||||
.comment-reply {
|
||||
border-top: 1px solid #ffffff;
|
||||
border-top: 1px solid var(--bg-color);
|
||||
background-color: inherit;
|
||||
}
|
||||
.comment-reply textarea, .comment-reply input[type="text"] {
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
.btn.revert-suggestion-btn {
|
||||
padding-left: 0;
|
||||
}
|
||||
.comment-edit-form {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* MODAL */
|
||||
.comment-modal .full-display-content {
|
||||
box-shadow: none;
|
||||
margin: 0 !important;
|
||||
border: none;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
.comment-modal .comment-modal-comment {
|
||||
padding: 0;
|
||||
}
|
||||
.comment-modal .comment-reply textarea, .comment-modal .comment-reply input[type="text"] {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
.comment-modal .comment-reply {
|
||||
border-top: 1px solid #f2f3f4;
|
||||
border-top: 1px solid var(--bg-soft-color);
|
||||
}
|
||||
.comment-modal .full-display-content .comment-title-wrapper,
|
||||
.comment-modal .full-display-content .comment-reply {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
|
||||
/* NEW COMMENT POPUP */
|
||||
.new-comment-popup textarea {
|
||||
background-color: #f2f3f4;
|
||||
background-color: var(--bg-soft-color);
|
||||
}
|
||||
.new-comment-popup .suggestion {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* EDITOR COMMENTEED LINE */
|
||||
#innerdocbody .ace-line .comment {
|
||||
background-color: #fffacc;
|
||||
color: var(--super-dark-color);
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
#comments {
|
||||
width: 300px;
|
||||
}
|
||||
.sidebar-comment .full-display-content {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.compact-display-content {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
41
src/static/skins/margin/src/plugins/font_color.css
Normal file
41
src/static/skins/margin/src/plugins/font_color.css
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
.font-color-icon {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#font-color {
|
||||
display: list-item !important;
|
||||
}
|
||||
.readonly #font-color {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.color\:black,
|
||||
[data-color=black] {
|
||||
color: #485365;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.color\:red,
|
||||
[data-color=red] {
|
||||
color: #F44336;
|
||||
}
|
||||
|
||||
.color\:green,
|
||||
[data-color=green] {
|
||||
color: #66d29c;
|
||||
}
|
||||
|
||||
.color\:blue,
|
||||
[data-color=blue] {
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.color\:yellow,
|
||||
[data-color=yellow] {
|
||||
color: #ffeb3b;
|
||||
}
|
||||
|
||||
.color\:orange,
|
||||
[data-color=orange] {
|
||||
color: #FF9800;
|
||||
}
|
||||
7
src/static/skins/margin/src/plugins/set_title_on_pad.css
Normal file
7
src/static/skins/margin/src/plugins/set_title_on_pad.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pad_title {
|
||||
border-bottom: 1px solid var(--border-color) !important;
|
||||
background-color: var(--bg-color) !important;
|
||||
}
|
||||
#edit_title {
|
||||
color: var(--text-soft-color);
|
||||
}
|
||||
239
src/static/skins/margin/src/plugins/tables2.css
Normal file
239
src/static/skins/margin/src/plugins/tables2.css
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/* MENU ICON*/
|
||||
#editbar #tbl_menu_list {
|
||||
width: auto !important;
|
||||
}
|
||||
#tbl-menu {
|
||||
background: none !important;
|
||||
width: 18px !important;
|
||||
padding-left: 2px !important;
|
||||
}
|
||||
#tbl-menu:before {
|
||||
content: "\F0CE";
|
||||
}
|
||||
|
||||
#tbl_menu_list > a {
|
||||
font-size: 16px;
|
||||
margin-top: 8px;
|
||||
padding-left: 0;
|
||||
padding-right: 2px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
/* DROP DOWN MENU */
|
||||
#tbl_context_menu {
|
||||
margin-left: -24px;
|
||||
border: none;
|
||||
margin-top: 9px;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
border-radius: 3px;
|
||||
background-color: white;
|
||||
font-size: 100%;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
#tbl_context_menu > .bd {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#tbl_context_menu > .bd > ul {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
/* TABLE SIZE PICKER */
|
||||
#tbl_insert {
|
||||
background-color: white;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#tbl_insert .bd {
|
||||
border: none;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
#tbl_insert .yuimenuitemlabel { text-align: center; }
|
||||
|
||||
#tbl_insert .ft {
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
padding: 6px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#matrix_table tr td {
|
||||
border: 1px solid #d7d7d7;
|
||||
height: 1px;
|
||||
padding: 7px;
|
||||
width: 11px;
|
||||
background-color: #fbfbfb;
|
||||
border-radius: 1px;
|
||||
}
|
||||
#matrix_table tr td.selected {
|
||||
border: 1px solid #789dce;
|
||||
background-color: #b3d4ff;
|
||||
}
|
||||
|
||||
/* TABLE SETTINGS POPUP */
|
||||
.yui-skin-sam .yui-panel-container {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 1px rgba(99, 114, 130, 0.16), 0 8px 16px rgba(27, 39, 51, 0.08);
|
||||
border-radius: 5px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-panel-container .yui-panel {
|
||||
border: none !important;
|
||||
background: none;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-panel-container .yui-panel .hd {
|
||||
cursor: move;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: 0;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
text-transform: uppercase;
|
||||
padding: 0 15px;
|
||||
padding-top: 5px;
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #d2d2d2;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-panel-container .yui-panel .container-close {
|
||||
top: 15px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: white;
|
||||
text-indent: 0;
|
||||
}
|
||||
.yui-skin-sam .yui-panel-container .yui-panel .container-close::before {
|
||||
content: "x";
|
||||
color: #6f757a;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-panel-container .yui-panel .bd {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 15px;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.yui-panel .underlay, .yui-skin-sam .yui-panel-container.shadow .underlay {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#div_tbl_btn_close {
|
||||
float: right;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#tbl_btn_close {
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#tbl_btn_close:hover { cursor: pointer; }
|
||||
|
||||
.yui-skin-sam .yui-button {
|
||||
background: none;
|
||||
background-color: white;
|
||||
border: none;
|
||||
height: 24px;
|
||||
margin-bottom: -4px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-button .first-child { margin: 0; border: none; }
|
||||
|
||||
.yui-skin-sam .yui-split-button button {
|
||||
padding: 0;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.yui-skin-sam .yui-split-button button em:not(.color-picker-button) {
|
||||
font-style: normal !important;
|
||||
border-bottom: 1px solid #b5b7b7;
|
||||
padding: 0 5px;
|
||||
margin: 0 5px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
button#yui-gen13-button {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
button .color-picker-button {
|
||||
border: 1px solid #c1c2c2;
|
||||
border-radius: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#even-row-bg-color, #single-row-bg-color {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#single-col-bg-color, #odd-row-bg-color {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
#yui-tbl-prop-panel .text-input[type=text] {
|
||||
border: 1px solid #d2d2d2;
|
||||
float: right;
|
||||
height: 10px;
|
||||
border-radius: 3px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
#text_input_message {
|
||||
background-color: #64d29b;
|
||||
padding: 0 5px;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* TABLES INSIDE THE PAD */
|
||||
td[name=tData] {
|
||||
/*border: 1px solid grey !important;*/
|
||||
}
|
||||
|
||||
#yui-picker-panel_c
|
||||
{
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
div#yui-picker-panel_h {
|
||||
line-height: 1.8em;
|
||||
font-size: 13px;
|
||||
padding: 9px 15px 5px;
|
||||
}
|
||||
|
||||
#yui-picker-panel .ft {
|
||||
position: relative;
|
||||
border: none;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
108
src/static/skins/margin/timeslider.css
Normal file
108
src/static/skins/margin/timeslider.css
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#timeslider-slider #ui-slider-handle {
|
||||
border-radius: 3px;
|
||||
width: 12px;
|
||||
height: 28px;
|
||||
background-color: #64d29b;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
#timeslider-slider #ui-slider-bar {
|
||||
border-radius: 3px;
|
||||
background-color: #d2d2d2;
|
||||
background-color: var(--border-color);
|
||||
}
|
||||
#slider-btn-container {
|
||||
margin: -18px 15px 0 20px;
|
||||
}
|
||||
#slider-btn-container #playpause_button_icon {
|
||||
color: #ffffff;
|
||||
color: var(--bg-color);
|
||||
background-color: #64d29b;
|
||||
background-color: var(--primary-color);
|
||||
border: none;
|
||||
margin-right: 5px;
|
||||
padding-top: 3px;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
#slider-btn-container #playpause_button_icon:not(.pause) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
#slider-btn-container .stepper {
|
||||
border: 2px solid !important;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
line-height: 28px;
|
||||
margin-left: 5px;
|
||||
font-size: 13px;
|
||||
color: #64d29b;
|
||||
color: var(--primary-color);
|
||||
border-color: #64d29b;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
#slider-btn-container .stepper.disabled {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.timeslider #editbar .buttontext {
|
||||
background-color: #576273;
|
||||
background-color: var(--text-soft-color);
|
||||
color: #ffffff;
|
||||
color: var(--bg-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#editbar {
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#editbar li > a {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#timeslider-slider #timer {
|
||||
opacity: .7;
|
||||
top: -12px;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.timeslider #authorsList .author {
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.timeslider-title {
|
||||
font-size: 1.8rem !important;
|
||||
}
|
||||
.timeslider-subtitle {
|
||||
margin-top: 6px;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.timeslider #outerdocbody > #sidediv {
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.timeslider #outerdocbody > #innerdocbody {
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
|
||||
#slider-btn-container {
|
||||
margin-top: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#slider-btn-container #playpause_button_icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
#slider-btn-container #playpause_button_icon:before {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
42
src/static/skins/margin/timeslider.js
Normal file
42
src/static/skins/margin/timeslider.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
'use strict';
|
||||
|
||||
// The timeslider page loads margin's pad.css, whose theme tokens live under
|
||||
// [data-theme="..."][data-mode="..."]. Without this bootstrap the history
|
||||
// view (and the in-place #history-frame iframe spun up by pad_mode.ts) would
|
||||
// render with no theme applied — visually broken vs the pad it came from.
|
||||
// Keep this list in sync with MARGIN_THEMES in pad.js.
|
||||
const MARGIN_THEME_VALUES = [
|
||||
'colibris', 'editorial', 'brutalist', 'paper', 'crt', 'industrial',
|
||||
];
|
||||
const MARGIN_THEME_DEFAULT = 'colibris';
|
||||
const MARGIN_MODE_DEFAULTS = {
|
||||
colibris: 'light', editorial: 'light', brutalist: 'light',
|
||||
paper: 'light', crt: 'dark', industrial: 'dark',
|
||||
};
|
||||
|
||||
const readStorage = (key) => {
|
||||
try { return localStorage.getItem(key); } catch (_) { return null; }
|
||||
};
|
||||
|
||||
// When opened as the in-place history iframe (#history-frame) prefer the
|
||||
// parent doc's live attribute over localStorage — that way history mirrors
|
||||
// whatever the pad currently shows even if the user toggled theme after
|
||||
// localStorage was last written.
|
||||
const readFromParent = (attr) => {
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
return window.parent.document.documentElement.getAttribute(attr);
|
||||
}
|
||||
} catch (_) { /* cross-origin — ignore */ }
|
||||
return null;
|
||||
};
|
||||
|
||||
let theme = readFromParent('data-theme') || readStorage('marginTheme');
|
||||
if (!MARGIN_THEME_VALUES.includes(theme)) theme = MARGIN_THEME_DEFAULT;
|
||||
let mode = readFromParent('data-mode') || readStorage('marginMode');
|
||||
if (mode !== 'light' && mode !== 'dark') mode = MARGIN_MODE_DEFAULTS[theme] || 'light';
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
document.documentElement.setAttribute('data-mode', mode);
|
||||
|
||||
window.customStart = () => {
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue