mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-11-06 21:50:40 +00:00
Vector shapes (Phases A-E) + project polish
Vector shapes feature (per docs/VECTOR_SHAPES_FEATURE.md): Phase A - Shape primitive layers (rect, rounded-rect, circle, ellipse, triangle, polygon, star, line) with a 0-100 viewBox coord system that renders on all six surfaces (editor canvas + five preview renderers) plus Canvas2D export. Solid fill, kind-specific controls (corner radius, sides, star points, inner ratio, line stroke width). Layer data is purely additive in JSON; old clients skip unknown shape kinds. Phase B - Linear + radial gradient fills with two-stop pickers. SVG emits via <defs><linearGradient>/<radialGradient>; canvas via createLinearGradient/createRadialGradient. Angles follow CSS linear-gradient convention. Switching fill types preserves the most relevant color. Phase C - Solid strokes on all non-line shapes. Color, width (in shape-local viewBox units), dash style (solid / dashed / dotted) with auto-scaled dash patterns. SVG emits stroke attributes; canvas uses strokeStyle + setLineDash. Phase D - Custom SVG / full-SVG layer via file upload: - File picker (.svg, image/svg+xml) replaces a paste textarea. - Detects single <path d=…> vs full <svg>…</svg>; single paths land as kind:'path' with editable fill/stroke, multi-element SVGs land as kind:'svg' with fills baked in. - Sanitizer strips <script>, <foreignObject>, <iframe>, <embed>, <animate>, <image>, <a>, all on* event handlers, external hrefs/xlink:hrefs, and javascript:/external-url style entries. - Canvas export serializes the sanitized inner into a blob URL, loads via Image, drawImage. - Per-element editor: a list inside the shape panel exposes every paintable child (path / rect / circle / ellipse / polygon / polyline / line) with fill + stroke color pickers and a stroke-width input. Auto-applies a viewBox-relative default stroke width when stroke is first set so strokes are visible at any zoom. Layer-level fill / stroke panels are hidden for SVG imports (per-element is the canonical control). Phase E - Clip / mask on any layer type: - New optional `clip` field with two flavors: inline-shape (clip to a primitive defined inline) and layer-ref (clip to another shape layer's geometry in the same target). - Clip source dropdown in the selected-layer panel offers rect / rounded-rect / circle / ellipse / triangle / polygon / star / custom path / From another layer. Kind-specific param inputs show on demand. - DOM rendering uses a shared hidden SVG defs container with <clipPath clipPathUnits="objectBoundingBox"> entries, referenced via clip-path: url(#clip-<layerId>) on each layer wrapper. - Canvas export builds a Path2D with a DOMMatrix transform mapping 0-100 coords to the layer's pixel bounds, then ctx.clip() before drawing the layer contents. - Cycle detection: if A clips to B and B clips back to A, both fall back to unclipped instead of looping. - Single-path-SVG clips reuse the upload modal in an edit-clip flow that rejects multi-element SVGs with an inline error. Phase A bonus polish: - Shapes spawn 1:1 (min(bounds.w, bounds.h) * 0.4). - Session-wide aspect-ratio lock (default on) with a 🔒/🔓 toggle between the W/H inputs in the selected-layer panel. Typing in one dimension updates the other proportionally on every layer type. Per-mode metadata isolation: - state.savedMetaByMode parks Template-mode and Disc-Designer-mode metadata separately. swapMetaForAppMode runs before any appMode flip so loading a template in disc designer doesn't overwrite the designer's title / category / identifiers. omdbApiKey stays sticky across modes as a per-user preference. Strict per-sub-mode layout isolation: - isLayerForCurrentMode no longer treats target='page' as a universal wildcard. Each layer belongs to exactly one sub-mode by its target. - Removed the "Whole page" entry from the layer-target dropdown. - migrateLegacyLayerTargets retargets legacy page/empty layers to the current sub-mode's primary target on load. Wired into all four mode-specific load paths and the legacy full-project path. - Fixes the bug where case-cover artwork was rendering misaligned in the disc-sheet preview. Layer clipboard: - Session-only clipboard supports cross-sub-mode and cross-tool paste with retargeting. Copy / Cut on selected layer + Copy all / Paste in the panel header. Paste retargets to the current sub-mode's primary target and clamps positions so a layer copied from a wide cover doesn't land off-canvas in a 4.6" disc. UI polish: - Hide unused artwork-mode sidebar controls: cover full-wrap mode hides the separate Back / Spine / Front controls and vice versa, via the existing body.mode-combined / mode-separate classes. - Category-aware identifier visibility: only show IMDb / UPC / TheTVDB / MusicBrainz fields that fit the chosen category. Custom art hides all four. - Added "Custom art" to the canonical mediaCategories list and populated both the template and designer category selects from it (the template select was previously hardcoded). - Selected-layer panel hides entirely when nothing is selected. - Jewel spine-text details block hides until at least one jewel insert has artwork. - Close project / disc-designer reset / clear images all use a shared blankMeta() helper that covers UPC / TheTVDB / MusicBrainz (the previous reset path was missing them). Close project also resets state.customArt to its defaults so the background color doesn't carry over. - Disc Designer mode now has a proper add-layer panel (Add image with URL + Copy / Add text / Add color block / Add shape menu) in addition to the layer list. - Project file loads route through loadProjectFromText regardless of which "Load from file" button was used; an info toast announces a mode switch when one is needed. Publish flow: - New publish-confirm modal renders a live design preview, a metadata table (Type / Title / Category / Language / IMDb / UPC / TheTVDB / MusicBrainz / Author), and an edit-mode tradeoff banner. Replaces the bare confirm(). Errors render inline. - Removed the legacy "Copy Nostr event" button — only "Copy event ID" remains, and it stays hidden until something has been published. Toast system: - All 41 native alert() calls swapped for in-app toasts (toastError with a red border for failures, toastSuccess with the accent color for publish/copy confirmations). Auto-dismiss after a few seconds; manual close button on each. NIP-57 zap tab: - _feedPagination grew a Zapped entry so the new tab can render without crashing the rerender pipeline. - fetchZapsForEvents now runs chunks in parallel and streams a debounced rerender on every ingested receipt, so totals appear within a second or two instead of taking up to ~28 s. - invalidateFeedCache clears the zap cache too so Refresh re-queries receipts. Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
52dbfae945
commit
861e17e3f9
1 file changed
+1908
-113
+1908
-113
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user