diff --git a/modules/rpubs/components/folk-pubs-editor.ts b/modules/rpubs/components/folk-pubs-editor.ts index 61495b5..3274454 100644 --- a/modules/rpubs/components/folk-pubs-editor.ts +++ b/modules/rpubs/components/folk-pubs-editor.ts @@ -64,6 +64,14 @@ These ideas matter because they challenge the assumption that only private owner const SYNC_DEBOUNCE_MS = 800; +// ── SVG Icons ── +const SVG_CHECK = ``; +const SVG_ARROW_RIGHT = ``; +const SVG_ARROW_LEFT = ``; +const SVG_EXPAND = ``; +const SVG_DOWNLOAD = ``; +const SVG_SPINNER = ``; + export class FolkPubsEditor extends HTMLElement { private _formats: BookFormat[] = []; private _spaceSlug = "personal"; @@ -451,18 +459,18 @@ export class FolkPubsEditor extends HTMLElement {
-
-
@@ -499,7 +507,9 @@ export class FolkPubsEditor extends HTMLElement {
${this._error ? `
${this.escapeHtml(this._error)}
` : ''} @@ -507,19 +517,22 @@ export class FolkPubsEditor extends HTMLElement { } private renderPreviewStep(): string { + const currentFormat = this._formats.find(f => f.id === this._selectedFormat); + const dims = currentFormat ? `${currentFormat.widthMm}\u00D7${currentFormat.heightMm}mm` : ''; return `
- - - Download PDF + + + ${SVG_DOWNLOAD} Download + ${currentFormat ? `${this.escapeHtml(currentFormat.name)} \u00B7 ${dims}` : ''}
${this._pdfInfo || ''} - +
`; @@ -942,7 +955,7 @@ export class FolkPubsEditor extends HTMLElement { display: flex; justify-content: space-between; align-items: center; - padding: 0.5rem 1rem; + padding: 0.625rem 1rem; border-bottom: 1px solid var(--rs-border-subtle); background: var(--rs-bg-surface); } @@ -956,39 +969,56 @@ export class FolkPubsEditor extends HTMLElement { .step { display: inline-flex; align-items: center; - gap: 0.375rem; - padding: 0.35rem 0.75rem; - border: 1px solid var(--rs-border); - border-radius: 2rem; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + border: none; + border-radius: 0; background: transparent; color: var(--rs-text-muted); font-size: 0.78rem; cursor: pointer; transition: all 0.15s; } - .step:disabled { cursor: not-allowed; opacity: 0.4; } - .step:not(:disabled):hover { border-color: var(--rs-primary); color: var(--rs-text-primary); } - .step.active { - background: var(--rs-primary); - border-color: var(--rs-primary); + .step:disabled { cursor: not-allowed; opacity: 0.35; } + .step:not(:disabled):hover { color: var(--rs-text-primary); } + .step:not(:disabled):hover .step-circle { border-color: var(--rs-accent, #14b8a6); } + .step.active .step-circle { + background: var(--rs-accent, #14b8a6); + border-color: var(--rs-accent, #14b8a6); color: #fff; - font-weight: 600; } - .step.completed:not(.active) { - border-color: var(--rs-success, #22c55e); - color: var(--rs-success, #22c55e); + .step.active { color: var(--rs-text-primary); font-weight: 600; } + .step.done .step-circle { + background: var(--rs-accent, #14b8a6); + border-color: var(--rs-accent, #14b8a6); + color: #fff; } + .step.done { color: var(--rs-accent, #14b8a6); } - .step-num { font-weight: 700; font-size: 0.75rem; } + .step-circle { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid var(--rs-border, #444); + background: transparent; + color: var(--rs-text-muted); + font-size: 0.75rem; + font-weight: 700; + transition: all 0.15s; + flex-shrink: 0; + } .step-line { - width: 24px; + width: 32px; height: 2px; background: var(--rs-border); - margin: 0 0.25rem; + margin: 0 0.125rem; transition: background 0.15s; } - .step-line.filled { background: var(--rs-primary); } + .step-line.filled { background: var(--rs-accent, #14b8a6); } .step-info { font-size: 0.75rem; @@ -1052,8 +1082,8 @@ export class FolkPubsEditor extends HTMLElement { .format-badge { padding: 0.15rem 0.5rem; border-radius: 1rem; - background: rgba(59, 130, 246, 0.1); - color: var(--rs-primary); + background: rgba(20, 184, 166, 0.1); + color: var(--rs-accent, #14b8a6); font-size: 0.65rem; font-weight: 500; } @@ -1067,17 +1097,30 @@ export class FolkPubsEditor extends HTMLElement { padding: 0.5rem 1.25rem; border: none; border-radius: 0.5rem; - background: var(--rs-primary); + background: var(--rs-accent, #14b8a6); color: #fff; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: background 0.15s; white-space: nowrap; + display: inline-flex; + align-items: center; + gap: 0.375rem; } - .btn-generate:hover { background: var(--rs-primary-hover); } + .btn-generate:hover { background: var(--rs-accent-hover, #0d9488); } .btn-generate:disabled { opacity: 0.5; cursor: not-allowed; } + .btn-spinner { + display: inline-block; + width: 14px; height: 14px; + border: 2px solid rgba(255,255,255,0.3); + border-top-color: #fff; + border-radius: 50%; + animation: btn-spin 0.6s linear infinite; + } + @keyframes btn-spin { to { transform: rotate(360deg); } } + /* ── Preview step ── */ .preview-step { @@ -1105,8 +1148,21 @@ export class FolkPubsEditor extends HTMLElement { text-decoration: none; display: inline-flex; align-items: center; + gap: 0.375rem; + } + .action-btn:hover { border-color: var(--rs-accent, #14b8a6); color: var(--rs-text-primary); } + .action-btn:hover svg { color: var(--rs-accent, #14b8a6); } + + .format-chip { + margin-left: auto; + padding: 0.25rem 0.625rem; + border-radius: 1rem; + background: rgba(20, 184, 166, 0.1); + color: var(--rs-accent, #14b8a6); + font-size: 0.7rem; + font-weight: 500; + white-space: nowrap; } - .action-btn:hover { border-color: var(--rs-primary); color: var(--rs-text-primary); } .preview-flipbook { flex: 1; @@ -1140,14 +1196,17 @@ export class FolkPubsEditor extends HTMLElement { padding: 0.5rem 1.25rem; border: none; border-radius: 0.5rem; - background: var(--rs-primary); + background: var(--rs-accent, #14b8a6); color: #fff; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: background 0.15s; + display: inline-flex; + align-items: center; + gap: 0.375rem; } - .btn-publish-next:hover { background: var(--rs-primary-hover); } + .btn-publish-next:hover { background: var(--rs-accent-hover, #0d9488); } /* ── Publish step ── */ diff --git a/modules/rpubs/components/folk-pubs-flipbook.ts b/modules/rpubs/components/folk-pubs-flipbook.ts index 9a2b88b..36a95cd 100644 --- a/modules/rpubs/components/folk-pubs-flipbook.ts +++ b/modules/rpubs/components/folk-pubs-flipbook.ts @@ -169,9 +169,19 @@ export class FolkPubsFlipbook extends HTMLElement { const container = this.shadowRoot.querySelector(".flipbook-container") as HTMLElement; if (!container) return; - await this.loadStPageFlip(); + try { + await this.loadStPageFlip(); + } catch (e) { + console.warn('[folk-pubs-flipbook] StPageFlip failed to load, using fallback:', e); + this.renderFallback(); + return; + } const PageFlip = (window as any).St?.PageFlip; - if (!PageFlip) return; + if (!PageFlip) { + console.warn('[folk-pubs-flipbook] StPageFlip not available, using fallback'); + this.renderFallback(); + return; + } this._flipBook = new PageFlip(container, { width: Math.round(pageW), @@ -241,9 +251,26 @@ export class FolkPubsFlipbook extends HTMLElement { }); } + private renderFallback() { + if (!this.shadowRoot) return; + this.shadowRoot.innerHTML = ` + ${this.getStyles()} +
+
+ ${this._pageImages.map((src, i) => `Page ${i + 1}`).join('')} +
+
${this._numPages} pages
+
+ `; + } + private getStyles(): string { return ``; } }