feat(web): implement complete workspace with themes, tabs, sidebar, and mobile
Transform CalcText from a single-document calculator into a full workspace application with multi-document support, theming, and responsive mobile experience. - Theme system: 5 presets (Light, Dark, Matrix, Midnight, Warm) + accent colors - Document model with localStorage persistence and auto-save - Tab bar with keyboard shortcuts (Ctrl+N/W/Tab/1-9), rename, close - Sidebar with search, recent, favorites, folders, templates, drag-and-drop - 5 templates: Budget, Invoice, Unit Converter, Trip Planner, Loan Calculator - Status bar with cursor position, engine status, dedication to Igor Cassel - Results panel: type-specific colors, click-to-copy, error hints - Format toolbar: H, B, I, //, color labels with live preview toggle - Syntax highlighting using theme CSS variables - Error hover tooltips - Mobile: bottom results tray, sidebar drawer, touch targets, safe areas - Docker multi-stage build (Rust WASM + Vite + Nginx) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
54
calcpad-web/src/editor/inline-results.ts
Normal file
54
calcpad-web/src/editor/inline-results.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* CodeMirror 6 extension for zebra-striped editor lines.
|
||||
*
|
||||
* Previously also contained inline result widgets, but results
|
||||
* are now rendered in a separate ResultsPanel component.
|
||||
*/
|
||||
|
||||
import { Decoration, EditorView, ViewPlugin } from '@codemirror/view'
|
||||
import type { DecorationSet, ViewUpdate } from '@codemirror/view'
|
||||
import type { Extension } from '@codemirror/state'
|
||||
|
||||
/**
|
||||
* ViewPlugin that applies alternating background colors (zebra striping)
|
||||
* to even-numbered editor lines, helping users visually connect
|
||||
* expressions on the left to their inline results on the right.
|
||||
*/
|
||||
export const stripedLines = ViewPlugin.fromClass(
|
||||
class {
|
||||
decorations: DecorationSet
|
||||
|
||||
constructor(view: EditorView) {
|
||||
this.decorations = buildStripeDecorations(view)
|
||||
}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged || update.viewportChanged) {
|
||||
this.decorations = buildStripeDecorations(update.view)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
decorations: (v) => v.decorations,
|
||||
},
|
||||
)
|
||||
|
||||
const stripeDeco = Decoration.line({ class: 'cm-stripe' })
|
||||
|
||||
function buildStripeDecorations(view: EditorView): DecorationSet {
|
||||
const decorations: Array<ReturnType<typeof stripeDeco.range>> = []
|
||||
for (let i = 1; i <= view.state.doc.lines; i++) {
|
||||
if (i % 2 === 0) {
|
||||
const line = view.state.doc.line(i)
|
||||
decorations.push(stripeDeco.range(line.from))
|
||||
}
|
||||
}
|
||||
return Decoration.set(decorations)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the striped-lines extension for the editor.
|
||||
*/
|
||||
export function stripedLinesExtension(): Extension {
|
||||
return [stripedLines]
|
||||
}
|
||||
Reference in New Issue
Block a user