From d4ea6d2739514393a573ce2ddd3c566ef82e2d2e Mon Sep 17 00:00:00 2001 From: Forbes Date: Fri, 13 Feb 2026 13:09:41 -0600 Subject: [PATCH 1/3] fix(web): align item type badge colors with style guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #65 - Part: blue → green (--ctp-green) - Assembly: green → mauve (--ctp-mauve) - Document: yellow → blue (--ctp-blue) - Add purchased (--ctp-peach) and phantom (--ctp-overlay1) - Keep tooling as red (--ctp-red) --- web/src/components/items/ItemDetail.tsx | 8 +++++--- web/src/components/items/ItemTable.tsx | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/web/src/components/items/ItemDetail.tsx b/web/src/components/items/ItemDetail.tsx index 7e78a52..f7fdf39 100644 --- a/web/src/components/items/ItemDetail.tsx +++ b/web/src/components/items/ItemDetail.tsx @@ -64,9 +64,11 @@ export function ItemDetail({ } const typeColors: Record = { - part: { bg: "rgba(137,180,250,0.2)", color: "var(--ctp-blue)" }, - assembly: { bg: "rgba(166,227,161,0.2)", color: "var(--ctp-green)" }, - document: { bg: "rgba(249,226,175,0.2)", color: "var(--ctp-yellow)" }, + part: { bg: "rgba(166,227,161,0.2)", color: "var(--ctp-green)" }, + assembly: { bg: "rgba(203,166,247,0.2)", color: "var(--ctp-mauve)" }, + document: { bg: "rgba(137,180,250,0.2)", color: "var(--ctp-blue)" }, + purchased: { bg: "rgba(250,179,135,0.2)", color: "var(--ctp-peach)" }, + phantom: { bg: "rgba(127,132,156,0.2)", color: "var(--ctp-overlay1)" }, tooling: { bg: "rgba(243,139,168,0.2)", color: "var(--ctp-red)" }, }; const tc = typeColors[item.item_type] ?? { diff --git a/web/src/components/items/ItemTable.tsx b/web/src/components/items/ItemTable.tsx index 504f7bb..a8941a4 100644 --- a/web/src/components/items/ItemTable.tsx +++ b/web/src/components/items/ItemTable.tsx @@ -49,9 +49,11 @@ interface ItemTableProps { } const typeColors: Record = { - part: { bg: "rgba(137,180,250,0.2)", color: "var(--ctp-blue)" }, - assembly: { bg: "rgba(166,227,161,0.2)", color: "var(--ctp-green)" }, - document: { bg: "rgba(249,226,175,0.2)", color: "var(--ctp-yellow)" }, + part: { bg: "rgba(166,227,161,0.2)", color: "var(--ctp-green)" }, + assembly: { bg: "rgba(203,166,247,0.2)", color: "var(--ctp-mauve)" }, + document: { bg: "rgba(137,180,250,0.2)", color: "var(--ctp-blue)" }, + purchased: { bg: "rgba(250,179,135,0.2)", color: "var(--ctp-peach)" }, + phantom: { bg: "rgba(127,132,156,0.2)", color: "var(--ctp-overlay1)" }, tooling: { bg: "rgba(243,139,168,0.2)", color: "var(--ctp-red)" }, }; From 648c659e2beea701ef0784477bf9082538607ad8 Mon Sep 17 00:00:00 2001 From: Forbes Date: Fri, 13 Feb 2026 13:09:56 -0600 Subject: [PATCH 2/3] fix(web): use system font stack per style guide Fixes #66 Remove Inter and Roboto from font-family. The style guide specifies system fonts only: -apple-system, BlinkMacSystemFont, Segoe UI, system-ui, sans-serif. --- web/src/styles/global.css | 45 +++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/web/src/styles/global.css b/web/src/styles/global.css index 9d1e6bb..0713022 100644 --- a/web/src/styles/global.css +++ b/web/src/styles/global.css @@ -1,51 +1,54 @@ -@import './theme.css'; +@import "./theme.css"; *, *::before, *::after { - margin: 0; - padding: 0; - box-sizing: border-box; + margin: 0; + padding: 0; + box-sizing: border-box; } body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background-color: var(--ctp-base); - color: var(--ctp-text); - line-height: 1.6; - min-height: 100vh; + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + background-color: var(--ctp-base); + color: var(--ctp-text); + line-height: 1.6; + min-height: 100vh; } a { - color: var(--ctp-sapphire); - text-decoration: none; + color: var(--ctp-sapphire); + text-decoration: none; } a:hover { - color: var(--ctp-sky); - text-decoration: underline; + color: var(--ctp-sky); + text-decoration: underline; } /* Scrollbar */ ::-webkit-scrollbar { - width: 8px; - height: 8px; + width: 8px; + height: 8px; } ::-webkit-scrollbar-track { - background: var(--ctp-mantle); + background: var(--ctp-mantle); } ::-webkit-scrollbar-thumb { - background: var(--ctp-surface1); - border-radius: 4px; + background: var(--ctp-surface1); + border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { - background: var(--ctp-surface2); + background: var(--ctp-surface2); } /* Monospace */ -code, pre, .mono { - font-family: 'JetBrains Mono', 'Fira Code', monospace; +code, +pre, +.mono { + font-family: "JetBrains Mono", "Fira Code", monospace; } From 1f7960db5087285270259d39cae4c55dc3c8784e Mon Sep 17 00:00:00 2001 From: Forbes Date: Fri, 13 Feb 2026 13:10:57 -0600 Subject: [PATCH 3/3] feat: implement date segment type for part number generation Fixes #79 Implement the date segment type in the part number generator. Uses Go's time.Format with the segment's Value field as the layout string. - Default format: 20060102 (YYYYMMDD) when no Value is specified - Custom formats via Value field: "0601" (YYMM), "2006" (YYYY), etc. - Always uses UTC time - Add 3 tests: default format, custom YYMM format, year-only format --- internal/partnum/generator.go | 8 ++- internal/partnum/generator_test.go | 86 ++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/internal/partnum/generator.go b/internal/partnum/generator.go index 9cc7d21..31b3776 100644 --- a/internal/partnum/generator.go +++ b/internal/partnum/generator.go @@ -6,6 +6,7 @@ import ( "fmt" "regexp" "strings" + "time" "github.com/kindredsystems/silo/internal/schema" ) @@ -99,8 +100,11 @@ func (g *Generator) resolveSegment( return g.formatSerial(seg, next), nil case "date": - // TODO: implement date formatting - return "", fmt.Errorf("date segments not yet implemented") + layout := seg.Value + if layout == "" { + layout = "20060102" + } + return time.Now().UTC().Format(layout), nil default: return "", fmt.Errorf("unknown segment type: %s", seg.Type) diff --git a/internal/partnum/generator_test.go b/internal/partnum/generator_test.go index 00dcf2b..0e63ccb 100644 --- a/internal/partnum/generator_test.go +++ b/internal/partnum/generator_test.go @@ -3,7 +3,9 @@ package partnum import ( "context" "fmt" + "regexp" "testing" + "time" "github.com/kindredsystems/silo/internal/schema" ) @@ -165,3 +167,87 @@ func TestGenerateConstantSegment(t *testing.T) { t.Errorf("got %q, want %q", pn, "KS-0001") } } + +func TestGenerateDateSegmentDefault(t *testing.T) { + s := &schema.Schema{ + Name: "date-test", + Version: 1, + Separator: "-", + Segments: []schema.Segment{ + {Name: "date", Type: "date"}, + {Name: "serial", Type: "serial", Length: 3}, + }, + } + gen := NewGenerator(map[string]*schema.Schema{"date-test": s}, &mockSeqStore{}) + + pn, err := gen.Generate(context.Background(), Input{ + SchemaName: "date-test", + Values: map[string]string{}, + }) + if err != nil { + t.Fatalf("Generate returned error: %v", err) + } + + // Default format: YYYYMMDD-NNN + want := time.Now().UTC().Format("20060102") + "-001" + if pn != want { + t.Errorf("got %q, want %q", pn, want) + } +} + +func TestGenerateDateSegmentCustomFormat(t *testing.T) { + s := &schema.Schema{ + Name: "date-custom", + Version: 1, + Separator: "-", + Segments: []schema.Segment{ + {Name: "date", Type: "date", Value: "0601"}, + {Name: "serial", Type: "serial", Length: 4}, + }, + } + gen := NewGenerator(map[string]*schema.Schema{"date-custom": s}, &mockSeqStore{}) + + pn, err := gen.Generate(context.Background(), Input{ + SchemaName: "date-custom", + Values: map[string]string{}, + }) + if err != nil { + t.Fatalf("Generate returned error: %v", err) + } + + // Format "0601" produces YYMM + if matched, _ := regexp.MatchString(`^\d{4}-\d{4}$`, pn); !matched { + t.Errorf("got %q, want pattern YYMM-NNNN", pn) + } + + want := time.Now().UTC().Format("0601") + "-0001" + if pn != want { + t.Errorf("got %q, want %q", pn, want) + } +} + +func TestGenerateDateSegmentYearOnly(t *testing.T) { + s := &schema.Schema{ + Name: "date-year", + Version: 1, + Separator: "-", + Segments: []schema.Segment{ + {Name: "year", Type: "date", Value: "2006"}, + {Name: "serial", Type: "serial", Length: 4}, + }, + } + gen := NewGenerator(map[string]*schema.Schema{"date-year": s}, &mockSeqStore{}) + + pn, err := gen.Generate(context.Background(), Input{ + SchemaName: "date-year", + Values: map[string]string{}, + }) + if err != nil { + t.Fatalf("Generate returned error: %v", err) + } + + want := time.Now().UTC().Format("2006") + "-0001" + if pn != want { + t.Errorf("got %q, want %q", pn, want) + } +}