@almadar/ui 1.0.0 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,196 +1,2 @@
1
- // stores/filtering.ts
2
- function getDateString(value) {
3
- if (!value) return null;
4
- if (typeof value === "string") {
5
- const match = value.match(/^(\d{4}-\d{2}-\d{2})/);
6
- return match ? match[1] : null;
7
- }
8
- if (value instanceof Date) {
9
- return value.toISOString().split("T")[0];
10
- }
11
- return null;
12
- }
13
- function matchesFilter(record, filter) {
14
- const fieldToCompare = filter.targetField || filter.field;
15
- const recordValue = record[fieldToCompare];
16
- const filterValue = filter.value;
17
- const operator = filter.operator || "eq";
18
- if (filterValue === null || filterValue === void 0 || filterValue === "") {
19
- return true;
20
- }
21
- switch (operator) {
22
- case "eq":
23
- if (typeof recordValue === "string" && typeof filterValue === "string") {
24
- return recordValue.toLowerCase() === filterValue.toLowerCase();
25
- }
26
- return recordValue === filterValue;
27
- case "contains":
28
- if (typeof recordValue !== "string") return false;
29
- return recordValue.toLowerCase().includes(String(filterValue).toLowerCase());
30
- case "in":
31
- if (Array.isArray(filterValue)) {
32
- const normalizedFilterValues = filterValue.map(
33
- (v) => typeof v === "string" ? v.toLowerCase() : v
34
- );
35
- const normalizedRecordValue = typeof recordValue === "string" ? recordValue.toLowerCase() : recordValue;
36
- return normalizedFilterValues.includes(normalizedRecordValue);
37
- }
38
- return false;
39
- case "date_eq": {
40
- const recordDate = getDateString(recordValue);
41
- const filterDate = getDateString(filterValue);
42
- return Boolean(recordDate && filterDate && recordDate === filterDate);
43
- }
44
- case "date_gte": {
45
- const recordDate = getDateString(recordValue);
46
- const filterDate = getDateString(filterValue);
47
- return Boolean(recordDate && filterDate && recordDate >= filterDate);
48
- }
49
- case "date_lte": {
50
- const recordDate = getDateString(recordValue);
51
- const filterDate = getDateString(filterValue);
52
- return Boolean(recordDate && filterDate && recordDate <= filterDate);
53
- }
54
- case "search": {
55
- if (typeof filterValue !== "string" || !filterValue.trim()) {
56
- return true;
57
- }
58
- const searchTerm = filterValue.toLowerCase();
59
- return Object.values(record).some((value) => {
60
- if (value === null || value === void 0) return false;
61
- return String(value).toLowerCase().includes(searchTerm);
62
- });
63
- }
64
- default:
65
- return true;
66
- }
67
- }
68
- function applyFilters(records, entityFilters) {
69
- if (entityFilters.size === 0) return records;
70
- return records.filter((record) => {
71
- for (const [, filter] of entityFilters) {
72
- if (!matchesFilter(record, filter)) {
73
- return false;
74
- }
75
- }
76
- return true;
77
- });
78
- }
79
- function createFilter(field, value, operator = "eq", targetField) {
80
- return {
81
- field,
82
- value,
83
- operator,
84
- targetField: targetField || field
85
- };
86
- }
87
-
88
- // stores/entityStore.ts
89
- var entities = /* @__PURE__ */ new Map();
90
- var filters = /* @__PURE__ */ new Map();
91
- var listeners = /* @__PURE__ */ new Set();
92
- var idCounter = 0;
93
- function subscribe(listener) {
94
- listeners.add(listener);
95
- return () => listeners.delete(listener);
96
- }
97
- function notify() {
98
- listeners.forEach((listener) => listener());
99
- }
100
- function getEntities() {
101
- return entities;
102
- }
103
- function getEntity(id) {
104
- return entities.get(id);
105
- }
106
- function getByType(type) {
107
- const types = Array.isArray(type) ? type : [type];
108
- return [...entities.values()].filter((e) => types.includes(e.type));
109
- }
110
- function getAllEntities() {
111
- return [...entities.values()];
112
- }
113
- function getSingleton(type) {
114
- return [...entities.values()].find((e) => e.type === type);
115
- }
116
- function spawnEntity(config) {
117
- const id = config.id ?? `entity_${++idCounter}`;
118
- const entity = { ...config, id };
119
- entities = new Map(entities);
120
- entities.set(id, entity);
121
- notify();
122
- return id;
123
- }
124
- function updateEntity(id, updates) {
125
- const entity = entities.get(id);
126
- if (entity) {
127
- entities = new Map(entities);
128
- entities.set(id, { ...entity, ...updates });
129
- notify();
130
- }
131
- }
132
- function updateSingleton(type, updates) {
133
- const entity = getSingleton(type);
134
- if (entity) {
135
- updateEntity(entity.id, updates);
136
- }
137
- }
138
- function removeEntity(id) {
139
- if (entities.has(id)) {
140
- entities = new Map(entities);
141
- entities.delete(id);
142
- notify();
143
- }
144
- }
145
- function clearEntities() {
146
- entities = /* @__PURE__ */ new Map();
147
- notify();
148
- }
149
- function setFilter(entityType, field, value, operator = "eq", targetField) {
150
- filters = new Map(filters);
151
- const entityFilters = new Map(filters.get(entityType) || []);
152
- entityFilters.set(field, createFilter(field, value, operator, targetField));
153
- filters.set(entityType, entityFilters);
154
- notify();
155
- }
156
- function clearFilter(entityType, field) {
157
- const entityFilters = filters.get(entityType);
158
- if (entityFilters && entityFilters.has(field)) {
159
- filters = new Map(filters);
160
- const newFilters = new Map(entityFilters);
161
- newFilters.delete(field);
162
- filters.set(entityType, newFilters);
163
- notify();
164
- }
165
- }
166
- function clearAllFilters(entityType) {
167
- if (filters.has(entityType)) {
168
- filters = new Map(filters);
169
- filters.set(entityType, /* @__PURE__ */ new Map());
170
- notify();
171
- }
172
- }
173
- function getFilters(entityType) {
174
- return filters.get(entityType) || /* @__PURE__ */ new Map();
175
- }
176
- function getByTypeFiltered(type) {
177
- const types = Array.isArray(type) ? type : [type];
178
- let result = [...entities.values()].filter((e) => types.includes(e.type));
179
- for (const t of types) {
180
- const typeFilters = filters.get(t);
181
- if (typeFilters && typeFilters.size > 0) {
182
- result = applyFilters(result, typeFilters);
183
- }
184
- }
185
- return result;
186
- }
187
- function getSnapshot() {
188
- return entities;
189
- }
190
- function getFilterSnapshot() {
191
- return filters;
192
- }
193
-
194
- export { applyFilters, clearAllFilters, clearEntities, clearFilter, createFilter, getAllEntities, getByType, getByTypeFiltered, getDateString, getEntities, getEntity, getFilterSnapshot, getFilters, getSingleton, getSnapshot, matchesFilter, removeEntity, setFilter, spawnEntity, subscribe, updateEntity, updateSingleton };
195
- //# sourceMappingURL=index.js.map
196
- //# sourceMappingURL=index.js.map
1
+ export { applyFilters, clearAllFilters, clearEntities, clearFilter, createFilter, getAllEntities, getByType, getByTypeFiltered, getDateString, getEntities, getEntity, getFilterSnapshot, getFilters, getSingleton, getSnapshot, matchesFilter, removeEntity, setFilter, spawnEntity, subscribe, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
2
+ import '../chunk-S7EYY36U.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "1.0.0",
3
+ "version": "1.0.10",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",
@@ -60,8 +60,9 @@
60
60
  "remark-gfm": "^4.0.1",
61
61
  "remark-math": "^6.0.0",
62
62
  "react-force-graph-2d": "^1.28.0",
63
- "@almadar/core": "1.0.0",
64
- "@almadar/patterns": "1.0.0"
63
+ "@almadar/evaluator": "1.0.10",
64
+ "@almadar/core": "1.0.10",
65
+ "@almadar/patterns": "1.0.10"
65
66
  },
66
67
  "peerDependencies": {
67
68
  "react": "^18.0.0",
@@ -75,15 +76,11 @@
75
76
  "@types/react": "^18.3.0",
76
77
  "@types/react-dom": "^18.3.0",
77
78
  "@types/react-syntax-highlighter": "^15.5.11",
78
- "@storybook/addon-essentials": "^8.0.0",
79
- "@storybook/addon-interactions": "^8.0.0",
80
- "@storybook/addon-links": "^8.0.0",
81
- "@storybook/addon-themes": "^8.0.0",
82
- "@storybook/blocks": "^8.0.0",
83
- "@storybook/react": "^8.0.0",
84
- "@storybook/react-vite": "^8.0.0",
85
- "@storybook/test": "^8.0.0",
86
- "storybook": "^8.0.0",
79
+ "@storybook/addon-links": "^10.2.6",
80
+ "@storybook/addon-themes": "^10.2.6",
81
+ "@storybook/react": "^10.2.6",
82
+ "@storybook/react-vite": "^10.2.6",
83
+ "storybook": "^10.2.6",
87
84
  "@vitejs/plugin-react": "^4.2.0",
88
85
  "autoprefixer": "^10.4.0",
89
86
  "postcss": "^8.4.35",
@@ -96,7 +93,8 @@
96
93
  "@testing-library/react": "^14.2.0",
97
94
  "@testing-library/jest-dom": "^6.4.0",
98
95
  "@vitest/ui": "^1.4.0",
99
- "jsdom": "^24.0.0"
96
+ "jsdom": "^24.0.0",
97
+ "@storybook/addon-docs": "^10.2.6"
100
98
  },
101
99
  "repository": {
102
100
  "type": "git",
@@ -98,6 +98,10 @@
98
98
  --focus-ring-width: 2px;
99
99
  --focus-ring-offset: 2px;
100
100
  --focus-ring-color: #14b8a6;
101
+
102
+ /* Apply background and foreground colors */
103
+ background-color: var(--color-background);
104
+ color: var(--color-foreground);
101
105
  }
102
106
 
103
107
  /* ==========================================================================
@@ -193,4 +197,8 @@
193
197
  --focus-ring-width: 2px;
194
198
  --focus-ring-offset: 2px;
195
199
  --focus-ring-color: #14b8a6;
200
+
201
+ /* Apply background and foreground colors */
202
+ background-color: var(--color-background);
203
+ color: var(--color-foreground);
196
204
  }
package/themes/index.css CHANGED
@@ -9,3 +9,4 @@
9
9
  @import "./wireframe.css";
10
10
  @import "./minimalist.css";
11
11
  @import "./almadar.css";
12
+ @import "./trait-wars.css";
@@ -97,6 +97,10 @@
97
97
  --focus-ring-width: 2px;
98
98
  --focus-ring-offset: 2px;
99
99
  --focus-ring-color: #18181b;
100
+
101
+ /* Apply background and foreground colors */
102
+ background-color: var(--color-background);
103
+ color: var(--color-foreground);
100
104
  }
101
105
 
102
106
  /* ==========================================================================
@@ -190,4 +194,8 @@
190
194
  --focus-ring-width: 2px;
191
195
  --focus-ring-offset: 2px;
192
196
  --focus-ring-color: #fafafa;
197
+
198
+ /* Apply background and foreground colors */
199
+ background-color: var(--color-background);
200
+ color: var(--color-foreground);
193
201
  }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Trait Wars Theme — "Illuminated Manuscript Futurism"
3
+ *
4
+ * Dune meets Book of Kells: aged parchment surfaces, gold celtic filigree
5
+ * borders, warm ivory text, faction-coded accents. Dark mode only — this
6
+ * is a game UI, not a productivity app.
7
+ *
8
+ * Surface hierarchy (darkest → lightest):
9
+ * background → card/surface → elevated (hover) → muted
10
+ */
11
+
12
+ /* Google Fonts — Cinzel (400, 500, 700) */
13
+ @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;700&display=swap');
14
+
15
+ /* ==========================================================================
16
+ * DARK MODE (primary — game is always dark)
17
+ * ========================================================================== */
18
+ [data-theme="trait-wars-dark"] {
19
+ /* Shadows — warm gold glow instead of cool blue */
20
+ --shadow-main:
21
+ 0 4px 14px rgba(201, 168, 76, 0.10), 0 1px 3px rgba(0, 0, 0, 0.20);
22
+ --shadow-sm: 0 2px 4px rgba(201, 168, 76, 0.06);
23
+ --shadow-lg:
24
+ 0 8px 30px rgba(201, 168, 76, 0.15), 0 4px 10px rgba(0, 0, 0, 0.15);
25
+ --shadow-inner: inset 0 1px 3px rgba(0, 0, 0, 0.25);
26
+ --shadow-none: none;
27
+ --shadow-hover:
28
+ 0 12px 40px rgba(201, 168, 76, 0.20), 0 4px 12px rgba(234, 179, 8, 0.10);
29
+ --shadow-active: 0 2px 8px rgba(201, 168, 76, 0.15);
30
+
31
+ /* Border radius — slightly rounded, not too modern */
32
+ --radius-none: 0px;
33
+ --radius-sm: 4px;
34
+ --radius-md: 6px;
35
+ --radius-lg: 8px;
36
+ --radius-xl: 12px;
37
+ --radius-full: 9999px;
38
+
39
+ /* Border width — thin default, thick for emphasis */
40
+ --border-width: 1px;
41
+ --border-width-thin: 1px;
42
+ --border-width-thick: 2px;
43
+
44
+ /* ======================================================================
45
+ * CORE COLORS
46
+ * ====================================================================== */
47
+
48
+ /* Primary — Gold (actions, interactive elements) */
49
+ --color-primary: #c9a84c;
50
+ --color-primary-hover: #eab308;
51
+ --color-primary-foreground: #1a1410;
52
+
53
+ /* Secondary — Dark parchment (neutral backgrounds) */
54
+ --color-secondary: #2a2118;
55
+ --color-secondary-hover: #3a2f22;
56
+ --color-secondary-foreground: #e8dcc8;
57
+
58
+ /* Accent — Teal resonance (faction, energy, selected) */
59
+ --color-accent: #14b8a6;
60
+ --color-accent-foreground: #042f2e;
61
+
62
+ /* Muted — Dim parchment (disabled, tertiary) */
63
+ --color-muted: #3a2f22;
64
+ --color-muted-foreground: #7a6a50;
65
+
66
+ /* Surfaces */
67
+ --color-background: #1a1410;
68
+ --color-foreground: #e8dcc8;
69
+ --color-card: #2a2118;
70
+ --color-card-foreground: #e8dcc8;
71
+ --color-surface: #2a2118;
72
+
73
+ /* Borders & Inputs */
74
+ --color-border: #5a4a36;
75
+ --color-input: #3a2f22;
76
+ --color-ring: #c9a84c;
77
+
78
+ /* Semantic colors — warmed to match parchment palette */
79
+ --color-error: #c04040;
80
+ --color-error-foreground: #e8dcc8;
81
+ --color-success: #4a9e4a;
82
+ --color-success-foreground: #e8dcc8;
83
+ --color-warning: #d97706;
84
+ --color-warning-foreground: #1a1410;
85
+ --color-info: #14b8a6;
86
+ --color-info-foreground: #e8dcc8;
87
+
88
+ /* ======================================================================
89
+ * GAME-SPECIFIC TOKENS (extend the base theme system)
90
+ * ====================================================================== */
91
+
92
+ /* Gold hierarchy (bright → dim) */
93
+ --tw-gold: #eab308;
94
+ --tw-gold-mid: #c9a84c;
95
+ --tw-gold-dim: #8a7340;
96
+ --tw-gold-dark: #5a4a36;
97
+
98
+ /* Parchment text hierarchy (bright → dim) */
99
+ --tw-text-primary: #e8dcc8;
100
+ --tw-text-secondary: #b8a88c;
101
+ --tw-text-dim: #7a6a50;
102
+
103
+ /* Surface hierarchy (light → dark) */
104
+ --tw-surface-elevated: #3a2f22;
105
+ --tw-surface-hover: #4a3d2e;
106
+
107
+ /* Faction: Resonator (player) */
108
+ --tw-faction-resonator: #7c3aed;
109
+ --tw-faction-resonator-glow: rgba(124, 58, 237, 0.3);
110
+
111
+ /* Faction: Dominion (enemy) */
112
+ --tw-faction-dominion: #b91c1c;
113
+ --tw-faction-dominion-glow: rgba(185, 28, 28, 0.3);
114
+
115
+ /* Faction: Neutral */
116
+ --tw-faction-neutral: #78716c;
117
+
118
+ /* Tier colors (bronze → illuminated) */
119
+ --tw-tier-1: #8B7355;
120
+ --tw-tier-2: #A8A8A8;
121
+ --tw-tier-3: #c9a84c;
122
+ --tw-tier-4: #eab308;
123
+
124
+ /* Combat */
125
+ --tw-health: #c04040;
126
+ --tw-health-bg: rgba(192, 64, 64, 0.2);
127
+ --tw-heal: #4a9e4a;
128
+ --tw-heal-bg: rgba(74, 158, 74, 0.2);
129
+ --tw-mana: #7c5cbf;
130
+ --tw-mana-bg: rgba(124, 92, 191, 0.2);
131
+
132
+ /* ======================================================================
133
+ * TYPOGRAPHY
134
+ * ====================================================================== */
135
+ --font-family:
136
+ "Cinzel", "Palatino Linotype", "Book Antiqua", Palatino, Georgia, serif;
137
+ --font-weight-normal: 400;
138
+ --font-weight-medium: 500;
139
+ --font-weight-bold: 700;
140
+ --letter-spacing: 0.01em;
141
+ --line-height: 1.5;
142
+
143
+ /* Icon styling — gold tint */
144
+ --icon-stroke-width: 1.75;
145
+ --icon-color: #c9a84c;
146
+
147
+ /* Transitions — slightly slower for gravitas */
148
+ --transition-fast: 150ms;
149
+ --transition-normal: 300ms;
150
+ --transition-slow: 500ms;
151
+ --transition-timing: cubic-bezier(0.4, 0, 0.2, 1);
152
+
153
+ /* Hover/Active transforms — subtle, dignified */
154
+ --hover-scale: 1.01;
155
+ --hover-translate-y: -1px;
156
+ --hover-translate-x: 0;
157
+ --active-scale: 0.99;
158
+ --active-translate-y: 0;
159
+
160
+ /* Focus ring — gold */
161
+ --focus-ring-width: 2px;
162
+ --focus-ring-offset: 2px;
163
+ --focus-ring-color: #c9a84c;
164
+
165
+ /* Apply background and foreground colors */
166
+ background-color: var(--color-background);
167
+ color: var(--color-foreground);
168
+ }
169
+
170
+ /* ==========================================================================
171
+ * LIGHT MODE (alias to dark — game has no light mode)
172
+ * ========================================================================== */
173
+ [data-theme="trait-wars-light"] {
174
+ /* Trait Wars is dark-only. Light selector inherits dark values so the
175
+ theme switcher doesn't break if someone selects "light". */
176
+ }
@@ -94,6 +94,10 @@
94
94
  --focus-ring-width: 2px;
95
95
  --focus-ring-offset: 2px;
96
96
  --focus-ring-color: #000000;
97
+
98
+ /* Apply background and foreground colors */
99
+ background-color: var(--color-background);
100
+ color: var(--color-foreground);
97
101
  }
98
102
 
99
103
  /* ==========================================================================
@@ -185,4 +189,8 @@
185
189
  --focus-ring-width: 2px;
186
190
  --focus-ring-offset: 2px;
187
191
  --focus-ring-color: #ffffff;
192
+
193
+ /* Apply background and foreground colors */
194
+ background-color: var(--color-background);
195
+ color: var(--color-foreground);
188
196
  }