fulldev-ui 0.1.64

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 (82) hide show
  1. package/.astro/types.d.ts +156 -0
  2. package/README.md +29 -0
  3. package/astro.config.mjs +7 -0
  4. package/package.json +45 -0
  5. package/src/blocks/todo.md +12 -0
  6. package/src/components/_Block.astro +20 -0
  7. package/src/components/_Blocks.astro +26 -0
  8. package/src/components/_Children.astro +38 -0
  9. package/src/components/_Plural.astro +27 -0
  10. package/src/components/_Tag.astro +53 -0
  11. package/src/components/base/Badge.astro +53 -0
  12. package/src/components/base/Button.astro +85 -0
  13. package/src/components/base/Buttons.astro +15 -0
  14. package/src/components/base/Checkbox.astro +39 -0
  15. package/src/components/base/Icon.astro +46 -0
  16. package/src/components/base/Image.astro +123 -0
  17. package/src/components/base/Images.astro +15 -0
  18. package/src/components/base/Input.astro +52 -0
  19. package/src/components/base/Logo.astro +33 -0
  20. package/src/components/base/Radio.astro +38 -0
  21. package/src/components/base/Rating.astro +45 -0
  22. package/src/components/base/Select.astro +65 -0
  23. package/src/components/base/SelectOption.astro +27 -0
  24. package/src/components/base/Switch.astro +82 -0
  25. package/src/components/base/Textarea.astro +31 -0
  26. package/src/components/base/Video.astro +32 -0
  27. package/src/components/base/todo.md +8 -0
  28. package/src/components/typography/Heading.astro +41 -0
  29. package/src/components/typography/Label.astro +36 -0
  30. package/src/components/typography/Link.astro +38 -0
  31. package/src/components/typography/Links.astro +15 -0
  32. package/src/components/typography/List.astro +42 -0
  33. package/src/components/typography/ListItem.astro +30 -0
  34. package/src/components/typography/Paragraph.astro +38 -0
  35. package/src/components/typography/Tagline.astro +39 -0
  36. package/src/components/typography/_Typography.astro +28 -0
  37. package/src/components/typography/todo.md +15 -0
  38. package/src/components/utility/DecorativeBox.astro +22 -0
  39. package/src/components/utility/Head.astro +81 -0
  40. package/src/components/wrapper/Body.astro +32 -0
  41. package/src/components/wrapper/Card.astro +144 -0
  42. package/src/components/wrapper/Cards.astro +15 -0
  43. package/src/components/wrapper/Deck.astro +133 -0
  44. package/src/components/wrapper/Footer.astro +14 -0
  45. package/src/components/wrapper/Form.astro +26 -0
  46. package/src/components/wrapper/Group.astro +26 -0
  47. package/src/components/wrapper/Header.astro +76 -0
  48. package/src/components/wrapper/Main.astro +25 -0
  49. package/src/components/wrapper/Nav.astro +32 -0
  50. package/src/components/wrapper/Prose.astro +108 -0
  51. package/src/components/wrapper/Section.astro +110 -0
  52. package/src/components/wrapper/Sections.astro +15 -0
  53. package/src/components/wrapper/Writeup.astro +23 -0
  54. package/src/components/wrapper/_Wrapper.astro +333 -0
  55. package/src/components/wrapper/todo.md +20 -0
  56. package/src/content/pages/index.md +2 -0
  57. package/src/css/border.css +23 -0
  58. package/src/css/colors.css +328 -0
  59. package/src/css/font.css +15 -0
  60. package/src/css/main.css +4 -0
  61. package/src/css/reset.css +388 -0
  62. package/src/css/sizes.css +273 -0
  63. package/src/env.d.ts +2 -0
  64. package/src/index.ts +63 -0
  65. package/src/integration/integration.ts +61 -0
  66. package/src/layouts/Layout.astro +39 -0
  67. package/src/layouts/todo.md +2 -0
  68. package/src/schemas/attributesSchema.ts +125 -0
  69. package/src/schemas/htmlAttributesSchema.ts +126 -0
  70. package/src/schemas/pageSchema.ts +185 -0
  71. package/src/schemas/staticPageSchema.ts +124 -0
  72. package/src/types/Childmorphic.ts +8 -0
  73. package/src/types/Pluralmorphic.ts +7 -0
  74. package/src/utils/getAllCollections.ts +10 -0
  75. package/src/utils/getCollectionCascade.ts +33 -0
  76. package/src/utils/getPathname.ts +18 -0
  77. package/src/utils/transform/transform.ts +25 -0
  78. package/src/utils/transform/transformCasing.ts +24 -0
  79. package/src/utils/transform/transformReferences.ts +54 -0
  80. package/src/utils/transform/transformSelfs.ts +20 -0
  81. package/src/utils/transform/transformUnderscores.ts +19 -0
  82. package/tsconfig.json +6 -0
@@ -0,0 +1,61 @@
1
+ // import type { AstroIntegration } from 'astro'
2
+ // import autoprefixer from 'autoprefixer'
3
+ // import postcssNesting from 'postcss-nesting'
4
+ // import postcssPresetEnv from 'postcss-preset-env'
5
+ // import { mergeDeep } from 'remeda'
6
+ // import virtual from 'vite-plugin-virtual'
7
+
8
+ // const defaultConfig = {
9
+ // color: {
10
+ // accent: 'indigo',
11
+ // base: 'slate',
12
+ // },
13
+ // size: {
14
+ // scale: 1,
15
+ // space: 1,
16
+ // radius: 1,
17
+ // text: 1,
18
+ // },
19
+ // theme: {
20
+ // border: '1px',
21
+ // },
22
+ // font: {
23
+ // heading.text: 'IMB Plex Sans:700',
24
+ // subheading.text: 'IMB Plex Sans:700',
25
+ // text: 'IMB Plex Sans:400',
26
+ // tagline: 'IMB Plex Sans:400',
27
+ // button: 'IMB Plex Sans:500',
28
+ // },
29
+ // }
30
+
31
+ // export default function fulluiIntegration(userConfig: any): AstroIntegration {
32
+ // const config: any = mergeDeep(defaultConfig || {}, userConfig || {})
33
+
34
+ // return {
35
+ // name: '/integration',
36
+ // hooks: {
37
+ // 'astro:config:setup': async ({
38
+ // // config: astroConfig,
39
+ // updateConfig,
40
+ // injectScript,
41
+ // }) => {
42
+ // updateConfig({
43
+ // vite: {
44
+ // plugins: [
45
+ // virtual({
46
+ // 'virtual:/config': `export default ${JSON.stringify(config)}`,
47
+ // }) as any,
48
+ // ],
49
+ // css: {
50
+ // postcss: {
51
+ // plugins: [postcssNesting, postcssPresetEnv, autoprefixer],
52
+ // },
53
+ // },
54
+ // },
55
+ // })
56
+
57
+ // // injectScript('page-ssr', 'import "fulldev-ui/css";')
58
+ // },
59
+ // },
60
+ // }
61
+ // }
@@ -0,0 +1,39 @@
1
+ ---
2
+ import type { ComponentProps } from 'astro/types'
3
+ import Tag from '../components/_Tag.astro'
4
+ import Head from '../components/utility/Head.astro'
5
+ import Body from '../components/wrapper/Body.astro'
6
+
7
+ interface Props extends ComponentProps<typeof Tag> {
8
+ title: ComponentProps<typeof Head>['title']
9
+ description: ComponentProps<typeof Head>['description']
10
+ image: ComponentProps<typeof Head>['image']
11
+ head?: ComponentProps<typeof Head>
12
+ body?: ComponentProps<typeof Body>
13
+ }
14
+
15
+ const { title, description, image, theme, head, body, ...rest } = Astro.props
16
+ ---
17
+
18
+ <Tag
19
+ class:list={['full-layout']}
20
+ as="html"
21
+ if={true}
22
+ {theme}
23
+ {...rest}
24
+ >
25
+ <Head
26
+ {title}
27
+ {description}
28
+ {image}
29
+ {...head}
30
+ />
31
+ <Body
32
+ if={true}
33
+ {theme}
34
+ {...body}
35
+ >
36
+ <slot name="before" />
37
+ <slot />
38
+ </Body>
39
+ </Tag>
@@ -0,0 +1,2 @@
1
+ example:
2
+ Layout component should choose which layout. Could also be a local hero. similar behaviour as blocks, but then only layouts.
@@ -0,0 +1,125 @@
1
+ import { z } from 'astro:content'
2
+
3
+ export const attributesSchema = z.object({
4
+ abbr: z.any(),
5
+ accept: z.any(),
6
+ acceptCharset: z.any(),
7
+ accessKey: z.any(),
8
+ allowFullScreen: z.any(),
9
+ allowTransparency: z.any(),
10
+ alt: z.any(),
11
+ async: z.any(),
12
+ autoComplete: z.any(),
13
+ autoFocus: z.any(),
14
+ autoPlay: z.any(),
15
+ cellPadding: z.any(),
16
+ cellSpacing: z.any(),
17
+ challenge: z.any(),
18
+ charset: z.any(),
19
+ checked: z.any(),
20
+ cite: z.any(),
21
+ class: z.any(),
22
+ className: z.any(),
23
+ cols: z.any(),
24
+ colSpan: z.any(),
25
+ command: z.any(),
26
+ content: z.any(),
27
+ contentEditable: z.any(),
28
+ contextMenu: z.any(),
29
+ controls: z.any(),
30
+ coords: z.any(),
31
+ crossOrigin: z.any(),
32
+ data: z.any(),
33
+ dateTime: z.any(),
34
+ default: z.any(),
35
+ defer: z.any(),
36
+ dir: z.any(),
37
+ disabled: z.any(),
38
+ download: z.any(),
39
+ draggable: z.any(),
40
+ dropzone: z.any(),
41
+ encType: z.any(),
42
+ for: z.any(),
43
+ form: z.any(),
44
+ action: z.any(),
45
+ formEncType: z.any(),
46
+ method: z.any(),
47
+ formNoValidate: z.any(),
48
+ target: z.any(),
49
+ frameBorder: z.any(),
50
+ headers: z.any(),
51
+ height: z.any(),
52
+ hidden: z.any(),
53
+ high: z.any(),
54
+ href: z.any(),
55
+ hrefLang: z.any(),
56
+ htmlFor: z.any(),
57
+ httpEquiv: z.any(),
58
+ id: z.any(),
59
+ inputMode: z.any(),
60
+ isMap: z.any(),
61
+ itemId: z.any(),
62
+ itemProp: z.any(),
63
+ itemRef: z.any(),
64
+ itemScope: z.any(),
65
+ itemType: z.any(),
66
+ kind: z.any(),
67
+ label: z.any(),
68
+ lang: z.any(),
69
+ list: z.any(),
70
+ loop: z.any(),
71
+ manifest: z.any(),
72
+ max: z.any(),
73
+ maxLength: z.any(),
74
+ media: z.any(),
75
+ mediaGroup: z.any(),
76
+ min: z.any(),
77
+ minLength: z.any(),
78
+ multiple: z.any(),
79
+ muted: z.any(),
80
+ name: z.any(),
81
+ noValidate: z.any(),
82
+ open: z.any(),
83
+ optimum: z.any(),
84
+ pattern: z.any(),
85
+ ping: z.any(),
86
+ placeholder: z.any(),
87
+ poster: z.any(),
88
+ preload: z.any(),
89
+ rel: z.any(),
90
+ required: z.any(),
91
+ rows: z.any(),
92
+ sizes: z.any(),
93
+
94
+ // role: z.any(),
95
+ // radioGroup: z.any(),
96
+ // readOnly: z.any(),
97
+ // rowSpan: z.any(),
98
+ // sandbox: z.any(),
99
+ // scope: z.any(),
100
+ // scoped: z.any(),
101
+ // scrolling: z.any(),
102
+ // seamless: z.any(),
103
+ // selected: z.any(),
104
+ // shape: z.any(),
105
+ // size: z.any(),
106
+ // sortable: z.any(),
107
+ // span: z.any(),
108
+ // spellCheck: z.any(),
109
+ src: z.any(),
110
+ // srcDoc: z.any(),
111
+ srcset: z.any(),
112
+ // start: z.any(),
113
+ // step: z.any(),
114
+ style: z.any(),
115
+ tabIndex: z.any(),
116
+ title: z.any(),
117
+ // translate: z.any(),
118
+ type: z.any(),
119
+ // typeMustMatch: z.any(),
120
+ // useMap: z.any(),
121
+ value: z.any(),
122
+ width: z.any(),
123
+ // wmode: z.any(),
124
+ // wrap: z.any(),
125
+ })
@@ -0,0 +1,126 @@
1
+ const arr = [
2
+ 'abbr',
3
+ 'accept',
4
+ 'acceptCharset',
5
+ 'accessKey',
6
+ 'action',
7
+ 'allowFullScreen',
8
+ 'allowTransparency',
9
+ 'alt',
10
+ 'async',
11
+ 'autoComplete',
12
+ 'autoFocus',
13
+ 'autoPlay',
14
+ 'cellPadding',
15
+ 'cellSpacing',
16
+ 'challenge',
17
+ 'charset',
18
+ 'checked',
19
+ 'cite',
20
+ 'class',
21
+ 'className',
22
+ 'cols',
23
+ 'colSpan',
24
+ 'command',
25
+ 'content',
26
+ 'contentEditable',
27
+ 'contextMenu',
28
+ 'controls',
29
+ 'coords',
30
+ 'crossOrigin',
31
+ 'data',
32
+ 'dateTime',
33
+ 'default',
34
+ 'defer',
35
+ 'dir',
36
+ 'disabled',
37
+ 'download',
38
+ 'draggable',
39
+ 'dropzone',
40
+ 'encType',
41
+ 'for',
42
+ 'form',
43
+ 'formAction',
44
+ 'formEncType',
45
+ 'formMethod',
46
+ 'formNoValidate',
47
+ 'formTarget',
48
+ 'frameBorder',
49
+ 'headers',
50
+ 'height',
51
+ 'hidden',
52
+ 'high',
53
+ 'href',
54
+ 'hrefLang',
55
+ 'htmlFor',
56
+ 'httpEquiv',
57
+ 'icon',
58
+ 'id',
59
+ 'inputMode',
60
+ 'isMap',
61
+ 'itemId',
62
+ 'itemProp',
63
+ 'itemRef',
64
+ 'itemScope',
65
+ 'itemType',
66
+ 'kind',
67
+ 'label',
68
+ 'lang',
69
+ 'list',
70
+ 'loop',
71
+ 'manifest',
72
+ 'max',
73
+ 'maxLength',
74
+ 'media',
75
+ 'mediaGroup',
76
+ 'method',
77
+ 'min',
78
+ 'minLength',
79
+ 'multiple',
80
+ 'muted',
81
+ 'name',
82
+ 'noValidate',
83
+ 'open',
84
+ 'optimum',
85
+ 'pattern',
86
+ 'ping',
87
+ 'placeholder',
88
+ 'poster',
89
+ 'preload',
90
+ 'radioGroup',
91
+ 'readOnly',
92
+ 'rel',
93
+ 'required',
94
+ 'role',
95
+ 'rows',
96
+ 'rowSpan',
97
+ 'sandbox',
98
+ 'scope',
99
+ 'scoped',
100
+ 'scrolling',
101
+ 'seamless',
102
+ 'selected',
103
+ 'shape',
104
+ 'size',
105
+ 'sizes',
106
+ 'sortable',
107
+ 'span',
108
+ 'spellCheck',
109
+ 'src',
110
+ 'srcDoc',
111
+ 'srcSet',
112
+ 'start',
113
+ 'step',
114
+ 'style',
115
+ 'tabIndex',
116
+ 'target',
117
+ 'title',
118
+ 'translate',
119
+ 'type',
120
+ 'typeMustMatch',
121
+ 'useMap',
122
+ 'value',
123
+ 'width',
124
+ 'wmode',
125
+ 'wrap',
126
+ ]
@@ -0,0 +1,185 @@
1
+ import {
2
+ getCollection,
3
+ getEntries,
4
+ getEntry,
5
+ z,
6
+ type CollectionEntry,
7
+ type CollectionKey,
8
+ } from 'astro:content'
9
+ import { flatten, unflatten } from 'flat'
10
+ import {
11
+ all,
12
+ camel,
13
+ construct,
14
+ get,
15
+ isString,
16
+ mapValues,
17
+ objectify,
18
+ } from 'radash'
19
+ import { mapKeys, merge } from 'remeda'
20
+
21
+ interface Options {
22
+ casing: boolean
23
+ layouts: boolean
24
+ references: boolean
25
+ selfs: boolean
26
+ }
27
+
28
+ const defaults: Options = {
29
+ casing: true,
30
+ layouts: true,
31
+ references: true,
32
+ selfs: true,
33
+ }
34
+
35
+ let cascade: any = {}
36
+
37
+ const transformReferences = async (data: object) =>
38
+ await all(
39
+ mapValues(flatten(data) as any, async (value) => {
40
+ if (!isString(value)) return value
41
+ const parts = (value as string).split(' ')
42
+ const results = await all(
43
+ parts.map(async (valuePart) => {
44
+ if (!valuePart.startsWith('$')) return valuePart
45
+ if (valuePart.startsWith('$self')) return valuePart
46
+
47
+ const reference = valuePart.split('.')[0].replace('$', '')
48
+ const collection = reference.split('/')[0]
49
+ const slug = reference.split('/').slice(1).join('/')
50
+ const path = valuePart.split('.').slice(1).join('.')
51
+
52
+ if (collection && slug) {
53
+ let response = await getEntry(collection as CollectionKey, slug)
54
+ const parsed = await pageSchema().parseAsync(response?.data)
55
+ // let response: any = get(cascade, `${collection}/${slug}`)
56
+ const result = get(parsed, path)
57
+ response = undefined
58
+ return result
59
+ } else if (collection) {
60
+ const response = await getCollection(collection as CollectionKey)
61
+ // const response: any = get(cascade, collection)
62
+ const result = response?.map((entry: any) => get(entry?.data, path))
63
+ return result
64
+ }
65
+
66
+ return valuePart
67
+ })
68
+ )
69
+ if (results.length == 1) return results[0]
70
+ return results.join(' ')
71
+ })
72
+ )
73
+
74
+ const transformLayouts = (data: object) => {
75
+ const flat: any = flatten(data)
76
+ let store: any = {}
77
+ let i: number = 0
78
+
79
+ const merged = mapKeys(flat, (key) => {
80
+ if (!isString(key)) return key
81
+ const parts = key.split('.')
82
+ const result = parts.map((part) => {
83
+ return part.replace(/^_+/, '')
84
+ })
85
+ const filtered = result.filter(Boolean)
86
+ const joined = filtered.join('.')
87
+ return joined
88
+ })
89
+ const nested = construct(merged)
90
+ return nested
91
+ }
92
+
93
+ const transformSelfs = (data: object) => {
94
+ const flat = flatten(data) as any
95
+ const mapped = mapValues(flat, (value) => {
96
+ if (!isString(value)) return value
97
+ const parts = (value as string).split(' ')
98
+ const result = parts.map((part) => {
99
+ if (!part.startsWith('$self')) return part
100
+ const pathParts = part.split('.').slice(1)
101
+ const camelCased = pathParts.map((part) => camel(part))
102
+ const path = camelCased.join('.')
103
+ const result = get(data, path)
104
+ return result ? result : part
105
+ })
106
+ return result.join(' ')
107
+ })
108
+ return unflatten(mapped)
109
+ }
110
+
111
+ const transformCasing = (object: object) => {
112
+ const flat = flatten(object)
113
+ const mapped = mapKeys(flat, (key) => {
114
+ if (!isString(key)) return key
115
+ const parts = (key as string).split('.')
116
+ const result = parts.map((part) => camel(part))
117
+ return result.join('.')
118
+ })
119
+ return unflatten(mapped)
120
+ }
121
+
122
+ const buildCascade = async (data: any) => {
123
+ const flat: any = flatten(data)
124
+ const values = Object.values(flat)
125
+ const strings = values.filter(isString)
126
+ const parts = strings.map((value: any) => value.split(' ')).flat()
127
+ const fullpaths = parts.filter(
128
+ (value) => value.startsWith('$') && !value.startsWith('$self')
129
+ )
130
+ const filepaths = fullpaths.map((f) => f.replace('$', '').split('.')[0])
131
+
132
+ const collections = filepaths.filter((f) => !f.includes('/'))
133
+ const collectionsNew = collections.filter((c) => !cascade[c])
134
+ // console.log('collectionsNew', collectionsNew)
135
+ const collectionsPromises = collectionsNew.map((c) => getCollection(c))
136
+ const collectionsResponses = await Promise.all(collectionsPromises)
137
+ const collectionsCascade = objectify(
138
+ collectionsResponses,
139
+ (c: any) => c[0]?.collection
140
+ )
141
+
142
+ const entries = filepaths.filter((f) => f.includes('/'))
143
+ const entriesNew = entries.filter(
144
+ (e) => !cascade[e.split('/').slice(1).join('/')]
145
+ )
146
+ // console.log('entriesNew', entriesNew)
147
+ const entriesResponses = await getEntries(
148
+ entriesNew.map((e) => ({
149
+ collection: e.split('/')[0],
150
+ slug: e.split('/').slice(1).join('/'),
151
+ }))
152
+ )
153
+ const entriesCascade = objectify(
154
+ entriesResponses,
155
+ (e: any) => `${e?.collection}/${e?.slug || e?.id}`
156
+ )
157
+
158
+ cascade = { ...cascade, ...collectionsCascade, ...entriesCascade }
159
+ }
160
+
161
+ let doIStay = false
162
+
163
+ export const pageSchema = (options: Partial<Options> = {}) =>
164
+ z.any().transform(async (data: CollectionEntry<CollectionKey>['data']) => {
165
+ const { layouts, casing, references, selfs } = merge(defaults, options)
166
+
167
+ // console.log('doIStay', doIStay)
168
+ // console.log('cascade', Object.keys(cascade))
169
+ doIStay = true
170
+ // await buildCascade(data)
171
+
172
+ if (references) data = await transformReferences(data)
173
+ // console.log('references', data)
174
+
175
+ if (layouts) data = transformLayouts(data)
176
+ // console.log('layouts', data)
177
+
178
+ if (casing) data = transformCasing(data)
179
+ // console.log('casing', data)
180
+
181
+ if (selfs) data = transformSelfs(data)
182
+ // console.log('selfs', data)
183
+
184
+ return data
185
+ })
@@ -0,0 +1,124 @@
1
+ import {
2
+ getCollection,
3
+ getEntry,
4
+ z,
5
+ type CollectionEntry,
6
+ type CollectionKey,
7
+ } from 'astro:content'
8
+ import { flatten, unflatten } from 'flat'
9
+ import { all, camel, construct, get, isString, mapValues } from 'radash'
10
+ import { mapKeys, merge } from 'remeda'
11
+
12
+ interface Options {
13
+ casing: boolean
14
+ layouts: boolean
15
+ references: boolean
16
+ selfs: boolean
17
+ }
18
+
19
+ const defaults: Options = {
20
+ casing: true,
21
+ layouts: true,
22
+ references: true,
23
+ selfs: true,
24
+ }
25
+
26
+ const transformReferences = async (data: object) =>
27
+ await all(
28
+ mapValues(flatten(data) as any, async (value) => {
29
+ if (!isString(value)) return value
30
+ const parts = (value as string).split(' ')
31
+ const results = await all(
32
+ parts.map(async (valuePart) => {
33
+ if (!valuePart.startsWith('$')) return valuePart
34
+ if (valuePart.startsWith('$self')) return valuePart
35
+
36
+ const reference = valuePart.split('.')[0].replace('$', '')
37
+ const collection = reference.split('/')[0]
38
+ const slug = reference.split('/').slice(1).join('/')
39
+ const path = valuePart.split('.').slice(1).join('.')
40
+
41
+ if (collection && slug) {
42
+ let response = await getEntry(collection as CollectionKey, slug)
43
+ const result = get(response?.data, path)
44
+ return result
45
+ } else if (collection) {
46
+ const response = await getCollection(collection as CollectionKey)
47
+ const result = response?.map((entry: any) => get(entry?.data, path))
48
+ return result
49
+ }
50
+
51
+ return valuePart
52
+ })
53
+ )
54
+ if (results.length == 1) return results[0]
55
+ return results.join(' ')
56
+ })
57
+ )
58
+
59
+ const transformLayouts = (data: object) => {
60
+ const flat: any = flatten(data)
61
+ let store: any = {}
62
+ let i: number = 0
63
+
64
+ const merged = mapKeys(flat, (key) => {
65
+ if (!isString(key)) return key
66
+ const parts = key.split('.')
67
+ const result = parts.map((part) => {
68
+ return part.replace(/^_+/, '')
69
+ })
70
+ const filtered = result.filter(Boolean)
71
+ const joined = filtered.join('.')
72
+ return joined
73
+ })
74
+ const nested = construct(merged)
75
+ return nested
76
+ }
77
+
78
+ const transformSelfs = (data: object) => {
79
+ const flat = flatten(data) as any
80
+ const mapped = mapValues(flat, (value) => {
81
+ if (!isString(value)) return value
82
+ const parts = (value as string).split(' ')
83
+ const result = parts.map((part) => {
84
+ if (!part.startsWith('$self')) return part
85
+ const pathParts = part.split('.').slice(1)
86
+ const camelCased = pathParts.map((part) => camel(part))
87
+ const path = camelCased.join('.')
88
+ const result = get(data, path)
89
+ return result ? result : part
90
+ })
91
+ return result.join(' ')
92
+ })
93
+ return unflatten(mapped)
94
+ }
95
+
96
+ const transformCasing = (object: object) => {
97
+ const flat = flatten(object)
98
+ const mapped = mapKeys(flat, (key) => {
99
+ if (!isString(key)) return key
100
+ const parts = (key as string).split('.')
101
+ const result = parts.map((part) => camel(part))
102
+ return result.join('.')
103
+ })
104
+ return unflatten(mapped)
105
+ }
106
+
107
+ export const pageSchema = (options: Partial<Options> = {}) =>
108
+ z.any().transform(async (data: CollectionEntry<CollectionKey>['data']) => {
109
+ const { layouts, casing, references, selfs } = merge(defaults, options)
110
+
111
+ if (references) data = await transformReferences(data)
112
+ // console.log('references', JSON.stringify(data, null, 2))
113
+
114
+ if (layouts) data = transformLayouts(data)
115
+ // console.log('layouts', data)
116
+
117
+ if (casing) data = transformCasing(data)
118
+ // console.log('casing', data)
119
+
120
+ if (selfs) data = transformSelfs(data)
121
+ // console.log('selfs', data)
122
+
123
+ return data
124
+ })
@@ -0,0 +1,8 @@
1
+ import type { AstroGlobal } from 'astro'
2
+
3
+ export type Childmorphic<C extends AstroGlobal['props']> = {
4
+ [Key in keyof C & string as
5
+ | Lowercase<Key>
6
+ | Capitalize<Key>
7
+ | `${string}${Capitalize<Key>}`]?: C[Key]
8
+ }
@@ -0,0 +1,7 @@
1
+ import type { AstroGlobal } from 'astro'
2
+
3
+ export type Pluralmorphic<P extends AstroGlobal['props']> =
4
+ | (P & {
5
+ [key: number]: P | string
6
+ })
7
+ | (P | string)[]
@@ -0,0 +1,10 @@
1
+ import type { CollectionKey } from 'astro:content'
2
+ import { getCollection } from 'astro:content'
3
+
4
+ export const getAllCollections = async (names: CollectionKey[]) => {
5
+ const promises = names.map((name) => getCollection(name))
6
+ const resolved = await Promise.all(promises)
7
+ const flattened = resolved.flat()
8
+ const filtered = flattened.filter(Boolean)
9
+ return filtered
10
+ }