Add landing page for kjol, documentation
This commit is contained in:
@@ -80,7 +80,7 @@ const (
|
||||
|
||||
// HEADER_COLOR_CLS is the background + text color per header color.
|
||||
var HEADER_COLOR_CLS = map[AutoTableHeaderColor]string{
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "bg-neutral-50",
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "bg-surface-muted",
|
||||
AUTOTABLE_HEADER_COLOR_BLUE: "bg-sky-700 text-white",
|
||||
AUTOTABLE_HEADER_COLOR_GREEN: "bg-green-700 text-white",
|
||||
AUTOTABLE_HEADER_COLOR_GRAY: "bg-neutral-600 text-white",
|
||||
@@ -89,7 +89,7 @@ var HEADER_COLOR_CLS = map[AutoTableHeaderColor]string{
|
||||
|
||||
// atHeaderSortHoverCls is the sortable-hover override per color.
|
||||
var atHeaderSortHoverCls = map[AutoTableHeaderColor]string{
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "hover:bg-neutral-300",
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "hover:bg-surface-strong",
|
||||
AUTOTABLE_HEADER_COLOR_BLUE: "hover:bg-sky-500",
|
||||
AUTOTABLE_HEADER_COLOR_GREEN: "hover:bg-green-800",
|
||||
AUTOTABLE_HEADER_COLOR_GRAY: "hover:bg-neutral-500",
|
||||
@@ -107,7 +107,7 @@ var HEADER_TEXT_CLS = map[AutoTableHeaderColor]string{
|
||||
|
||||
// atHeaderSortIconCls is the sort-icon color (matches header text) per color.
|
||||
var atHeaderSortIconCls = map[AutoTableHeaderColor]string{
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "text-black",
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "text-ink",
|
||||
AUTOTABLE_HEADER_COLOR_BLUE: "text-white",
|
||||
AUTOTABLE_HEADER_COLOR_GREEN: "text-white",
|
||||
AUTOTABLE_HEADER_COLOR_GRAY: "text-white",
|
||||
@@ -137,11 +137,11 @@ var atPaginationPaddingCls = map[AutoTableSize]string{
|
||||
|
||||
// atRowHoverCls is the body-row hover background per color (when hover is on).
|
||||
var atRowHoverCls = map[AutoTableHeaderColor]string{
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "hover:bg-neutral-200",
|
||||
AUTOTABLE_HEADER_COLOR_BLUE: "hover:bg-sky-100",
|
||||
AUTOTABLE_HEADER_COLOR_GREEN: "hover:bg-green-100",
|
||||
AUTOTABLE_HEADER_COLOR_GRAY: "hover:bg-neutral-200",
|
||||
AUTOTABLE_HEADER_COLOR_DARK_BLUE: "hover:bg-sky-100",
|
||||
AUTOTABLE_HEADER_COLOR_DEFAULT: "hover:bg-surface-strong",
|
||||
AUTOTABLE_HEADER_COLOR_BLUE: "hover:bg-sky-100 dark:bg-sky-900",
|
||||
AUTOTABLE_HEADER_COLOR_GREEN: "hover:bg-green-100 dark:bg-green-900",
|
||||
AUTOTABLE_HEADER_COLOR_GRAY: "hover:bg-surface-strong",
|
||||
AUTOTABLE_HEADER_COLOR_DARK_BLUE: "hover:bg-sky-100 dark:bg-sky-900",
|
||||
}
|
||||
|
||||
// POS_CLS is the text alignment per ColumnPosition.
|
||||
@@ -160,7 +160,7 @@ var HEADER_INNER_POS = map[ColumnPosition]string{
|
||||
|
||||
// -- Class string constants for parts that don't vary by config ------------
|
||||
const (
|
||||
TBL_CONTAINER = "relative flex flex-col w-full h-full bg-white rounded-default overflow-hidden"
|
||||
TBL_CONTAINER = "relative flex flex-col w-full h-full bg-surface rounded-default overflow-hidden"
|
||||
TBL_WRAPPER = "overflow-x-auto w-full"
|
||||
TBL_BASE = "min-w-full"
|
||||
|
||||
@@ -169,20 +169,20 @@ const (
|
||||
|
||||
atSortIconWrap = "leading-none shrink-0 opacity-50"
|
||||
|
||||
atSkeleton = "h-4 bg-neutral-200 rounded-default animate-pulse"
|
||||
atErrorCell = "text-center text-red-600"
|
||||
atEmptyCell = "text-center text-neutral-500"
|
||||
atSkeleton = "h-4 bg-surface-strong rounded-default animate-pulse"
|
||||
atErrorCell = "text-center text-red-600 dark:text-red-400"
|
||||
atEmptyCell = "text-center text-ink-muted"
|
||||
|
||||
atPaginationBase = "flex justify-between items-center border-t border-neutral-300"
|
||||
atPaginationInfo = "hidden sm:flex items-center text-sm text-neutral-500"
|
||||
atPaginationBase = "flex justify-between items-center border-t border-line-strong"
|
||||
atPaginationInfo = "hidden sm:flex items-center text-sm text-ink-muted"
|
||||
atPaginationControls = "flex items-center"
|
||||
atPaginationLabel = "hidden sm:block text-sm text-neutral-500 mr-2"
|
||||
atPaginationPage = "text-sm text-neutral-500 px-3"
|
||||
atPaginationBtn = "p-1 min-h-9 text-sm font-normal leading-none bg-transparent border-0 cursor-pointer hover:bg-neutral-100 disabled:text-neutral-300 disabled:cursor-not-allowed disabled:hover:bg-transparent"
|
||||
atPaginationLabel = "hidden sm:block text-sm text-ink-muted mr-2"
|
||||
atPaginationPage = "text-sm text-ink-muted px-3"
|
||||
atPaginationBtn = "p-1 min-h-9 text-sm font-normal leading-none bg-transparent border-0 cursor-pointer hover:bg-surface-raised disabled:text-ink-faint disabled:cursor-not-allowed disabled:hover:bg-transparent"
|
||||
|
||||
// thead sticky classes are the STATIC replacement for the TSX's JS-driven
|
||||
// header pinning (transform tracking on scroll). See file-level NOTE.
|
||||
atTheadCls = "sticky top-0 z-10 [&_th]:border-b [&_th]:border-neutral-300"
|
||||
atTheadCls = "sticky top-0 z-10 [&_th]:border-b [&_th]:border-line-strong"
|
||||
)
|
||||
|
||||
// AutoTableColumn describes one column: its header, alignment, width, whether it
|
||||
@@ -475,7 +475,7 @@ func AutoTable(cols []AutoTableColumn, rows []any, opts ...AutoTableOption) *vdo
|
||||
|
||||
containerCls := TBL_CONTAINER
|
||||
if cfg.surroundingBorder {
|
||||
containerCls = cx(containerCls, "border border-neutral-300")
|
||||
containerCls = cx(containerCls, "border border-line-strong")
|
||||
}
|
||||
if cfg.shadow {
|
||||
containerCls = cx(containerCls, "shadow-sm")
|
||||
@@ -754,7 +754,7 @@ func atResizeHandle(key string, h *atColumnHooks) *vdom.VNode {
|
||||
func atRenderBody(cols []AutoTableColumn, rows []any, cfg *atConfig) *vdom.VNode {
|
||||
bodyCls := BODY_PADDING_CLS[cfg.size]
|
||||
if cfg.borderY {
|
||||
bodyCls = cx(bodyCls, "[&_td+td]:border-l [&_td+td]:border-neutral-300")
|
||||
bodyCls = cx(bodyCls, "[&_td+td]:border-l [&_td+td]:border-line-strong")
|
||||
}
|
||||
|
||||
colspan := atTotalColumns(cols, cfg)
|
||||
@@ -768,7 +768,7 @@ func atRenderBody(cols []AutoTableColumn, rows []any, cfg *atConfig) *vdom.VNode
|
||||
for r := 0; r < 5; r++ {
|
||||
tr := vdom.Tr()
|
||||
if cfg.alternate && r%2 == 1 {
|
||||
tr.Attrs["class"] = "bg-neutral-100"
|
||||
tr.Attrs["class"] = "bg-surface-raised"
|
||||
}
|
||||
if cfg.accordion {
|
||||
tr.Children = append(tr.Children, vdom.Td(vdom.Attr("class", AUTOTABLE_ACCORDION_CELL)))
|
||||
@@ -799,11 +799,11 @@ func atRenderBody(cols []AutoTableColumn, rows []any, cfg *atConfig) *vdom.VNode
|
||||
isLast := rowIdx == len(rows)-1
|
||||
rowCls := ""
|
||||
if cfg.alternate && rowIdx%2 == 1 {
|
||||
rowCls = cx(rowCls, "bg-neutral-100")
|
||||
rowCls = cx(rowCls, "bg-surface-raised")
|
||||
}
|
||||
rowCls = cx(rowCls, hoverCls)
|
||||
if cfg.borderX && !isLast {
|
||||
rowCls = cx(rowCls, "border-b border-neutral-300")
|
||||
rowCls = cx(rowCls, "border-b border-line-strong")
|
||||
}
|
||||
if cfg.highlight != nil && cfg.highlight(row) {
|
||||
rowCls = cx(rowCls, AUTOTABLE_HIGHLIGHT_ROW)
|
||||
@@ -2182,14 +2182,14 @@ func (s *AutoTableState) FiltersToggle() *vdom.VNode {
|
||||
const (
|
||||
AUTOTABLE_SEARCH_FIELDS = "flex flex-wrap items-end gap-2"
|
||||
AUTOTABLE_SEARCH_FIELD = "flex flex-col gap-1 min-w-0 grow sm:grow-0 sm:w-48"
|
||||
AUTOTABLE_SEARCH_SELECT = "w-full rounded-default border border-neutral-300 bg-white px-3 py-2 text-sm"
|
||||
AUTOTABLE_FILTERS_TOGGLE = "sm:hidden inline-flex items-center gap-2 rounded-default border border-neutral-300 px-3 py-2 text-sm"
|
||||
AUTOTABLE_SEARCH_SELECT = "w-full rounded-default border border-line-strong bg-surface px-3 py-2 text-sm"
|
||||
AUTOTABLE_FILTERS_TOGGLE = "sm:hidden inline-flex items-center gap-2 rounded-default border border-line-strong px-3 py-2 text-sm"
|
||||
AUTOTABLE_FILTERS_BADGE = "ml-1 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-sky-600 px-1.5 text-xs font-semibold text-white"
|
||||
AUTOTABLE_TOOLBAR = "flex flex-wrap items-end justify-between gap-3 pb-3"
|
||||
AUTOTABLE_ASIDE = "w-full sm:w-64 shrink-0 rounded-default border border-neutral-300 bg-white p-3"
|
||||
AUTOTABLE_ASIDE = "w-full sm:w-64 shrink-0 rounded-default border border-line-strong bg-surface p-3"
|
||||
AUTOTABLE_ACCORDION_CELL = "w-10 text-center"
|
||||
AUTOTABLE_ACCORDION_ROW = "bg-neutral-50"
|
||||
AUTOTABLE_HIGHLIGHT_ROW = "bg-amber-100! shadow-[inset_3px_0_0_0_theme(colors.amber.500)]"
|
||||
AUTOTABLE_ACCORDION_ROW = "bg-surface-muted"
|
||||
AUTOTABLE_HIGHLIGHT_ROW = "bg-amber-100 dark:bg-amber-900! shadow-[inset_3px_0_0_0_theme(colors.amber.500)]"
|
||||
)
|
||||
|
||||
// ==========================================================================
|
||||
@@ -2602,7 +2602,7 @@ func (s *AutoTableState) pendingSkeleton() *vdom.VNode {
|
||||
vdom.Attr("aria-label", "Loading table"),
|
||||
vdom.Div(
|
||||
kids([]vdom.Mod{
|
||||
vdom.Attr("class", cx(TBL_CONTAINER, "border border-neutral-300 p-4 flex flex-col gap-3")),
|
||||
vdom.Attr("class", cx(TBL_CONTAINER, "border border-line-strong p-4 flex flex-col gap-3")),
|
||||
}, bars)...,
|
||||
),
|
||||
)
|
||||
@@ -2718,6 +2718,7 @@ func (s *AutoTableState) ColumnPicker() *vdom.VNode {
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
}
|
||||
total := len(options)
|
||||
return s.multiSelect("__columns__").Render(FormMultiSelectProps{
|
||||
Options: options,
|
||||
Value: selected,
|
||||
@@ -2725,6 +2726,11 @@ func (s *AutoTableState) ColumnPicker() *vdom.VNode {
|
||||
Searchable: true,
|
||||
ShowSelectAll: true,
|
||||
FieldWidth: "w-52",
|
||||
// Not "5 items selected": this picker is about COLUMNS, and the count is only
|
||||
// meaningful next to how many there are to choose from.
|
||||
CollapsedLabel: func(n int) string {
|
||||
return strconv.Itoa(n) + " of " + strconv.Itoa(total) + " columns"
|
||||
},
|
||||
OnChange: func(visible []string) {
|
||||
show := map[string]bool{}
|
||||
for _, k := range visible {
|
||||
@@ -2779,7 +2785,7 @@ func (s *AutoTableState) ResetMenu() *vdom.VNode {
|
||||
}
|
||||
|
||||
if len(items) == 0 {
|
||||
items = append(items, vdom.Div(vdom.Attr("class", "px-3 py-2 text-sm text-neutral-500"),
|
||||
items = append(items, vdom.Div(vdom.Attr("class", "px-3 py-2 text-sm text-ink-muted"),
|
||||
vdom.Text("Nothing to reset"),
|
||||
))
|
||||
} else {
|
||||
@@ -3091,7 +3097,7 @@ func (s *AutoTableState) summaryFoot(ctx *CalcContext, colCount int) *vdom.VNode
|
||||
}
|
||||
|
||||
// AUTOTABLE_TFOOT styles the summary footer.
|
||||
const AUTOTABLE_TFOOT = "border-t-2 border-neutral-300 bg-neutral-50 [&_td]:p-3"
|
||||
const AUTOTABLE_TFOOT = "border-t-2 border-line-strong bg-surface-muted [&_td]:p-3"
|
||||
|
||||
// ---- the calculated-column editor ----
|
||||
|
||||
@@ -3127,16 +3133,16 @@ func isBinaryCalcFn(fn CalculatedFunction) bool {
|
||||
// their metrics line up to the pixel; if they ever drift, the caret stops landing on
|
||||
// the glyph it appears to be on.
|
||||
const (
|
||||
CALC_ADD_TRIGGER_CLS = "inline-flex items-center justify-center gap-2 cursor-pointer text-sm font-normal rounded-default transition shadow-xs bg-neutral-50 text-black border border-neutral-300 hover:bg-neutral-100 py-1 px-3"
|
||||
CALC_ADD_TRIGGER_CLS = "inline-flex items-center justify-center gap-2 cursor-pointer text-sm font-normal rounded-default transition shadow-xs bg-surface-muted text-ink border border-line-strong hover:bg-surface-raised py-1 px-3"
|
||||
|
||||
FORMULA_EDIT_BASE = "block w-full h-[30px] font-mono text-sm p-1 rounded-default box-border whitespace-pre"
|
||||
FORMULA_OVERLAY_CLS = FORMULA_EDIT_BASE + " absolute inset-0 overflow-hidden pointer-events-none border border-transparent text-neutral-800"
|
||||
FORMULA_TEXTAREA_CLS = FORMULA_EDIT_BASE + " relative bg-transparent text-transparent caret-neutral-800 resize-none overflow-x-auto overflow-y-hidden shadow-xs border border-neutral-300 focus:border-sky-500 outline-hidden"
|
||||
FORMULA_OVERLAY_CLS = FORMULA_EDIT_BASE + " absolute inset-0 overflow-hidden pointer-events-none border border-transparent text-ink"
|
||||
FORMULA_TEXTAREA_CLS = FORMULA_EDIT_BASE + " relative bg-transparent text-transparent caret-neutral-800 resize-none overflow-x-auto overflow-y-hidden shadow-xs border border-line-strong focus:border-sky-500 outline-hidden"
|
||||
|
||||
formulaPlaceholder = `<span class="text-neutral-400">e.g. [Revenue] / SUM({Revenue}) * 100</span>`
|
||||
formulaPlaceholder = `<span class="text-ink-faint">e.g. [Revenue] / SUM({Revenue}) * 100</span>`
|
||||
|
||||
calcMenuTrigger = "inline-flex items-center gap-1 rounded-default border border-neutral-300 bg-neutral-50 px-2 py-1 text-xs leading-none text-neutral-700 cursor-pointer hover:bg-neutral-100"
|
||||
calcChooserItem = "w-full text-left px-2 py-2 rounded-default hover:bg-neutral-100 cursor-pointer border-0 bg-transparent flex items-start gap-2.5"
|
||||
calcMenuTrigger = "inline-flex items-center gap-1 rounded-default border border-line-strong bg-surface-muted px-2 py-1 text-xs leading-none text-ink-soft cursor-pointer hover:bg-surface-raised"
|
||||
calcChooserItem = "w-full text-left px-2 py-2 rounded-default hover:bg-surface-raised cursor-pointer border-0 bg-transparent flex items-start gap-2.5"
|
||||
)
|
||||
|
||||
// HighlightFormula renders a formula as HTML with syntax colouring: cell refs
|
||||
@@ -3145,6 +3151,20 @@ const (
|
||||
// Purely visual, and deliberately LEXICAL rather than a real parse — it has to
|
||||
// colour a half-typed formula that does not compile yet, which is exactly when the
|
||||
// colours are worth the most.
|
||||
// The formula highlighter's token colours.
|
||||
//
|
||||
// Named, rather than written inline, because they are asserted on in tests — and a
|
||||
// colour spelled out in two places is a colour that gets changed in one. (It already
|
||||
// happened: adding the dark: variants broke every highlighter test, none of which cared
|
||||
// about the colour, all of which had a copy of it.)
|
||||
const (
|
||||
fmlCellClass = "text-sky-600 dark:text-sky-400" // [Cell]
|
||||
fmlColumnClass = "text-violet-600 dark:text-violet-400" // {Column}
|
||||
fmlNumberClass = "text-amber-600 dark:text-amber-400" // 42, PI
|
||||
fmlFuncClass = "text-emerald-700 dark:text-emerald-400 font-semibold" // SUM(
|
||||
fmlOpClass = "text-ink-faint" // + - * /
|
||||
)
|
||||
|
||||
func HighlightFormula(src string) string {
|
||||
var b strings.Builder
|
||||
i := 0
|
||||
@@ -3159,7 +3179,7 @@ func HighlightFormula(src string) string {
|
||||
if j >= 0 {
|
||||
end = i + j + 1
|
||||
}
|
||||
b.WriteString(`<span class="text-sky-600">`)
|
||||
b.WriteString(`<span class="` + fmlCellClass + `">`)
|
||||
b.WriteString(html.EscapeString(src[i:end]))
|
||||
b.WriteString(`</span>`)
|
||||
i = end
|
||||
@@ -3176,7 +3196,7 @@ func HighlightFormula(src string) string {
|
||||
}
|
||||
j++
|
||||
}
|
||||
b.WriteString(`<span class="text-violet-600">`)
|
||||
b.WriteString(`<span class="` + fmlColumnClass + `">`)
|
||||
b.WriteString(html.EscapeString(src[i:j]))
|
||||
b.WriteString(`</span>`)
|
||||
i = j
|
||||
@@ -3186,7 +3206,7 @@ func HighlightFormula(src string) string {
|
||||
for j < len(src) && (isDigit(src[j]) || src[j] == '.') {
|
||||
j++
|
||||
}
|
||||
b.WriteString(`<span class="text-amber-600">`)
|
||||
b.WriteString(`<span class="` + fmlNumberClass + `">`)
|
||||
b.WriteString(html.EscapeString(src[i:j]))
|
||||
b.WriteString(`</span>`)
|
||||
i = j
|
||||
@@ -3205,11 +3225,11 @@ func HighlightFormula(src string) string {
|
||||
}
|
||||
switch {
|
||||
case k < len(src) && src[k] == '(':
|
||||
b.WriteString(`<span class="text-emerald-700 font-semibold">`)
|
||||
b.WriteString(`<span class="` + fmlFuncClass + `">`)
|
||||
b.WriteString(html.EscapeString(word))
|
||||
b.WriteString(`</span>`)
|
||||
case isFormulaConstant(word):
|
||||
b.WriteString(`<span class="text-amber-600">`)
|
||||
b.WriteString(`<span class="` + fmlNumberClass + `">`)
|
||||
b.WriteString(html.EscapeString(word))
|
||||
b.WriteString(`</span>`)
|
||||
default:
|
||||
@@ -3218,7 +3238,7 @@ func HighlightFormula(src string) string {
|
||||
i = j
|
||||
|
||||
case strings.IndexByte("+-*/^%=<>(),:", c) >= 0:
|
||||
b.WriteString(`<span class="text-neutral-400">`)
|
||||
b.WriteString(`<span class="` + fmlOpClass + `">`)
|
||||
b.WriteString(html.EscapeString(string(c)))
|
||||
b.WriteString(`</span>`)
|
||||
i++
|
||||
@@ -3590,7 +3610,7 @@ func (s *AutoTableState) calcChooser(e *calcEditor) *vdom.VNode {
|
||||
))
|
||||
}
|
||||
if len(existing) > 0 {
|
||||
children = append(children, vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-1 border-b border-neutral-200 pb-2 mb-1")}, existing)...))
|
||||
children = append(children, vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-1 border-b border-line pb-2 mb-1")}, existing)...))
|
||||
}
|
||||
|
||||
children = append(children,
|
||||
@@ -3607,19 +3627,19 @@ func calcChooserButton(icon, title, subtitle string, onClick func()) *vdom.VNode
|
||||
return vdom.Button(vdom.Attr("type", "button"),
|
||||
vdom.Attr("class", calcChooserItem),
|
||||
vdom.On(vdom.EVENT_CLICK, onClick),
|
||||
Icon(icon, 16, "mt-0.5 text-neutral-500"),
|
||||
Icon(icon, 16, "mt-0.5 text-ink-muted"),
|
||||
vdom.Span(vdom.Attr("class", "flex flex-col"),
|
||||
vdom.Span(vdom.Attr("class", "text-sm font-medium text-neutral-800"), vdom.Text(title)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text(subtitle)),
|
||||
vdom.Span(vdom.Attr("class", "text-sm font-medium text-ink"), vdom.Text(title)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(subtitle)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func calcListRow(title, subtitle string, onEdit, onDelete func()) *vdom.VNode {
|
||||
return vdom.Div(vdom.Attr("class", "flex items-center gap-2 rounded-default px-2 py-1 hover:bg-neutral-50"),
|
||||
return vdom.Div(vdom.Attr("class", "flex items-center gap-2 rounded-default px-2 py-1 hover:bg-surface-muted"),
|
||||
vdom.Div(vdom.Attr("class", "min-w-0 grow"),
|
||||
vdom.Div(vdom.Attr("class", "truncate text-sm font-medium text-neutral-800"), vdom.Text(title)),
|
||||
vdom.Div(vdom.Attr("class", "truncate font-mono text-xs text-neutral-500"), vdom.Text(subtitle)),
|
||||
vdom.Div(vdom.Attr("class", "truncate text-sm font-medium text-ink"), vdom.Text(title)),
|
||||
vdom.Div(vdom.Attr("class", "truncate font-mono text-xs text-ink-muted"), vdom.Text(subtitle)),
|
||||
),
|
||||
Button(ButtonProps{Color: ButtonLightNeutral, Small: true, Icon: "pencil", Title: "Edit", OnClick: onEdit}),
|
||||
Button(ButtonProps{Color: ButtonLightNeutral, Small: true, Icon: "trash", Title: "Delete", OnClick: onDelete}),
|
||||
@@ -3712,14 +3732,14 @@ func (s *AutoTableState) calcForm(e *calcEditor, summary bool) *vdom.VNode {
|
||||
title = "Edit " + strings.ToLower(title)
|
||||
}
|
||||
|
||||
header := vdom.Div(vdom.Attr("class", "flex items-center gap-2 border-b border-neutral-200 px-3 py-2"),
|
||||
header := vdom.Div(vdom.Attr("class", "flex items-center gap-2 border-b border-line px-3 py-2"),
|
||||
vdom.Button(vdom.Attr("type", "button"),
|
||||
vdom.Attr("class", "shrink-0 cursor-pointer rounded-default p-1 text-neutral-500 hover:bg-neutral-100 border-0 bg-transparent"),
|
||||
vdom.Attr("class", "shrink-0 cursor-pointer rounded-default p-1 text-ink-muted hover:bg-surface-raised border-0 bg-transparent"),
|
||||
vdom.Attr("aria-label", "Back"),
|
||||
vdom.On(vdom.EVENT_CLICK, e.reset),
|
||||
Icon("chevron-left", 14, ""),
|
||||
),
|
||||
vdom.Span(vdom.Attr("class", "text-sm font-medium text-neutral-800"), vdom.Text(title)),
|
||||
vdom.Span(vdom.Attr("class", "text-sm font-medium text-ink"), vdom.Text(title)),
|
||||
// Basic vs Advanced.
|
||||
vdom.Div(vdom.Attr("class", "ml-auto"),
|
||||
SegmentedButtons([]SegmentedButtonOption{
|
||||
@@ -3773,7 +3793,7 @@ func (s *AutoTableState) calcForm(e *calcEditor, summary bool) *vdom.VNode {
|
||||
}
|
||||
|
||||
if msg := e.errorMsg.Get(); msg != "" {
|
||||
fields = append(fields, vdom.P(vdom.Attr("class", "text-xs text-red-600"), vdom.Text(msg)))
|
||||
fields = append(fields, vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(msg)))
|
||||
}
|
||||
|
||||
saveLabel := "Add"
|
||||
@@ -3877,7 +3897,7 @@ func (s *AutoTableState) calcBasicEditor(e *calcEditor, summary bool) *vdom.VNod
|
||||
})))
|
||||
}
|
||||
|
||||
children = append(children, vdom.P(vdom.Attr("class", "text-xs text-neutral-500"),
|
||||
children = append(children, vdom.P(vdom.Attr("class", "text-xs text-ink-muted"),
|
||||
vdom.Text(calcBasicHint(e, summary))))
|
||||
|
||||
return vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-2")}, children)...)
|
||||
@@ -3908,12 +3928,12 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
label := o.Label
|
||||
colItems = append(colItems,
|
||||
e.colMenu.Item(MenuItemProps{OnClick: func() { e.insertAtCaret("[" + label + "]") }},
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-sky-600"), vdom.Text("["+label+"]")),
|
||||
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-neutral-500"), vdom.Text("this row")),
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-sky-600 dark:text-sky-400"), vdom.Text("["+label+"]")),
|
||||
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-ink-muted"), vdom.Text("this row")),
|
||||
),
|
||||
e.colMenu.Item(MenuItemProps{OnClick: func() { e.insertAtCaret("{" + label + "}") }},
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-violet-600"), vdom.Text("{"+label+"}")),
|
||||
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-neutral-500"), vdom.Text("whole column")),
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-violet-600 dark:text-violet-400"), vdom.Text("{"+label+"}")),
|
||||
vdom.Span(vdom.Attr("class", "ml-2 text-xs text-ink-muted"), vdom.Text("whole column")),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -3925,7 +3945,7 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
groups := filterFormulaGroups(e.fnSearch.Get())
|
||||
if len(groups) == 0 {
|
||||
fnItems = append(fnItems, vdom.Div(
|
||||
vdom.Attr("class", "px-2 py-3 text-center text-xs text-neutral-500"),
|
||||
vdom.Attr("class", "px-2 py-3 text-center text-xs text-ink-muted"),
|
||||
vdom.Text("No functions match"),
|
||||
))
|
||||
}
|
||||
@@ -3940,7 +3960,7 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
// The signature is syntax-highlighted with the same highlighter the
|
||||
// formula box uses, so the menu and the editor speak one language.
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-xs"), vdom.Raw(HighlightFormula(f.Sig))),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text(f.Desc)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(f.Desc)),
|
||||
),
|
||||
))
|
||||
}
|
||||
@@ -3953,8 +3973,8 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
OnClick: func() { e.insertAtCaret(cc.Name) },
|
||||
},
|
||||
vdom.Div(vdom.Attr("class", "flex flex-col items-start gap-0.5"),
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-xs text-amber-600"), vdom.Text(cc.Name)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text(cc.Desc)),
|
||||
vdom.Span(vdom.Attr("class", "font-mono text-xs text-amber-600 dark:text-amber-400"), vdom.Text(cc.Name)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(cc.Desc)),
|
||||
),
|
||||
))
|
||||
}
|
||||
@@ -4008,7 +4028,7 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
),
|
||||
)
|
||||
|
||||
help := vdom.P(vdom.Attr("class", "text-xs text-neutral-500"),
|
||||
help := vdom.P(vdom.Attr("class", "text-xs text-ink-muted"),
|
||||
vdom.Text("[Column] is this row's cell · {Column} is the whole column · {Column:1:ROW()} is a running total."))
|
||||
|
||||
children := []*vdom.VNode{menus, editor, help}
|
||||
@@ -4024,11 +4044,11 @@ func (s *AutoTableState) calcAdvancedEditor(e *calcEditor, summary bool) *vdom.V
|
||||
func (e *calcEditor) fnSearchBox() *vdom.VNode {
|
||||
wasmruntime.AfterRender(func() { wasmruntime.Focus(e.fnSearchRef) })
|
||||
|
||||
return vdom.Div(vdom.Attr("class", "sticky top-0 z-10 -m-1.5 mb-1 border-b border-neutral-200 bg-white p-1.5"),
|
||||
return vdom.Div(vdom.Attr("class", "sticky top-0 z-10 -m-1.5 mb-1 border-b border-line bg-surface p-1.5"),
|
||||
vdom.Input(
|
||||
vdom.WithRef(e.fnSearchRef),
|
||||
vdom.Attr("type", "text"),
|
||||
vdom.Attr("class", "w-full rounded-default border border-neutral-300 p-1 text-xs focus:outline-2 focus:outline-sky-500"),
|
||||
vdom.Attr("class", "w-full rounded-default border border-line-strong p-1 text-xs focus:outline-2 focus:outline-sky-500"),
|
||||
vdom.Attr("placeholder", "Search functions…"),
|
||||
vdom.Attr("spellcheck", "false"),
|
||||
vdom.Prop("value", e.fnSearch.Get()),
|
||||
@@ -4069,12 +4089,12 @@ func (s *AutoTableState) calcPreview(e *calcEditor, src string, summary bool) *v
|
||||
return nil
|
||||
}
|
||||
if _, err := CompileFormula(src); err != nil {
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-red-600"), vdom.Text(err.Error()))
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
|
||||
}
|
||||
|
||||
rows := s.FilteredRows()
|
||||
if len(rows) == 0 {
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text("Formula is valid."))
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text("Formula is valid."))
|
||||
}
|
||||
ctx := NewCalcContext(rows, s.cols, s.Calculated(), s.read)
|
||||
|
||||
@@ -4087,10 +4107,10 @@ func (s *AutoTableState) calcPreview(e *calcEditor, src string, summary bool) *v
|
||||
|
||||
n, err := EvalFormula(src, target)
|
||||
if err != nil {
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-red-600"), vdom.Text(err.Error()))
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-red-600 dark:text-red-400"), vdom.Text(err.Error()))
|
||||
}
|
||||
out := FormatCalcResult(n, CalculatedDataType(e.dataType.Get()), calcPrecisionOf(e.precision.Get()), "", "", "")
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-neutral-500"), vdom.Text(prefix+out))
|
||||
return vdom.P(vdom.Attr("class", "text-xs text-ink-muted"), vdom.Text(prefix+out))
|
||||
}
|
||||
|
||||
// insertAtCaret drops text where the cursor is, rather than at the end — which is
|
||||
@@ -4121,7 +4141,7 @@ func (e *calcEditor) insertAtCaretOffset(text string, back int) {
|
||||
|
||||
func calcField(label string, children ...*vdom.VNode) *vdom.VNode {
|
||||
nodes := []*vdom.VNode{
|
||||
vdom.Span(vdom.Attr("class", "text-xs font-medium text-neutral-600"), vdom.Text(label)),
|
||||
vdom.Span(vdom.Attr("class", "text-xs font-medium text-ink-soft"), vdom.Text(label)),
|
||||
}
|
||||
nodes = append(nodes, children...)
|
||||
return vdom.Div(kids([]vdom.Mod{vdom.Attr("class", "flex flex-col gap-1")}, nodes)...)
|
||||
|
||||
Reference in New Issue
Block a user