Spreadsheet-UX op een echte relationele engine

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

2.5 kB Ruw bestand
import type { ReactNode } from 'react';
import { currencySymbol, type ColumnType } from '@wellformed/shared';

export function KeyIcon(): ReactNode {
  return (
    <svg
      width="10"
      height="10"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2.4"
      strokeLinecap="round"
      aria-hidden="true"
    >
      <circle cx="8" cy="8" r="4.5" />
      <path d="M11.5 11.5 20 20M16 16l3-3" />
    </svg>
  );
}

export function SearchIcon(): ReactNode {
  return (
    <svg
      width="13"
      height="13"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2.2"
      strokeLinecap="round"
      aria-hidden="true"
    >
      <circle cx="10.5" cy="10.5" r="7" />
      <path d="M16 16l5 5" />
    </svg>
  );
}

/** Compact type marker shown in headers and the schema outline. */
export const TYPE_LABEL: Record<ColumnType, string> = {
  text: 'abc',
  number: '123',
  currency: '¤',
  date: 'date',
  checkbox: '☑',
  select: 'enum',
  link: 'fk',
  formula: 'fx',
  rollup: 'Σ',
};

/**
 * The same marker, but a money column wears the sign the workspace actually
 * uses. A header that says `$` over a column of euros is a small lie told on
 * every screen.
 */
export function typeMark(type: ColumnType, currency: string): string {
  return type === 'currency' ? currencySymbol(currency) : TYPE_LABEL[type];
}

/** Palette for select values. Stable per label so a status keeps its colour. */
const NAMED_COLORS: Record<string, [string, string]> = {
  Draft: ['#EEF2F6', '#5A6B80'],
  Invoiced: ['#E7EDFC', '#2050D8'],
  Paid: ['#E2F3EC', '#0B7A55'],
  Overdue: ['#FBEAE9', '#B3261E'],
  West: ['#E7EDFC', '#2050D8'],
  East: ['#E2F3EC', '#0B7A55'],
  North: ['#FBF1DC', '#A16207'],
  South: ['#F3E8FA', '#7C3AED'],
  Sales: ['#E7EDFC', '#2050D8'],
  Ops: ['#FBF1DC', '#A16207'],
  Finance: ['#E2F3EC', '#0B7A55'],
};

const FALLBACK_COLORS: [string, string][] = [
  ['#E7EDFC', '#2050D8'],
  ['#E2F3EC', '#0B7A55'],
  ['#FBF1DC', '#A16207'],
  ['#F3E8FA', '#7C3AED'],
  ['#FBEAE9', '#B3261E'],
  ['#E4F1F6', '#0E6E86'],
];

export function selectColors(value: string): [string, string] {
  const named = NAMED_COLORS[value];
  if (named) return named;
  // Hash the label so a user-defined option gets a consistent colour without
  // anyone having to pick one.
  let hash = 0;
  for (let i = 0; i < value.length; i++) hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
  return FALLBACK_COLORS[hash % FALLBACK_COLORS.length]!;
}