Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 62 additions & 3 deletions .ai/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,68 @@
<!-- ====================================================================== -->

## Last Updated
2026-03-30 -- **Pre-Reddit Launch + Entity Type Hierarchy + Settings Redesign.**

68. **Pre-Reddit Launch + Entity Type Hierarchy + Settings Redesign (15+ items).**
2026-04-06 -- **Major Feature Sprint: Map Drawing, Bulk Ops, Genre Presets, Topbar Image.**

69. **Major Feature Sprint (30+ commits).**

**New Features:**
- **Map Drawing Tools (W-2)** — Interactive Leaflet drawing toolbar: freehand, rectangle,
circle, polygon, text annotation. Color picker + stroke width. Right-click to delete.
No external dependency (native Leaflet APIs). Persists via REST API, broadcasts via
WebSocket. Floating toolbar for Scribe+. Max 10K points security validation.
- **Bulk Operations (W-4)** — Multi-select checkboxes on entity list (grid + table views),
floating action bar with: Change Type, Add Tags, Visibility toggle, Delete. 4 new
web-facing endpoints. Select-all in table header. Re-injects on HTMX pagination.
- **Genre Presets (T-4b)** — 5 genre presets for campaign creation: Fantasy, Sci-Fi,
Horror, Modern, Historical. Visual radio-card picker on campaign form. Each genre
seeds tailored entity types with appropriate icons, colors, and custom fields.
- **Topbar Image Upload** — Image mode button in Appearance editor. POST/DELETE endpoints.
Upload sets topbar to image mode with background-image: cover. JS dynamically adds
the Image button and upload panel to the existing mode selector.
- **Entity Type Hierarchy** — Migration 000019: parent_type_id on entity_types. Sub-types
with max 1 level. Layout Studio: nested display + "Add sub-type" button. Sidebar:
child types indented under parents.

**Settings & Admin Consolidation:**
- Features tab merged into Settings (instant Alpine.js toggles, no page reload)
- Settings General tab compacted (2-column grids, reduced padding/gaps)
- Standalone /plugins page redirects to Settings > Features tab
- Duplicate nav links removed (Features sidebar, Activity sidebar, quick links row)
- Campaign dashboard "Plugins" → "Features" terminology fix
- Admin sidebar cleaned: Content Packs hidden (WIP badge), Design Lab → Demo Page
- Demo Page link on admin dashboard (opens new tab)

**Sidebar Editor Rewrite (W-7):**
- Single pencil icon replaces gear + grip buttons
- Inline edit mode (hides nav, shows draggable item list)
- Restores nav on exit (reload if changes made)
- Entity-level reorg: wired to sidebar_tree.js via chronicle:reorg-changed event
- Body class: sidebar-reorg-active (matches tree expectations)
- Sub-type hierarchy display in sidebar navigation

**Nav Glow CSS:**
- Refined to: bottom 2/3 border + right edge + small top-right wrap
- Right-side gradient wash (inset box-shadow) fading left
- Click: border completes full wrap, gradient deepens
- Removed 418 lines of design lab A/B test CSS
- Removed duplicate sidebar.css glow definitions

**Bug Fixes:**
- Layout editor save: button ID mismatch (ls-te-save-btn vs te-save-btn)
- Game system not loading: manifest "file" vs "script_file" field name
- Game system discovery: ScanPackageDir at startup + callback on install
- CreateEntityType: returns JSON for API callers (was HTMX redirect)
- Sidebar drill "+": passes ?type= to pre-select category
- Sidebar editor: doesn't destroy nav content (hide/show instead)
- Mobile: editor touch targets, responsive entity pages

**Infrastructure:**
- Foundry module unbundled (package-manager installed now)
- Docker: MariaDB/Redis → latest
- LICENSE: AGPL-3.0
- README: cleaned TODO comments, v0.1 feature list

68. **Pre-Reddit Launch Cleanup + Entity Type Hierarchy + Settings Redesign.**

**Pre-Reddit Launch Fixes:**
- **LICENSE file** — AGPL-3.0 (662 lines, fetched from GitHub API)
Expand Down
3 changes: 3 additions & 0 deletions internal/plugins/maps/drawing_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ func (s *drawingService) CreateDrawing(ctx context.Context, input CreateDrawingI
if len(input.Points) == 0 {
return nil, apperror.NewBadRequest("points are required")
}
if len(input.Points) > 10000 {
return nil, apperror.NewBadRequest("too many points (maximum 10,000)")
}

vis := input.Visibility
if vis == "" {
Expand Down
14 changes: 14 additions & 0 deletions internal/plugins/maps/maps.templ
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,22 @@ templ mapShowContent(cc *campaigns.CampaignContext, data MapViewData) {
Chronicle.notify('Network error: ' + err.message, 'error');
}
};
// Expose map context for drawing tools.
window.chronicleMap = {
map: map,
campaignID: campaignID,
mapID: mapID,
imageW: w,
imageH: h,
isScribe: isScribe
};
})();
</script>

if data.IsScribe {
<script src="/static/js/map_drawing_tools.js"></script>
}

<!-- Minimal CSS for Leaflet marker icons -->
<style>
.chronicle-marker { background: none !important; border: none !important; }
Expand All @@ -634,6 +647,7 @@ templ mapShowContent(cc *campaigns.CampaignContext, data MapViewData) {
color: #fff; background: rgba(59, 130, 246, 0.85);
border-radius: 50%; box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
.map-text-annotation { background: none !important; border: none !important; }
</style>
}

Expand Down
8 changes: 8 additions & 0 deletions internal/systems/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ type WidgetDef struct {
// ScriptFile is the relative path to the JS file within the system
// directory (e.g., "widgets/stat-block.js").
ScriptFile string `json:"script_file"`

// File is an alias for ScriptFile for backward compatibility.
File string `json:"file"`
}

// CategoryDef describes one category of reference content within a module.
Expand Down Expand Up @@ -554,6 +557,11 @@ func ValidateManifest(m *SystemManifest) error {
if w.Name == "" {
return fmt.Errorf("widget %d (%s): name is required", i, w.Slug)
}
// Accept "file" as an alias for "script_file" (backward compatibility).
if w.ScriptFile == "" && w.File != "" {
m.Widgets[i].ScriptFile = w.File
w.ScriptFile = w.File
}
if w.ScriptFile == "" {
return fmt.Errorf("widget %d (%s): script_file is required", i, w.Slug)
}
Expand Down
Loading
Loading