@nixxie-cms/core 1.0.0 → 1.0.1

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.
Files changed (186) hide show
  1. package/README.md +2 -2
  2. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +4 -4
  3. package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +4 -4
  4. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
  5. package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
  6. package/context/dist/nixxie-cms-core-context.cjs.js +2 -2
  7. package/context/dist/nixxie-cms-core-context.esm.js +2 -2
  8. package/dist/{CreateItemDialog-33335548.esm.js → CreateItemDialog-7008b050.esm.js} +1 -1
  9. package/dist/{CreateItemDialog-56cf59b7.cjs.js → CreateItemDialog-a0cab315.cjs.js} +1 -1
  10. package/dist/{PageContainer-7db73317.esm.js → PageContainer-5ae731cc.esm.js} +25 -18
  11. package/dist/{PageContainer-27c27f10.cjs.js → PageContainer-abd7159f.cjs.js} +25 -18
  12. package/dist/{admin-meta-graphql-6f7f5331.esm.js → admin-meta-graphql-0e6e606e.esm.js} +1 -1
  13. package/dist/{admin-meta-graphql-c8f926e9.cjs.js → admin-meta-graphql-306c224a.cjs.js} +1 -1
  14. package/dist/{context-3132c3ed.esm.js → context-af9957ed.esm.js} +2 -2
  15. package/dist/{context-e7a45152.cjs.js → context-b5204629.cjs.js} +2 -2
  16. package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
  17. package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
  18. package/dist/declarations/src/helpers.d.ts.map +1 -1
  19. package/dist/declarations/src/index.d.ts +1 -0
  20. package/dist/declarations/src/index.d.ts.map +1 -1
  21. package/dist/declarations/src/internal-unstable/admin-ui/id-field-view.d.ts.map +1 -0
  22. package/dist/declarations/src/internal-unstable/admin-ui/pages/App/index.d.ts.map +1 -0
  23. package/dist/declarations/src/internal-unstable/admin-ui/pages/CreateItemPage/index.d.ts.map +1 -0
  24. package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -0
  25. package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -0
  26. package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -0
  27. package/dist/declarations/src/internal-unstable/admin-ui/pages/NoAccessPage/index.d.ts.map +1 -0
  28. package/dist/declarations/src/internal-unstable/artifacts.d.ts.map +1 -0
  29. package/dist/declarations/src/lib/core/initialise-lists.d.ts +1 -1
  30. package/dist/declarations/src/schema.d.ts.map +1 -1
  31. package/dist/declarations/src/types/config/index.d.ts +60 -1
  32. package/dist/declarations/src/types/config/index.d.ts.map +1 -1
  33. package/dist/declarations/src/types/config/lists.d.ts +4 -4
  34. package/dist/declarations/src/types/context.d.ts +150 -0
  35. package/dist/declarations/src/types/context.d.ts.map +1 -1
  36. package/dist/declarations/src/types/next-fields.d.ts +1 -1
  37. package/dist/{express-e9ed9a7d.cjs.js → express-455ae20c.cjs.js} +1 -1
  38. package/dist/{express-6743b918.esm.js → express-7559ca2d.esm.js} +1 -1
  39. package/dist/{index-ac01583b.cjs.js → index-89635494.cjs.js} +4 -4
  40. package/dist/{index-24b78415.esm.js → index-baa799e0.esm.js} +4 -4
  41. package/dist/nixxie-cms-core.cjs.js +104 -77
  42. package/dist/nixxie-cms-core.esm.js +104 -77
  43. package/dist/{non-null-graphql-5315718c.esm.js → non-null-graphql-a84ed64d.esm.js} +1 -1
  44. package/dist/{non-null-graphql-17b83ddc.cjs.js → non-null-graphql-add6bb3d.cjs.js} +1 -1
  45. package/dist/{resolve-hooks-66fe8a8e.cjs.js → resolve-hooks-165a9ce2.cjs.js} +1 -1
  46. package/dist/{resolve-hooks-17aafd37.esm.js → resolve-hooks-6813a045.esm.js} +2 -2
  47. package/dist/{system-dfec2f0a.esm.js → system-03e49e4f.esm.js} +8 -4
  48. package/dist/{system-48c5f6df.cjs.js → system-a321642d.cjs.js} +8 -4
  49. package/dist/{useFilter-0b5a1ee6.esm.js → useFilter-9b6db1f9.esm.js} +1 -1
  50. package/dist/{useFilter-1a4e6900.cjs.js → useFilter-acc9d413.cjs.js} +1 -1
  51. package/fields/dist/nixxie-cms-core-fields.cjs.js +16 -16
  52. package/fields/dist/nixxie-cms-core-fields.esm.js +17 -17
  53. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +3 -3
  54. package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +3 -3
  55. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +1 -1
  56. package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +1 -1
  57. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +3 -3
  58. package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +3 -3
  59. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +4 -4
  60. package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +4 -4
  61. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +1 -1
  62. package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +1 -1
  63. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +1 -1
  64. package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +1 -1
  65. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.d.ts +2 -0
  66. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.cjs.js +244 -0
  67. package/internal-unstable/admin-ui/id-field-view/dist/nixxie-cms-core-internal-unstable-admin-ui-id-field-view.esm.js +235 -0
  68. package/internal-unstable/admin-ui/id-field-view/package.json +4 -0
  69. package/internal-unstable/admin-ui/next-config/package.json +4 -0
  70. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.d.ts +2 -0
  71. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +59 -0
  72. package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +55 -0
  73. package/internal-unstable/admin-ui/pages/App/package.json +4 -0
  74. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.d.ts +2 -0
  75. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +116 -0
  76. package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +112 -0
  77. package/internal-unstable/admin-ui/pages/CreateItemPage/package.json +4 -0
  78. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.d.ts +2 -0
  79. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +336 -0
  80. package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +332 -0
  81. package/internal-unstable/admin-ui/pages/HomePage/package.json +4 -0
  82. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.d.ts +2 -0
  83. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +463 -0
  84. package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +455 -0
  85. package/internal-unstable/admin-ui/pages/ItemPage/package.json +4 -0
  86. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.d.ts +2 -0
  87. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +1195 -0
  88. package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +1187 -0
  89. package/internal-unstable/admin-ui/pages/ListPage/package.json +4 -0
  90. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.d.ts +2 -0
  91. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.cjs.js +40 -0
  92. package/internal-unstable/admin-ui/pages/NoAccessPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-NoAccessPage.esm.js +35 -0
  93. package/internal-unstable/admin-ui/pages/NoAccessPage/package.json +4 -0
  94. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.d.ts +2 -0
  95. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +51 -0
  96. package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +38 -0
  97. package/internal-unstable/artifacts/package.json +4 -0
  98. package/package.json +44 -44
  99. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +15 -15
  100. package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +15 -15
  101. package/scripts/dist/nixxie-cms-core-scripts.cjs.js +3 -3
  102. package/scripts/dist/nixxie-cms-core-scripts.esm.js +3 -3
  103. package/src/admin-ui/admin-meta-graphql.ts +168 -168
  104. package/src/admin-ui/components/CommandPalette.tsx +433 -431
  105. package/src/admin-ui/components/Navigation.tsx +389 -385
  106. package/src/admin-ui/components/PageContainer.tsx +311 -310
  107. package/src/admin-ui/components/WelcomeDialog.tsx +1 -1
  108. package/src/admin-ui/context.tsx +338 -338
  109. package/src/admin-ui/templates/app.ts +60 -60
  110. package/src/admin-ui/templates/create-item.ts +5 -5
  111. package/src/admin-ui/templates/home.ts +2 -2
  112. package/src/admin-ui/templates/item.tsx +5 -5
  113. package/src/admin-ui/templates/list.tsx +5 -5
  114. package/src/admin-ui/templates/no-access.ts +7 -7
  115. package/src/fields/types/bigInt/index.ts +181 -181
  116. package/src/fields/types/bytes/index.ts +275 -275
  117. package/src/fields/types/calendarDay/index.ts +194 -194
  118. package/src/fields/types/checkbox/index.ts +76 -76
  119. package/src/fields/types/decimal/index.ts +182 -182
  120. package/src/fields/types/file/index.ts +168 -168
  121. package/src/fields/types/float/index.ts +133 -133
  122. package/src/fields/types/image/index.ts +244 -244
  123. package/src/fields/types/integer/index.ts +156 -156
  124. package/src/fields/types/json/index.ts +77 -77
  125. package/src/fields/types/multiselect/index.ts +212 -212
  126. package/src/fields/types/password/index.ts +241 -241
  127. package/src/fields/types/relationship/index.ts +381 -381
  128. package/src/fields/types/relationship/views/RelationshipTable.tsx +190 -190
  129. package/src/fields/types/select/index.ts +226 -226
  130. package/src/fields/types/text/index.ts +207 -207
  131. package/src/fields/types/timestamp/index.ts +116 -116
  132. package/src/fields/types/virtual/index.ts +108 -108
  133. package/src/helpers.ts +342 -316
  134. package/src/index.ts +4 -0
  135. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.tsx +167 -167
  136. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.tsx +22 -22
  137. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.tsx +71 -71
  138. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.tsx +333 -333
  139. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/common.tsx +358 -358
  140. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.tsx +483 -483
  141. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/FilterAdd.tsx +221 -221
  142. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/PaginationControls.tsx +170 -170
  143. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/Tag.tsx +72 -72
  144. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.tsx +1006 -1006
  145. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.tsx +24 -24
  146. package/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.ts +5 -5
  147. package/src/lib/context/createContext.ts +165 -161
  148. package/src/lib/core/initialise-lists.ts +1097 -1097
  149. package/src/lib/id-field.ts +214 -214
  150. package/src/lib/telemetry.ts +342 -342
  151. package/src/schema.ts +237 -233
  152. package/src/scripts/telemetry.ts +1 -1
  153. package/src/types/config/index.ts +400 -333
  154. package/src/types/config/lists.ts +4 -4
  155. package/src/types/context.ts +700 -530
  156. package/src/types/next-fields.ts +499 -499
  157. package/src/types/telemetry.ts +51 -51
  158. package/tests/telemetry.test.ts +361 -361
  159. package/CHANGELOG.md +0 -3158
  160. package/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view/package.json +0 -4
  161. package/___internal-do-not-use-will-break-in-patch/admin-ui/next-config/package.json +0 -4
  162. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/package.json +0 -4
  163. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/package.json +0 -4
  164. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/package.json +0 -4
  165. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/package.json +0 -4
  166. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/package.json +0 -4
  167. package/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/package.json +0 -4
  168. package/___internal-do-not-use-will-break-in-patch/artifacts/package.json +0 -4
  169. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.d.ts.map +0 -1
  170. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.d.ts.map +0 -1
  171. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.d.ts.map +0 -1
  172. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.d.ts.map +0 -1
  173. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.d.ts.map +0 -1
  174. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.d.ts.map +0 -1
  175. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.d.ts.map +0 -1
  176. package/dist/declarations/src/___internal-do-not-use-will-break-in-patch/artifacts.d.ts.map +0 -1
  177. /package/dist/{common-1a350e11.cjs.js → common-5933f758.cjs.js} +0 -0
  178. /package/dist/{common-29fc82e6.esm.js → common-ea5c441a.esm.js} +0 -0
  179. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/id-field-view.d.ts +0 -0
  180. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/App/index.d.ts +0 -0
  181. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/CreateItemPage/index.d.ts +0 -0
  182. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/HomePage/index.d.ts +0 -0
  183. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ItemPage/index.d.ts +0 -0
  184. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/ListPage/index.d.ts +0 -0
  185. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/admin-ui/pages/NoAccessPage/index.d.ts +0 -0
  186. /package/dist/declarations/src/{___internal-do-not-use-will-break-in-patch → internal-unstable}/artifacts.d.ts +0 -0
@@ -1,310 +1,311 @@
1
- import NextHead from 'next/head'
2
- import { type HTMLAttributes, type ReactNode, useEffect, useState } from 'react'
3
-
4
- import { css } from '@keystar/ui/style'
5
-
6
- import { Logo } from './Logo'
7
- import { Navigation } from './Navigation'
8
- import { CommandPalette } from './CommandPalette'
9
-
10
- const SIDEBAR_WIDTH = 256
11
- const TOPBAR_HEIGHT = 52
12
-
13
- export function PageWrapper(props: HTMLAttributes<HTMLElement>) {
14
- return (
15
- <div
16
- className={css({
17
- display: 'flex',
18
- height: '100vh',
19
- overflow: 'hidden',
20
- backgroundColor: '#fafafa',
21
- fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
22
- })}
23
- {...props}
24
- />
25
- )
26
- }
27
-
28
- // ---- Mobile overlay ----
29
- function Backdrop({ isVisible, onClick }: { isVisible: boolean; onClick: () => void }) {
30
- return (
31
- <div
32
- onClick={onClick}
33
- aria-hidden={!isVisible}
34
- className={css({
35
- position: 'fixed',
36
- inset: 0,
37
- backgroundColor: 'rgba(10,10,10,0.35)',
38
- zIndex: 40,
39
- transition: 'opacity 200ms',
40
- opacity: isVisible ? 1 : 0,
41
- pointerEvents: isVisible ? 'auto' : 'none',
42
- backdropFilter: 'blur(2px)',
43
- '@media (min-width: 768px)': { display: 'none' },
44
- })}
45
- />
46
- )
47
- }
48
-
49
- // ---- Sidebar — pure white, precise ----
50
- function Sidebar({
51
- isOpen,
52
- onClose,
53
- onCmdK,
54
- }: {
55
- isOpen: boolean
56
- onClose: () => void
57
- onCmdK: () => void
58
- }) {
59
- return (
60
- <>
61
- <Backdrop isVisible={isOpen} onClick={onClose} />
62
- <aside
63
- className={css({
64
- position: 'fixed',
65
- top: 0,
66
- left: 0,
67
- bottom: 0,
68
- width: SIDEBAR_WIDTH,
69
- zIndex: 50,
70
- display: 'flex',
71
- flexDirection: 'column',
72
- backgroundColor: '#ffffff',
73
- borderRight: '1px solid #ebebeb',
74
- transform: isOpen ? 'translateX(0)' : `translateX(-${SIDEBAR_WIDTH}px)`,
75
- transition: 'transform 220ms cubic-bezier(0.4,0,0.2,1)',
76
-
77
- '@media (min-width: 768px)': {
78
- position: 'relative',
79
- transform: 'translateX(0)',
80
- flexShrink: 0,
81
- },
82
- })}
83
- >
84
- {/* Logo bar */}
85
- <div
86
- className={css({
87
- display: 'flex',
88
- alignItems: 'center',
89
- height: TOPBAR_HEIGHT,
90
- paddingInline: '16px',
91
- borderBottom: '1px solid #f2f2f2',
92
- flexShrink: 0,
93
- })}
94
- >
95
- <Logo />
96
- </div>
97
-
98
- {/* Nav scrollable area */}
99
- <div
100
- className={css({
101
- flex: 1,
102
- overflowY: 'auto',
103
- overflowX: 'hidden',
104
- WebkitOverflowScrolling: 'touch',
105
- '&::-webkit-scrollbar': { width: 3 },
106
- '&::-webkit-scrollbar-thumb': { background: '#ebebeb', borderRadius: 3 },
107
- })}
108
- >
109
- <Navigation onNavItemClick={onClose} onCmdK={onCmdK} />
110
- </div>
111
- </aside>
112
- </>
113
- )
114
- }
115
-
116
- // ---- Top bar ----
117
- function TopBar({
118
- header,
119
- onMenuClick,
120
- isSidebarOpen,
121
- }: {
122
- header: ReactNode
123
- onMenuClick: () => void
124
- isSidebarOpen: boolean
125
- }) {
126
- return (
127
- <header
128
- className={css({
129
- display: 'flex',
130
- alignItems: 'center',
131
- height: TOPBAR_HEIGHT,
132
- paddingInline: '24px',
133
- gap: '14px',
134
- backgroundColor: '#ffffff',
135
- borderBottom: '1px solid #ebebeb',
136
- flexShrink: 0,
137
- zIndex: 30,
138
- })}
139
- >
140
- {/* Mobile menu button */}
141
- <button
142
- onClick={onMenuClick}
143
- aria-label={isSidebarOpen ? 'Close menu' : 'Open menu'}
144
- aria-expanded={isSidebarOpen}
145
- className={css({
146
- display: 'inline-flex',
147
- alignItems: 'center',
148
- justifyContent: 'center',
149
- width: 32,
150
- height: 32,
151
- borderRadius: 6,
152
- border: '1px solid #ebebeb',
153
- background: 'transparent',
154
- cursor: 'pointer',
155
- flexShrink: 0,
156
- color: '#a3a3a3',
157
- transition: 'color 130ms, background 130ms',
158
- '&:hover': { background: '#f5f5f5', color: '#0a0a0a' },
159
- '@media (min-width: 768px)': { display: 'none' },
160
- })}
161
- >
162
- <svg width="15" height="15" viewBox="0 0 15 15" fill="none">
163
- {isSidebarOpen ? (
164
- <path
165
- d="M3 3L12 12M12 3L3 12"
166
- stroke="currentColor"
167
- strokeWidth="1.4"
168
- strokeLinecap="round"
169
- />
170
- ) : (
171
- <>
172
- <line
173
- x1="2"
174
- y1="4.5"
175
- x2="13"
176
- y2="4.5"
177
- stroke="currentColor"
178
- strokeWidth="1.4"
179
- strokeLinecap="round"
180
- />
181
- <line
182
- x1="2"
183
- y1="7.5"
184
- x2="13"
185
- y2="7.5"
186
- stroke="currentColor"
187
- strokeWidth="1.4"
188
- strokeLinecap="round"
189
- />
190
- <line
191
- x1="2"
192
- y1="10.5"
193
- x2="13"
194
- y2="10.5"
195
- stroke="currentColor"
196
- strokeWidth="1.4"
197
- strokeLinecap="round"
198
- />
199
- </>
200
- )}
201
- </svg>
202
- </button>
203
-
204
- {/* Header content (breadcrumbs / title / actions) */}
205
- <div
206
- className={css({
207
- display: 'flex',
208
- alignItems: 'center',
209
- justifyContent: 'space-between',
210
- flex: 1,
211
- minWidth: 0,
212
- gap: '12px',
213
- })}
214
- >
215
- {header}
216
- </div>
217
- </header>
218
- )
219
- }
220
-
221
- // ---- Main content area ----
222
- function MainContent(props: HTMLAttributes<HTMLElement>) {
223
- return (
224
- <main
225
- className={css({
226
- flex: 1,
227
- display: 'flex',
228
- flexDirection: 'column',
229
- overflow: 'hidden',
230
- minWidth: 0,
231
- minHeight: 0,
232
- })}
233
- {...props}
234
- />
235
- )
236
- }
237
-
238
- function ContentScroller(props: HTMLAttributes<HTMLDivElement>) {
239
- return (
240
- <div
241
- data-nixxie-content=""
242
- className={css({
243
- flex: 1,
244
- overflowY: 'auto',
245
- overflowX: 'hidden',
246
- WebkitOverflowScrolling: 'touch',
247
- '&::-webkit-scrollbar': { width: 5 },
248
- '&::-webkit-scrollbar-thumb': { background: '#e8e8e8', borderRadius: 4 },
249
- '&::-webkit-scrollbar-thumb:hover': { background: '#d4d4d4' },
250
- })}
251
- {...props}
252
- />
253
- )
254
- }
255
-
256
- // ---- Public API ----
257
- type PageContainerProps = {
258
- children: ReactNode
259
- header: ReactNode
260
- title?: string
261
- }
262
-
263
- export function PageContainer({ children, header, title }: PageContainerProps) {
264
- const [isSidebarOpen, setSidebarOpen] = useState(false)
265
- const [cmdOpen, setCmdOpen] = useState(false)
266
-
267
- useEffect(() => {
268
- function onResize() {
269
- if (window.innerWidth >= 768) setSidebarOpen(false)
270
- }
271
- window.addEventListener('resize', onResize)
272
- return () => window.removeEventListener('resize', onResize)
273
- }, [])
274
-
275
- useEffect(() => {
276
- function onKeyDown(e: KeyboardEvent) {
277
- if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
278
- e.preventDefault()
279
- setCmdOpen(v => !v)
280
- }
281
- }
282
- window.addEventListener('keydown', onKeyDown)
283
- return () => window.removeEventListener('keydown', onKeyDown)
284
- }, [])
285
-
286
- return (
287
- <PageWrapper>
288
- <NextHead>
289
- <title key="title">{title ? `Nixxie – ${title}` : 'Nixxie'}</title>
290
- </NextHead>
291
-
292
- <Sidebar
293
- isOpen={isSidebarOpen}
294
- onClose={() => setSidebarOpen(false)}
295
- onCmdK={() => setCmdOpen(v => !v)}
296
- />
297
-
298
- <MainContent>
299
- <TopBar
300
- header={header}
301
- onMenuClick={() => setSidebarOpen(v => !v)}
302
- isSidebarOpen={isSidebarOpen}
303
- />
304
- <ContentScroller>{children}</ContentScroller>
305
- </MainContent>
306
-
307
- <CommandPalette isOpen={cmdOpen} onClose={() => setCmdOpen(false)} />
308
- </PageWrapper>
309
- )
310
- }
1
+ import NextHead from 'next/head'
2
+ import { type HTMLAttributes, type ReactNode, useEffect, useState } from 'react'
3
+
4
+ import { css } from '@keystar/ui/style'
5
+
6
+ import { Logo } from './Logo'
7
+ import { Navigation } from './Navigation'
8
+ import { CommandPalette } from './CommandPalette'
9
+
10
+ const SIDEBAR_WIDTH = 256
11
+ const TOPBAR_HEIGHT = 52
12
+
13
+ export function PageWrapper(props: HTMLAttributes<HTMLElement>) {
14
+ return (
15
+ <div
16
+ className={css({
17
+ display: 'flex',
18
+ height: '100vh',
19
+ overflow: 'hidden',
20
+ backgroundColor: '#fafafa',
21
+ fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
22
+ })}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ // ---- Mobile overlay ----
29
+ function Backdrop({ isVisible, onClick }: { isVisible: boolean; onClick: () => void }) {
30
+ return (
31
+ <div
32
+ onClick={onClick}
33
+ aria-hidden={!isVisible}
34
+ className={css({
35
+ position: 'fixed',
36
+ inset: 0,
37
+ backgroundColor: 'rgba(10,10,10,0.35)',
38
+ zIndex: 40,
39
+ transition: 'opacity 200ms',
40
+ opacity: isVisible ? 1 : 0,
41
+ pointerEvents: isVisible ? 'auto' : 'none',
42
+ backdropFilter: 'blur(2px)',
43
+ '@media (min-width: 768px)': { display: 'none' },
44
+ })}
45
+ />
46
+ )
47
+ }
48
+
49
+ // ---- Sidebar — pure white, precise ----
50
+ function Sidebar({
51
+ isOpen,
52
+ onClose,
53
+ onCmdK,
54
+ }: {
55
+ isOpen: boolean
56
+ onClose: () => void
57
+ onCmdK: () => void
58
+ }) {
59
+ return (
60
+ <>
61
+ <Backdrop isVisible={isOpen} onClick={onClose} />
62
+ <aside
63
+ className={css({
64
+ position: 'fixed',
65
+ top: 0,
66
+ left: 0,
67
+ bottom: 0,
68
+ width: SIDEBAR_WIDTH,
69
+ zIndex: 50,
70
+ display: 'flex',
71
+ flexDirection: 'column',
72
+ backgroundColor: '#ffffff',
73
+ borderRight: '1px solid #ebebeb',
74
+ transform: isOpen ? 'translateX(0)' : `translateX(-${SIDEBAR_WIDTH}px)`,
75
+ transition: 'transform 220ms cubic-bezier(0.4,0,0.2,1)',
76
+
77
+ '@media (min-width: 768px)': {
78
+ position: 'relative',
79
+ transform: 'translateX(0)',
80
+ flexShrink: 0,
81
+ },
82
+ })}
83
+ >
84
+ {/* Logo bar */}
85
+ <div
86
+ className={css({
87
+ display: 'flex',
88
+ alignItems: 'center',
89
+ height: TOPBAR_HEIGHT,
90
+ paddingInline: '16px',
91
+ borderBottom: '1px solid #f2f2f2',
92
+ flexShrink: 0,
93
+ })}
94
+ >
95
+ <Logo />
96
+ </div>
97
+
98
+ {/* Nav scrollable area */}
99
+ <div
100
+ className={css({
101
+ flex: 1,
102
+ overflowY: 'auto',
103
+ overflowX: 'hidden',
104
+ WebkitOverflowScrolling: 'touch',
105
+ '&::-webkit-scrollbar': { width: 3 },
106
+ '&::-webkit-scrollbar-thumb': { background: '#ebebeb', borderRadius: 3 },
107
+ })}
108
+ >
109
+ <Navigation onNavItemClick={onClose} onCmdK={onCmdK} />
110
+ </div>
111
+ </aside>
112
+ </>
113
+ )
114
+ }
115
+
116
+ // ---- Top bar ----
117
+ function TopBar({
118
+ header,
119
+ onMenuClick,
120
+ isSidebarOpen,
121
+ }: {
122
+ header: ReactNode
123
+ onMenuClick: () => void
124
+ isSidebarOpen: boolean
125
+ }) {
126
+ return (
127
+ <header
128
+ className={css({
129
+ display: 'flex',
130
+ alignItems: 'center',
131
+ height: TOPBAR_HEIGHT,
132
+ paddingInline: '24px',
133
+ gap: '14px',
134
+ backgroundColor: '#ffffff',
135
+ borderBottom: '1px solid #ebebeb',
136
+ flexShrink: 0,
137
+ zIndex: 30,
138
+ })}
139
+ >
140
+ {/* Mobile menu button */}
141
+ <button
142
+ onClick={onMenuClick}
143
+ aria-label={isSidebarOpen ? 'Close menu' : 'Open menu'}
144
+ aria-expanded={isSidebarOpen}
145
+ className={css({
146
+ display: 'inline-flex',
147
+ alignItems: 'center',
148
+ justifyContent: 'center',
149
+ width: 32,
150
+ height: 32,
151
+ borderRadius: 6,
152
+ border: '1px solid #ebebeb',
153
+ background: 'transparent',
154
+ cursor: 'pointer',
155
+ flexShrink: 0,
156
+ color: '#a3a3a3',
157
+ transition: 'color 130ms, background 130ms',
158
+ '&:hover': { background: '#f5f5f5', color: '#0a0a0a' },
159
+ '@media (min-width: 768px)': { display: 'none' },
160
+ })}
161
+ >
162
+ <svg width="15" height="15" viewBox="0 0 15 15" fill="none">
163
+ {isSidebarOpen ? (
164
+ <path
165
+ d="M3 3L12 12M12 3L3 12"
166
+ stroke="currentColor"
167
+ strokeWidth="1.4"
168
+ strokeLinecap="round"
169
+ />
170
+ ) : (
171
+ <>
172
+ <line
173
+ x1="2"
174
+ y1="4.5"
175
+ x2="13"
176
+ y2="4.5"
177
+ stroke="currentColor"
178
+ strokeWidth="1.4"
179
+ strokeLinecap="round"
180
+ />
181
+ <line
182
+ x1="2"
183
+ y1="7.5"
184
+ x2="13"
185
+ y2="7.5"
186
+ stroke="currentColor"
187
+ strokeWidth="1.4"
188
+ strokeLinecap="round"
189
+ />
190
+ <line
191
+ x1="2"
192
+ y1="10.5"
193
+ x2="13"
194
+ y2="10.5"
195
+ stroke="currentColor"
196
+ strokeWidth="1.4"
197
+ strokeLinecap="round"
198
+ />
199
+ </>
200
+ )}
201
+ </svg>
202
+ </button>
203
+
204
+ {/* Header content (breadcrumbs / title / actions) */}
205
+ <div
206
+ className={css({
207
+ display: 'flex',
208
+ alignItems: 'center',
209
+ justifyContent: 'space-between',
210
+ flex: 1,
211
+ minWidth: 0,
212
+ gap: '12px',
213
+ })}
214
+ >
215
+ {header}
216
+ </div>
217
+ </header>
218
+ )
219
+ }
220
+
221
+ // ---- Main content area ----
222
+ function MainContent(props: HTMLAttributes<HTMLElement>) {
223
+ return (
224
+ <main
225
+ className={css({
226
+ flex: 1,
227
+ display: 'flex',
228
+ flexDirection: 'column',
229
+ overflow: 'hidden',
230
+ minWidth: 0,
231
+ minHeight: 0,
232
+ })}
233
+ {...props}
234
+ />
235
+ )
236
+ }
237
+
238
+ function ContentScroller(props: HTMLAttributes<HTMLDivElement>) {
239
+ return (
240
+ <div
241
+ data-nixxie-content=""
242
+ className={css({
243
+ flex: 1,
244
+ overflowY: 'auto',
245
+ overflowX: 'hidden',
246
+ WebkitOverflowScrolling: 'touch',
247
+ '&::-webkit-scrollbar': { width: 5 },
248
+ '&::-webkit-scrollbar-thumb': { background: '#e8e8e8', borderRadius: 4 },
249
+ '&::-webkit-scrollbar-thumb:hover': { background: '#d4d4d4' },
250
+ })}
251
+ {...props}
252
+ />
253
+ )
254
+ }
255
+
256
+ // ---- Public API ----
257
+ type PageContainerProps = {
258
+ children: ReactNode
259
+ header: ReactNode
260
+ title?: string
261
+ }
262
+
263
+ export function PageContainer({ children, header, title }: PageContainerProps) {
264
+ const [isSidebarOpen, setSidebarOpen] = useState(false)
265
+ const [cmdOpen, setCmdOpen] = useState(false)
266
+
267
+ useEffect(() => {
268
+ function onResize() {
269
+ if (window.innerWidth >= 768) setSidebarOpen(false)
270
+ }
271
+ window.addEventListener('resize', onResize)
272
+ return () => window.removeEventListener('resize', onResize)
273
+ }, [])
274
+
275
+ useEffect(() => {
276
+ function onKeyDown(e: KeyboardEvent) {
277
+ // Match both 'k' and 'K' (Shift/Caps Lock can change e.key's case).
278
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
279
+ e.preventDefault()
280
+ setCmdOpen(v => !v)
281
+ }
282
+ }
283
+ window.addEventListener('keydown', onKeyDown)
284
+ return () => window.removeEventListener('keydown', onKeyDown)
285
+ }, [])
286
+
287
+ return (
288
+ <PageWrapper>
289
+ <NextHead>
290
+ <title key="title">{title ? `Nixxie – ${title}` : 'Nixxie'}</title>
291
+ </NextHead>
292
+
293
+ <Sidebar
294
+ isOpen={isSidebarOpen}
295
+ onClose={() => setSidebarOpen(false)}
296
+ onCmdK={() => setCmdOpen(v => !v)}
297
+ />
298
+
299
+ <MainContent>
300
+ <TopBar
301
+ header={header}
302
+ onMenuClick={() => setSidebarOpen(v => !v)}
303
+ isSidebarOpen={isSidebarOpen}
304
+ />
305
+ <ContentScroller>{children}</ContentScroller>
306
+ </MainContent>
307
+
308
+ <CommandPalette isOpen={cmdOpen} onClose={() => setCmdOpen(false)} />
309
+ </PageWrapper>
310
+ )
311
+ }
@@ -79,7 +79,7 @@ export function WelcomeDialog() {
79
79
  <VStack gap="xlarge">
80
80
  <Text elementType="p">
81
81
  Thanks for installing Nixxie, checkout the{' '}
82
- <TextLink href="https://nixxiecms.com">documentation</TextLink> for help getting
82
+ <TextLink href="https://nixxieinternational.com">documentation</TextLink> for help getting
83
83
  started. To stay connected{' '}
84
84
  <TextLink href="https://twitter.com/nixxiecms" target="_blank">
85
85
  follow us on twitter