@open-press/core 1.1.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/engine/cli.mjs +3 -3
- package/engine/commands/_shared.mjs +89 -13
- package/engine/commands/deploy.mjs +19 -4
- package/engine/commands/image.mjs +9 -3
- package/engine/commands/pdf.mjs +4 -1
- package/engine/output/chrome-pdf.mjs +102 -0
- package/engine/output/static-server.mjs +64 -17
- package/engine/react/document-export.mjs +22 -0
- package/package.json +1 -1
- package/src/openpress/app/OpenPressApp.tsx +5 -1
- package/src/openpress/app/OpenPressRuntime.tsx +85 -6
- package/src/openpress/reader/PageThumbnailsPanel.tsx +28 -5
- package/src/openpress/reader/PublicReaderPage.tsx +163 -74
- package/src/openpress/reader/SlidePresentationPage.tsx +37 -15
- package/src/openpress/reader/SlidePublicPage.tsx +332 -0
- package/src/openpress/reader/index.ts +1 -0
- package/src/openpress/reader/pageViewportScaleModel.ts +5 -3
- package/src/openpress/reader/usePageViewportScale.ts +9 -5
- package/src/openpress/reader/usePanelState.ts +14 -5
- package/src/openpress/shared/index.ts +1 -0
- package/src/openpress/shared/staticSearch.ts +174 -0
- package/src/openpress/workbench/Workbench.tsx +61 -176
- package/src/openpress/workbench/actions/DeploymentControl.tsx +1 -1
- package/src/openpress/workbench/actions/ExportControl.tsx +267 -0
- package/src/openpress/workbench/actions/SearchControl.tsx +32 -43
- package/src/openpress/workbench/actions/index.ts +1 -1
- package/src/openpress/workbench/actions/useDeploymentWorkbench.ts +21 -5
- package/src/openpress/workbench/hooks/useWorkbenchNavigation.ts +42 -0
- package/src/openpress/workbench/inspector/useInspectorComments.ts +6 -6
- package/src/openpress/workbench/project/ProjectEntryPanel.tsx +2 -278
- package/src/openpress/workbench/shell/WorkbenchShell.tsx +44 -18
- package/src/openpress/workbench/shell/WorkbenchToolbarActions.tsx +206 -0
- package/src/styles/openpress/app-shell.css +0 -83
- package/src/styles/openpress/print-route.css +1 -3
- package/src/styles/openpress/project-preview-panel.css +5 -783
- package/src/styles/openpress/public-viewer.css +7 -249
- package/src/styles/openpress/reader-runtime.css +0 -274
- package/src/styles/openpress/slide-presenter.css +150 -0
- package/src/styles/openpress/slide-public-viewer.css +222 -0
- package/src/styles/openpress/workbench-dialog.css +267 -0
- package/src/styles/openpress/workbench-export.css +154 -0
- package/src/styles/openpress/workbench-inline-editor.css +128 -0
- package/src/styles/openpress/workbench-panels.css +0 -88
- package/src/styles/openpress/workbench-search.css +257 -0
- package/src/styles/openpress/workbench-toolbar.css +422 -0
- package/src/styles/openpress/workbench.css +34 -1263
- package/src/styles/openpress/workspace-gallery.css +0 -5
- package/src/styles/openpress.css +7 -1
- package/vite.config.ts +66 -17
- package/src/openpress/workbench/actions/ExportImageControl.tsx +0 -96
- package/src/styles/openpress/media-workspace.css +0 -230
|
@@ -262,11 +262,6 @@
|
|
|
262
262
|
white-space: nowrap;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
.openpress-workspace-gallery__dot {
|
|
266
|
-
color: color-mix(in srgb, var(--workspace-card-muted) 55%, transparent);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.openpress-workspace-gallery__pages,
|
|
270
265
|
.openpress-workspace-gallery__geom {
|
|
271
266
|
color: var(--workspace-card-muted);
|
|
272
267
|
}
|
package/src/styles/openpress.css
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
@import "./openpress/app-shell.css";
|
|
2
2
|
@import "./openpress/workspace-gallery.css";
|
|
3
3
|
@import "./openpress/workbench.css";
|
|
4
|
+
@import "./openpress/slide-presenter.css";
|
|
5
|
+
@import "./openpress/workbench-toolbar.css";
|
|
6
|
+
@import "./openpress/slide-public-viewer.css";
|
|
7
|
+
@import "./openpress/workbench-inline-editor.css";
|
|
8
|
+
@import "./openpress/workbench-dialog.css";
|
|
9
|
+
@import "./openpress/workbench-search.css";
|
|
10
|
+
@import "./openpress/workbench-export.css";
|
|
4
11
|
@import "./openpress/workbench-panels.css";
|
|
5
12
|
@import "./openpress/project-preview-panel.css";
|
|
6
|
-
@import "./openpress/media-workspace.css";
|
|
7
13
|
@import "./openpress/reader-runtime.css";
|
|
8
14
|
@import "./openpress/public-viewer.css";
|
|
9
15
|
@import "./openpress/responsive.css";
|
package/vite.config.ts
CHANGED
|
@@ -233,13 +233,18 @@ async function handleLocalPdfExportRequest(req: IncomingMessage, res: ServerResp
|
|
|
233
233
|
return;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
const
|
|
237
|
-
const
|
|
236
|
+
const body = await readJsonRequestBody(req);
|
|
237
|
+
const slug = normalizePressSlug(body?.press);
|
|
238
|
+
const result = await runLocalPdfExport(slug);
|
|
239
|
+
const pdfPath = pressPdfAbsolutePath(slug);
|
|
240
|
+
const exists = await fileExists(pdfPath);
|
|
241
|
+
const cliArgs = slug ? ["pdf", ".", "--press", slug] : ["pdf", "."];
|
|
242
|
+
const pdfUrl = `/__openpress/local-pdf-file?${slug ? `press=${encodeURIComponent(slug)}&` : ""}ts=${Date.now()}`;
|
|
238
243
|
writeJson(res, result.code === 0 && exists ? 200 : 500, {
|
|
239
244
|
ok: result.code === 0 && exists,
|
|
240
245
|
code: result.code,
|
|
241
|
-
pdf:
|
|
242
|
-
command: openpressCliCommand(
|
|
246
|
+
pdf: pdfUrl,
|
|
247
|
+
command: openpressCliCommand(cliArgs),
|
|
243
248
|
stdout: result.stdout,
|
|
244
249
|
stderr: result.stderr,
|
|
245
250
|
});
|
|
@@ -251,11 +256,15 @@ async function handleLocalPdfFileRequest(req: IncomingMessage, res: ServerRespon
|
|
|
251
256
|
return;
|
|
252
257
|
}
|
|
253
258
|
|
|
259
|
+
const requestUrl = new URL(req.url ?? "/", "http://localhost");
|
|
260
|
+
const slug = normalizePressSlug(requestUrl.searchParams.get("press"));
|
|
261
|
+
const pdfPath = pressPdfAbsolutePath(slug);
|
|
262
|
+
const filename = pressFilename(openpressConfig.pdf.filename, slug);
|
|
254
263
|
try {
|
|
255
|
-
const body = await fs.readFile(
|
|
264
|
+
const body = await fs.readFile(pdfPath);
|
|
256
265
|
res.writeHead(200, {
|
|
257
266
|
"Content-Type": "application/pdf",
|
|
258
|
-
"Content-Disposition": `inline; filename="${
|
|
267
|
+
"Content-Disposition": `inline; filename="${filename}"`,
|
|
259
268
|
"Cache-Control": "no-store",
|
|
260
269
|
});
|
|
261
270
|
res.end(body);
|
|
@@ -264,6 +273,37 @@ async function handleLocalPdfFileRequest(req: IncomingMessage, res: ServerRespon
|
|
|
264
273
|
}
|
|
265
274
|
}
|
|
266
275
|
|
|
276
|
+
function normalizePressSlug(value: unknown): string {
|
|
277
|
+
if (typeof value !== "string") return "";
|
|
278
|
+
return value.trim().replace(/^\/+|\/+$/g, "");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function pressFilename(baseFilename: string, slug: string): string {
|
|
282
|
+
if (!slug) return baseFilename;
|
|
283
|
+
const ext = path.extname(baseFilename);
|
|
284
|
+
const stem = ext ? baseFilename.slice(0, -ext.length) : baseFilename;
|
|
285
|
+
return `${stem}-${slug}${ext}`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function pressPdfAbsolutePath(slug: string): string {
|
|
289
|
+
return path.join(openpressConfig.outputDir, pressFilename(openpressConfig.pdf.filename, slug));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function readJsonRequestBody(req: IncomingMessage): Promise<{ press?: unknown } | null> {
|
|
293
|
+
try {
|
|
294
|
+
const chunks: Buffer[] = [];
|
|
295
|
+
for await (const chunk of req) {
|
|
296
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : (chunk as Buffer));
|
|
297
|
+
}
|
|
298
|
+
if (chunks.length === 0) return null;
|
|
299
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
300
|
+
if (!text.trim()) return null;
|
|
301
|
+
return JSON.parse(text);
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
267
307
|
async function handleLocalStatusRequest(req: IncomingMessage, res: ServerResponse) {
|
|
268
308
|
if (req.method !== "GET") {
|
|
269
309
|
writeJson(res, 405, { ok: false, message: "Status endpoint requires GET." });
|
|
@@ -321,6 +361,11 @@ async function handleLocalDeployRequest(req: IncomingMessage, res: ServerRespons
|
|
|
321
361
|
return;
|
|
322
362
|
}
|
|
323
363
|
|
|
364
|
+
const body = await readJsonRequestBody(req);
|
|
365
|
+
const slug = normalizePressSlug(body?.press);
|
|
366
|
+
const cliArgs = slug ? ["deploy", ".", "--confirm", "--press", slug] : ["deploy", ".", "--confirm"];
|
|
367
|
+
const pdfFilename = pressFilename(openpressConfig.pdf.filename, slug);
|
|
368
|
+
|
|
324
369
|
if (!isLocalDeployConfigured()) {
|
|
325
370
|
writeJson(res, 400, {
|
|
326
371
|
ok: false,
|
|
@@ -330,15 +375,15 @@ async function handleLocalDeployRequest(req: IncomingMessage, res: ServerRespons
|
|
|
330
375
|
deploy_adapter: openpressConfig.deploy.adapter,
|
|
331
376
|
deploy_source: openpressConfig.deploy.source,
|
|
332
377
|
deploy_project_name: openpressConfig.deploy.projectName,
|
|
333
|
-
command: openpressCliCommand(
|
|
378
|
+
command: openpressCliCommand(cliArgs),
|
|
334
379
|
});
|
|
335
380
|
return;
|
|
336
381
|
}
|
|
337
382
|
|
|
338
|
-
const result = await runLocalDeploy();
|
|
383
|
+
const result = await runLocalDeploy(slug);
|
|
339
384
|
const deployedUrl = extractDeployUrl(result.stdout);
|
|
340
385
|
if (result.code === 0 && deployedUrl) {
|
|
341
|
-
await writeLocalDeploymentPublicUrl(deployedUrl);
|
|
386
|
+
await writeLocalDeploymentPublicUrl(deployedUrl, pdfFilename);
|
|
342
387
|
}
|
|
343
388
|
const deploymentInfo = await readLocalDeploymentInfo();
|
|
344
389
|
const publicUrl = deployedUrl ?? deploymentInfo.public_url;
|
|
@@ -346,18 +391,20 @@ async function handleLocalDeployRequest(req: IncomingMessage, res: ServerRespons
|
|
|
346
391
|
ok: result.code === 0,
|
|
347
392
|
code: result.code,
|
|
348
393
|
deployed_at: deploymentInfo.deployed_at,
|
|
349
|
-
pdf: deployedUrl ? `${deployedUrl}/${
|
|
394
|
+
pdf: deployedUrl ? `${deployedUrl}/${pdfFilename}` : deploymentInfo.pdf,
|
|
350
395
|
public_url: publicUrl,
|
|
351
396
|
dirty: false,
|
|
352
|
-
command: openpressCliCommand(
|
|
397
|
+
command: openpressCliCommand(cliArgs),
|
|
353
398
|
stdout: result.stdout,
|
|
354
399
|
stderr: result.stderr,
|
|
355
400
|
});
|
|
356
401
|
}
|
|
357
402
|
|
|
358
|
-
function runLocalPdfExport() {
|
|
403
|
+
function runLocalPdfExport(slug = "") {
|
|
404
|
+
const args = [openpressCliPath, "pdf", "."];
|
|
405
|
+
if (slug) args.push("--press", slug);
|
|
359
406
|
return new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
|
|
360
|
-
const child = spawn("node",
|
|
407
|
+
const child = spawn("node", args, {
|
|
361
408
|
cwd: workspaceRoot,
|
|
362
409
|
shell: false,
|
|
363
410
|
});
|
|
@@ -378,9 +425,11 @@ function runLocalPdfExport() {
|
|
|
378
425
|
});
|
|
379
426
|
}
|
|
380
427
|
|
|
381
|
-
function runLocalDeploy() {
|
|
428
|
+
function runLocalDeploy(slug = "") {
|
|
429
|
+
const args = [openpressCliPath, "deploy", ".", "--confirm"];
|
|
430
|
+
if (slug) args.push("--press", slug);
|
|
382
431
|
return new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
|
|
383
|
-
const child = spawn("node",
|
|
432
|
+
const child = spawn("node", args, {
|
|
384
433
|
cwd: workspaceRoot,
|
|
385
434
|
shell: false,
|
|
386
435
|
});
|
|
@@ -443,7 +492,7 @@ async function readLocalDeploymentInfo() {
|
|
|
443
492
|
}
|
|
444
493
|
}
|
|
445
494
|
|
|
446
|
-
async function writeLocalDeploymentPublicUrl(publicUrl: string) {
|
|
495
|
+
async function writeLocalDeploymentPublicUrl(publicUrl: string, pdfFilename = openpressConfig.pdf.filename) {
|
|
447
496
|
let deployConfig: Record<string, unknown> = {};
|
|
448
497
|
try {
|
|
449
498
|
deployConfig = JSON.parse(await fs.readFile(openpressConfig.paths.deployMetadata, "utf8")) as Record<string, unknown>;
|
|
@@ -453,7 +502,7 @@ async function writeLocalDeploymentPublicUrl(publicUrl: string) {
|
|
|
453
502
|
await fs.mkdir(path.dirname(openpressConfig.paths.deployMetadata), { recursive: true });
|
|
454
503
|
await fs.writeFile(
|
|
455
504
|
openpressConfig.paths.deployMetadata,
|
|
456
|
-
`${JSON.stringify({ ...deployConfig, pdf: `${publicUrl}/${
|
|
505
|
+
`${JSON.stringify({ ...deployConfig, pdf: `${publicUrl}/${pdfFilename}`, public_url: publicUrl }, null, 2)}\n`,
|
|
457
506
|
"utf8",
|
|
458
507
|
);
|
|
459
508
|
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { useCallback, useState } from "react";
|
|
2
|
-
import { Camera } from "lucide-react";
|
|
3
|
-
import { toPng } from "html-to-image";
|
|
4
|
-
|
|
5
|
-
type ExportStatus = "idle" | "exporting" | "done" | "error";
|
|
6
|
-
|
|
7
|
-
// Exports the currently visible page as a PNG. Locates the page DOM via
|
|
8
|
-
// the data-openpress-page-index attribute (set in PublicReaderPage) and
|
|
9
|
-
// hands it to html-to-image, then triggers a browser download.
|
|
10
|
-
//
|
|
11
|
-
// Lives in the workbench toolbar so it's reachable for any Press shape
|
|
12
|
-
// (manuscript / canvas / slide); for multi-page Press the user navigates
|
|
13
|
-
// to the page first, then exports.
|
|
14
|
-
export function ExportImageControl({
|
|
15
|
-
currentPageIndex,
|
|
16
|
-
currentPageLabel,
|
|
17
|
-
pressTitle,
|
|
18
|
-
}: {
|
|
19
|
-
currentPageIndex: number;
|
|
20
|
-
currentPageLabel: string;
|
|
21
|
-
pressTitle: string;
|
|
22
|
-
}) {
|
|
23
|
-
const [status, setStatus] = useState<ExportStatus>("idle");
|
|
24
|
-
|
|
25
|
-
const handleExport = useCallback(async () => {
|
|
26
|
-
if (status === "exporting") return;
|
|
27
|
-
setStatus("exporting");
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
const pageEl = typeof window === "undefined"
|
|
31
|
-
? null
|
|
32
|
-
: window.document.querySelector<HTMLElement>(
|
|
33
|
-
`[data-openpress-page-index="${currentPageIndex}"]`,
|
|
34
|
-
);
|
|
35
|
-
if (!pageEl) throw new Error("找不到目前頁面");
|
|
36
|
-
|
|
37
|
-
// pixelRatio: 2 — retina-ish; keeps text crisp without blowing the file size.
|
|
38
|
-
// cacheBust: true — force re-fetch of images so stale CORS doesn't taint the canvas.
|
|
39
|
-
const dataUrl = await toPng(pageEl, {
|
|
40
|
-
pixelRatio: 2,
|
|
41
|
-
cacheBust: true,
|
|
42
|
-
backgroundColor: "#ffffff",
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const safeTitle = sanitizeFilename(pressTitle) || "openpress";
|
|
46
|
-
const safePage = sanitizeFilename(currentPageLabel) || String(currentPageIndex + 1);
|
|
47
|
-
const link = window.document.createElement("a");
|
|
48
|
-
link.href = dataUrl;
|
|
49
|
-
link.download = `${safeTitle}-${safePage}.png`;
|
|
50
|
-
window.document.body.appendChild(link);
|
|
51
|
-
link.click();
|
|
52
|
-
link.remove();
|
|
53
|
-
|
|
54
|
-
setStatus("done");
|
|
55
|
-
window.setTimeout(() => setStatus("idle"), 1600);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.error("[openpress] page PNG export failed", error);
|
|
58
|
-
setStatus("error");
|
|
59
|
-
window.setTimeout(() => setStatus("idle"), 2400);
|
|
60
|
-
}
|
|
61
|
-
}, [currentPageIndex, currentPageLabel, pressTitle, status]);
|
|
62
|
-
|
|
63
|
-
const label = status === "exporting"
|
|
64
|
-
? "匯出中…"
|
|
65
|
-
: status === "done"
|
|
66
|
-
? "已下載"
|
|
67
|
-
: status === "error"
|
|
68
|
-
? "匯出失敗"
|
|
69
|
-
: "PNG";
|
|
70
|
-
const title = "將目前頁面匯出為 PNG";
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<button
|
|
74
|
-
type="button"
|
|
75
|
-
className="openpress-workbench-toolbar-action"
|
|
76
|
-
data-openpress-page-png-export
|
|
77
|
-
data-openpress-export-status={status}
|
|
78
|
-
disabled={status === "exporting"}
|
|
79
|
-
onClick={handleExport}
|
|
80
|
-
title={title}
|
|
81
|
-
aria-label={title}
|
|
82
|
-
>
|
|
83
|
-
<Camera aria-hidden="true" />
|
|
84
|
-
<span className="openpress-workbench-toolbar-action__label">{label}</span>
|
|
85
|
-
</button>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function sanitizeFilename(value: string): string {
|
|
90
|
-
return value
|
|
91
|
-
.replace(/[\\/:*?"<>|]+/g, "-")
|
|
92
|
-
.replace(/\s+/g, "-")
|
|
93
|
-
.replace(/-+/g, "-")
|
|
94
|
-
.replace(/^-+|-+$/g, "")
|
|
95
|
-
.slice(0, 80);
|
|
96
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
.openpress-media-assets {
|
|
2
|
-
display: grid;
|
|
3
|
-
grid-template-rows: auto minmax(120px, 1fr) auto auto auto;
|
|
4
|
-
min-height: 0;
|
|
5
|
-
overflow: hidden;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.openpress-media-workspace-page {
|
|
9
|
-
position: absolute;
|
|
10
|
-
inset: 0;
|
|
11
|
-
z-index: 8;
|
|
12
|
-
padding: 28px clamp(24px, 4vw, 48px) 40px;
|
|
13
|
-
background: #141414;
|
|
14
|
-
color: #dfe1dd;
|
|
15
|
-
overflow: auto;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.openpress-media-workspace-header {
|
|
19
|
-
display: flex;
|
|
20
|
-
gap: 18px;
|
|
21
|
-
align-items: start;
|
|
22
|
-
justify-content: space-between;
|
|
23
|
-
border-bottom: 1px solid rgb(255 255 255 / 9%);
|
|
24
|
-
padding-bottom: 18px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.openpress-media-workspace-header .openpress-panel-heading {
|
|
28
|
-
padding: 0 0 8px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.openpress-media-workspace-header h2 {
|
|
32
|
-
margin: 0;
|
|
33
|
-
color: #f2f2f0;
|
|
34
|
-
font-size: 22px;
|
|
35
|
-
font-weight: 500;
|
|
36
|
-
line-height: 1.2;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.openpress-media-workspace-header p {
|
|
40
|
-
margin: 8px 0 0;
|
|
41
|
-
color: #858c93;
|
|
42
|
-
font-size: 12px;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.openpress-media-workspace-back {
|
|
46
|
-
flex: 0 0 auto;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.openpress-media-asset-list {
|
|
50
|
-
display: grid;
|
|
51
|
-
min-height: 0;
|
|
52
|
-
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
53
|
-
gap: 10px;
|
|
54
|
-
overflow: auto;
|
|
55
|
-
padding: 18px 0;
|
|
56
|
-
scrollbar-width: none;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.openpress-media-asset-list::-webkit-scrollbar {
|
|
60
|
-
width: 0;
|
|
61
|
-
height: 0;
|
|
62
|
-
display: none;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.openpress-media-asset {
|
|
66
|
-
display: grid;
|
|
67
|
-
grid-template-columns: 54px minmax(0, 1fr);
|
|
68
|
-
gap: 12px;
|
|
69
|
-
align-items: center;
|
|
70
|
-
min-height: 66px;
|
|
71
|
-
border: 1px solid rgb(255 255 255 / 9%);
|
|
72
|
-
padding: 10px;
|
|
73
|
-
background: rgb(255 255 255 / 3%);
|
|
74
|
-
color: #a2a8ae;
|
|
75
|
-
text-decoration: none;
|
|
76
|
-
transition:
|
|
77
|
-
border-color 160ms ease,
|
|
78
|
-
background 160ms ease,
|
|
79
|
-
color 160ms ease;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.openpress-media-asset:hover {
|
|
83
|
-
border-color: rgb(255 255 255 / 18%);
|
|
84
|
-
background: rgb(255 255 255 / 6%);
|
|
85
|
-
color: #f3f3ef;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.openpress-media-asset__thumb {
|
|
89
|
-
display: grid;
|
|
90
|
-
width: 54px;
|
|
91
|
-
height: 54px;
|
|
92
|
-
place-items: center;
|
|
93
|
-
overflow: hidden;
|
|
94
|
-
border: 1px solid rgb(255 255 255 / 10%);
|
|
95
|
-
background: #101010;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.openpress-media-asset__thumb img {
|
|
99
|
-
display: block;
|
|
100
|
-
width: 100%;
|
|
101
|
-
height: 100%;
|
|
102
|
-
object-fit: cover;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.openpress-media-asset--svg .openpress-media-asset__thumb img {
|
|
106
|
-
object-fit: contain;
|
|
107
|
-
padding: 5px;
|
|
108
|
-
background: #f4f4f0;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.openpress-media-asset__meta {
|
|
112
|
-
min-width: 0;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.openpress-media-asset__meta strong {
|
|
116
|
-
display: block;
|
|
117
|
-
overflow: hidden;
|
|
118
|
-
color: #e2e4e1;
|
|
119
|
-
font-size: 12px;
|
|
120
|
-
font-weight: 500;
|
|
121
|
-
line-height: 1.2;
|
|
122
|
-
text-overflow: ellipsis;
|
|
123
|
-
white-space: nowrap;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.openpress-media-asset__meta small {
|
|
127
|
-
display: block;
|
|
128
|
-
overflow: hidden;
|
|
129
|
-
margin-top: 4px;
|
|
130
|
-
color: #6b7178;
|
|
131
|
-
font-size: 10px;
|
|
132
|
-
line-height: 1.2;
|
|
133
|
-
text-overflow: ellipsis;
|
|
134
|
-
white-space: nowrap;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.openpress-media-dropzone {
|
|
138
|
-
display: grid;
|
|
139
|
-
gap: 7px;
|
|
140
|
-
margin: 0 0 14px;
|
|
141
|
-
border: 1px dashed rgb(255 255 255 / 18%);
|
|
142
|
-
padding: 12px;
|
|
143
|
-
background: rgb(255 255 255 / 2%);
|
|
144
|
-
color: #7f868d;
|
|
145
|
-
font-size: 11px;
|
|
146
|
-
line-height: 1.45;
|
|
147
|
-
transition:
|
|
148
|
-
border-color 160ms ease,
|
|
149
|
-
background 160ms ease,
|
|
150
|
-
color 160ms ease;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.openpress-media-dropzone[data-drag-active="true"] {
|
|
154
|
-
border-color: rgb(223 75 33 / 70%);
|
|
155
|
-
background: rgb(223 75 33 / 9%);
|
|
156
|
-
color: #ece7df;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.openpress-media-dropzone__action,
|
|
160
|
-
.openpress-staged-asset button {
|
|
161
|
-
width: fit-content;
|
|
162
|
-
border: 1px solid rgb(255 255 255 / 14%);
|
|
163
|
-
padding: 6px 9px;
|
|
164
|
-
background: rgb(255 255 255 / 4%);
|
|
165
|
-
color: #ececea;
|
|
166
|
-
font: inherit;
|
|
167
|
-
font-size: 11px;
|
|
168
|
-
cursor: pointer;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.openpress-media-dropzone__action:hover,
|
|
172
|
-
.openpress-staged-asset button:hover {
|
|
173
|
-
border-color: rgb(255 255 255 / 24%);
|
|
174
|
-
background: rgb(255 255 255 / 8%);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.openpress-staged-assets {
|
|
178
|
-
display: grid;
|
|
179
|
-
max-height: 180px;
|
|
180
|
-
gap: 8px;
|
|
181
|
-
overflow: auto;
|
|
182
|
-
padding: 0 0 12px;
|
|
183
|
-
scrollbar-width: none;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.openpress-staged-asset {
|
|
187
|
-
display: grid;
|
|
188
|
-
grid-template-columns: 34px minmax(0, 1fr) auto;
|
|
189
|
-
gap: 9px;
|
|
190
|
-
align-items: center;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.openpress-staged-asset img {
|
|
194
|
-
width: 34px;
|
|
195
|
-
height: 34px;
|
|
196
|
-
object-fit: cover;
|
|
197
|
-
border: 1px solid rgb(255 255 255 / 10%);
|
|
198
|
-
background: #111;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.openpress-staged-asset span {
|
|
202
|
-
min-width: 0;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.openpress-staged-asset strong,
|
|
206
|
-
.openpress-staged-asset small {
|
|
207
|
-
display: block;
|
|
208
|
-
overflow: hidden;
|
|
209
|
-
text-overflow: ellipsis;
|
|
210
|
-
white-space: nowrap;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.openpress-staged-asset strong {
|
|
214
|
-
color: #dedfdd;
|
|
215
|
-
font-size: 11px;
|
|
216
|
-
font-weight: 500;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.openpress-staged-asset small {
|
|
220
|
-
margin-top: 3px;
|
|
221
|
-
color: #70767d;
|
|
222
|
-
font-size: 10px;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
body::-webkit-scrollbar,
|
|
226
|
-
html::-webkit-scrollbar {
|
|
227
|
-
width: 0;
|
|
228
|
-
height: 0;
|
|
229
|
-
display: none;
|
|
230
|
-
}
|