@samuelgomez/astro 0.1.0

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 (115) hide show
  1. package/README.md +54 -0
  2. package/package.json +42 -0
  3. package/src/components/Accordion/index.astro +31 -0
  4. package/src/components/Alert/AlertDanger.astro +12 -0
  5. package/src/components/Alert/AlertInfo.astro +12 -0
  6. package/src/components/Alert/AlertSuccess.astro +12 -0
  7. package/src/components/Alert/AlertWarning.astro +12 -0
  8. package/src/components/Alert/index.astro +10 -0
  9. package/src/components/Badge/BadgeDanger.astro +15 -0
  10. package/src/components/Badge/BadgeInfo.astro +15 -0
  11. package/src/components/Badge/BadgeSuccess.astro +15 -0
  12. package/src/components/Badge/BadgeWarning.astro +15 -0
  13. package/src/components/Badge/index.astro +9 -0
  14. package/src/components/Box/index.astro +45 -0
  15. package/src/components/BoxPost/index.astro +66 -0
  16. package/src/components/Button/index.astro +35 -0
  17. package/src/components/Caniuse/index.astro +24 -0
  18. package/src/components/Codepen/index.astro +25 -0
  19. package/src/components/DebugGrid/index.astro +100 -0
  20. package/src/components/Demo/Demoui.astro +13 -0
  21. package/src/components/Demo/index.astro +105 -0
  22. package/src/components/Dialog/index.astro +74 -0
  23. package/src/components/FormattedDate/index.astro +17 -0
  24. package/src/components/GithubContributions/index.astro +88 -0
  25. package/src/components/Home/CardsBlog.astro +41 -0
  26. package/src/components/Home/CardsCodepen.astro +53 -0
  27. package/src/components/Home/CardsGithub.astro +44 -0
  28. package/src/components/Img/index.astro +28 -0
  29. package/src/components/Link/index.astro +33 -0
  30. package/src/components/Nav/NavToggle.astro +40 -0
  31. package/src/components/Nav/index.astro +71 -0
  32. package/src/components/Pagination/PaginationItem.astro +51 -0
  33. package/src/components/Pagination/index.astro +39 -0
  34. package/src/components/ScrollWatcher/index.astro +11 -0
  35. package/src/components/Social/index.astro +22 -0
  36. package/src/components/Support/index.astro +24 -0
  37. package/src/components/Svg/index.astro +30 -0
  38. package/src/components/SwitchTheme.astro +45 -0
  39. package/src/components/Table/Table.astro +15 -0
  40. package/src/components/Table/TableBody.astro +21 -0
  41. package/src/components/Table/TableHeader.astro +19 -0
  42. package/src/components/Table/index.astro +21 -0
  43. package/src/components/TableOfContent/index.astro +117 -0
  44. package/src/components/Tabs/TabList.astro +23 -0
  45. package/src/components/Tabs/TabListItem.astro +22 -0
  46. package/src/components/Tabs/TabPanel.astro +19 -0
  47. package/src/components/Tabs/TabsContainer.astro +174 -0
  48. package/src/components/Tabs/index.astro +46 -0
  49. package/src/components/Title/h1.astro +12 -0
  50. package/src/components/Title/h2.astro +12 -0
  51. package/src/components/Title/h3.astro +12 -0
  52. package/src/components/Title/h4.astro +12 -0
  53. package/src/components/Title/h5.astro +12 -0
  54. package/src/components/Title/h6.astro +12 -0
  55. package/src/components/Title/heading.astro +8 -0
  56. package/src/components/Title/index.astro +39 -0
  57. package/src/components/WrapperToHtml/index.astro +8 -0
  58. package/src/components/form/Field/index.astro +43 -0
  59. package/src/components/form/Fieldset/index.astro +14 -0
  60. package/src/components/form/Form/FieldDate.astro +32 -0
  61. package/src/components/form/Form/FieldEmail.astro +32 -0
  62. package/src/components/form/Form/FieldNumber.astro +35 -0
  63. package/src/components/form/Form/FieldPassword.astro +32 -0
  64. package/src/components/form/Form/FieldRadio.astro +32 -0
  65. package/src/components/form/Form/FieldSelect.astro +26 -0
  66. package/src/components/form/Form/FieldText.astro +35 -0
  67. package/src/components/form/Form/FieldTextarea.astro +25 -0
  68. package/src/components/form/Form/index.astro +5 -0
  69. package/src/components/form/Input/index.astro +27 -0
  70. package/src/components/form/InputRadio/index.astro +30 -0
  71. package/src/components/form/MoreInfo/index.astro +14 -0
  72. package/src/components/form/Select/index.astro +25 -0
  73. package/src/components/form/Status/index.astro +34 -0
  74. package/src/components/form/Textarea/index.astro +26 -0
  75. package/src/components/helpers/WrapperOrNot/index.astro +23 -0
  76. package/src/components/layout/Footer.astro +3 -0
  77. package/src/components/layout/Head.astro +154 -0
  78. package/src/components/layout/Header.astro +28 -0
  79. package/src/components/old/Grid.astro +18 -0
  80. package/src/components/old/Section.astro +19 -0
  81. package/src/components/old/SwitchTheme.astro +66 -0
  82. package/src/components/old/index-webco.astro +55 -0
  83. package/src/components/old/send.astro +28 -0
  84. package/src/helpers/dom.ts +19 -0
  85. package/src/helpers/isEmptyOrNull.test.ts +58 -0
  86. package/src/helpers/isEmptyOrNull.ts +6 -0
  87. package/src/helpers/setSlug.test.ts +20 -0
  88. package/src/helpers/setSlug.ts +7 -0
  89. package/src/helpers/setTocTitle.ts +2 -0
  90. package/src/helpers/setVariants.test.ts +26 -0
  91. package/src/helpers/setVariants.ts +18 -0
  92. package/src/icons/Add.astro +18 -0
  93. package/src/icons/Anchor.astro +22 -0
  94. package/src/icons/Arrow.astro +11 -0
  95. package/src/icons/AstroLogo.astro +35 -0
  96. package/src/icons/Check.astro +11 -0
  97. package/src/icons/ChevronDown.astro +11 -0
  98. package/src/icons/ChevronLeft.astro +11 -0
  99. package/src/icons/ChevronRight.astro +11 -0
  100. package/src/icons/Codepen.astro +36 -0
  101. package/src/icons/Cross.astro +11 -0
  102. package/src/icons/ExternalLink.astro +19 -0
  103. package/src/icons/Github.astro +36 -0
  104. package/src/icons/Github2.astro +11 -0
  105. package/src/icons/Grid.astro +19 -0
  106. package/src/icons/Info.astro +11 -0
  107. package/src/icons/Instagram.astro +11 -0
  108. package/src/icons/Linkedin.astro +11 -0
  109. package/src/icons/LogoSG.astro +66 -0
  110. package/src/icons/MoonSun.astro +17 -0
  111. package/src/icons/Send.astro +11 -0
  112. package/src/icons/Slash.astro +14 -0
  113. package/src/icons/Trash.astro +19 -0
  114. package/src/icons/Twitter.astro +14 -0
  115. package/src/types/Permutations.d.ts +3 -0
@@ -0,0 +1,154 @@
1
+ ---
2
+ import { SEO } from 'astro-seo';
3
+ /* import { ClientRouter, ViewTransitions } from 'astro:transitions'; */
4
+
5
+ type Props = {
6
+ title: string;
7
+ description?: string;
8
+ image?: string;
9
+ lang?: string;
10
+ keywords?: string;
11
+ };
12
+
13
+ const defaultDescription =
14
+ 'Samuel Gomez, Software Engineer - Lead Front-end, Nodejs à Lille. Développement et intégration de SPA avec ReactJS. Développement de sites Web avec NodeJS';
15
+ const defaultImage = '/images/avatar.jpg';
16
+ const defautlKeywords =
17
+ 'Expert ReactJS, Développeur Front-end, UX Designer, Développeur Web, développeur ReactJS Lille, Développeur Lille Front-end, Développeur ReactJS, Développeur JavaScript, Développeur Nodejs, Développeur NodeJS';
18
+ const defaultTitle =
19
+ 'Samuel Gomez, Software Engineer - Lead Front-end - ReactJS - Javascript - Nodejs, France';
20
+ const {
21
+ title,
22
+ description = defaultDescription,
23
+ image = defaultImage,
24
+ lang = 'fr',
25
+ keywords = defautlKeywords,
26
+ } = Astro.props;
27
+
28
+ const currentYear = new Date().getFullYear();
29
+
30
+ const url = Astro.url.href;
31
+
32
+ const fullTitle = `${defaultTitle}${title && ` - ${title}`}`;
33
+
34
+ const color = '#2d89ef';
35
+ ---
36
+
37
+ <head>
38
+ <meta charset="UTF-8" />
39
+ <SEO
40
+ title={fullTitle}
41
+ description={description}
42
+ openGraph={{
43
+ basic: {
44
+ title: fullTitle,
45
+ type: 'website',
46
+ image,
47
+ },
48
+ }}
49
+ twitter={{
50
+ creator: '@gamuez',
51
+ }}
52
+ extend={{
53
+ link: [
54
+ { rel: 'icon', href: '/favicon/favicon.svg', type: 'image/svg+xml' },
55
+ {
56
+ rel: 'apple-touch-icon',
57
+ href: '/favicon/apple-touch-icon.png',
58
+ sizes: '180x180',
59
+ },
60
+ {
61
+ rel: 'icon',
62
+ type: 'image/png',
63
+ href: '/favicon/favicon-32x32.png',
64
+ sizes: '32x32',
65
+ },
66
+ {
67
+ rel: 'icon',
68
+ type: 'image/png',
69
+ href: '/favicon/favicon-16x16.png',
70
+ sizes: '16x16',
71
+ },
72
+ { rel: 'manifest', href: '/favicon/site.webmanifest' },
73
+ ],
74
+ meta: [
75
+ {
76
+ name: 'viewport',
77
+ content:
78
+ 'width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=5.0',
79
+ },
80
+ {
81
+ name: 'color-scheme',
82
+ content: 'dark light',
83
+ },
84
+ {
85
+ name: 'Content-Language',
86
+ content: lang,
87
+ },
88
+ {
89
+ name: 'Subject',
90
+ content: fullTitle,
91
+ },
92
+ {
93
+ name: 'Copyright',
94
+ content: `Ⓒ ${currentYear} Samuel Gomez`,
95
+ },
96
+ {
97
+ name: 'Author',
98
+ content: 'Samuel Gomez',
99
+ },
100
+ {
101
+ name: 'Publisher',
102
+ content: 'Samuel Gomez',
103
+ },
104
+ {
105
+ name: 'Identifier-Url',
106
+ content: url,
107
+ },
108
+ {
109
+ name: 'Reply-To',
110
+ content: 'contact@samuelgomez.fr',
111
+ },
112
+ {
113
+ name: 'Distribution',
114
+ content: 'global',
115
+ },
116
+ {
117
+ name: 'Revisit-After',
118
+ content: '15 days',
119
+ },
120
+ {
121
+ name: 'Rating',
122
+ content: 'general',
123
+ },
124
+ {
125
+ name: 'Geography',
126
+ content: 'France',
127
+ },
128
+ {
129
+ name: 'Category',
130
+ content: 'engineering',
131
+ },
132
+ {
133
+ name: 'keywords',
134
+ content: keywords,
135
+ },
136
+ {
137
+ name: 'theme-color',
138
+ content: color,
139
+ },
140
+ {
141
+ name: 'msapplication-TileColor',
142
+ content: color,
143
+ },
144
+ {
145
+ name: 'twitter:image',
146
+ content: image,
147
+ },
148
+ { name: 'twitter:title', content: fullTitle },
149
+ { name: 'twitter:description', content: description },
150
+ ],
151
+ }}
152
+ />
153
+ <link rel="mask-icon" href="/favicon/favicon.svg" color={color} />
154
+ </head>
@@ -0,0 +1,28 @@
1
+ ---
2
+ import LogoSG from '@samuelgomez/astro/icons/LogoSG.astro';
3
+ import SwitchTheme from '@samuelgomez/astro/components/SwitchTheme.astro';
4
+ import NavToggle from '@samuelgomez/astro/components/Nav/NavToggle.astro';
5
+ import Nav from '@samuelgomez/astro/components/Nav/index.astro';
6
+ import Link from '@samuelgomez/astro/components/Link/index.astro';
7
+ import { getEntry } from 'astro:content';
8
+ import { setSlug } from '@samuelgomez/astro/helpers/setSlug';
9
+
10
+ const mainMenu = await getEntry('menu', 'main');
11
+ const { userEmail } = Astro.locals;
12
+
13
+ const LABEL = 'Menu de navigation principal';
14
+ const ID = `id-${setSlug(LABEL)}`;
15
+ ---
16
+
17
+ <header>
18
+ <Link id="logo" href="/">
19
+ <LogoSG
20
+ slot="after-link"
21
+ title="Samuel Gomez - Accéder à la page d'accueil"
22
+ />
23
+ </Link>
24
+ <NavToggle aria-controls={ID} />
25
+ <Nav items={mainMenu?.data.items} label={LABEL} id={ID} />
26
+ <SwitchTheme />
27
+ {userEmail && <p>Welcome {userEmail}</p>}
28
+ </header>
@@ -0,0 +1,18 @@
1
+ ---
2
+ type Props = {
3
+ md: number;
4
+ gap: number;
5
+ };
6
+
7
+ const { md, gap } = Astro.props;
8
+ ---
9
+
10
+ <div class="grid"><slot /></div>
11
+
12
+ <style define:vars={{ md, gap }}>
13
+ .grid {
14
+ display: grid;
15
+ grid-template-columns: repeat(var(--md), 1fr);
16
+ gap: calc(var(--gap) * 1rem);
17
+ }
18
+ </style>
@@ -0,0 +1,19 @@
1
+ <section>
2
+ {
3
+ Astro.slots.has('header') && (
4
+ <header>
5
+ <slot name="header" />
6
+ </header>
7
+ )
8
+ }
9
+
10
+ <slot />
11
+
12
+ {
13
+ Astro.slots.has('footer') && (
14
+ <footer>
15
+ <slot name="footer" />
16
+ </footer>
17
+ )
18
+ }
19
+ </section>
@@ -0,0 +1,66 @@
1
+ ---
2
+ import MoonSun from '@samuelgomez/astro/icons/MoonSun.astro';
3
+ import Button from '@samuelgomez/astro/components/Button/index.astro';
4
+
5
+ const cookieTheme = Astro.cookies.get('theme')?.value ?? null;
6
+ ---
7
+
8
+ <Button
9
+ class="switch-theme"
10
+ variant="ghost small"
11
+ id="switch-theme"
12
+ title="Changer en mode clair ou sombre"
13
+ aria-label={cookieTheme}
14
+ aria-live="polite"
15
+ >
16
+ <MoonSun />
17
+ </Button>
18
+
19
+ <script>
20
+ const cookies = Object.assign(
21
+ {},
22
+ ...document.cookie.split('; ').map(cookie => {
23
+ const name = cookie.split('=')[0];
24
+ const value = cookie.split('=')[1];
25
+
26
+ return { [name]: value };
27
+ }),
28
+ );
29
+
30
+ const getCookie = (name: string) => cookies[name];
31
+
32
+ const setCookie = (name: string, value: string) => {
33
+ cookies[name] = value;
34
+ document.cookie = [...Object.keys(cookies)]
35
+ .filter(Boolean)
36
+ .map(key => `${key}=${cookies[key]}`)
37
+ .join('; ');
38
+ };
39
+
40
+ const DARK = 'dark';
41
+ const LIGHT = 'light';
42
+ const themeToggle = document.querySelector('#switch-theme');
43
+ const matchMediaDark = window.matchMedia('(prefers-color-scheme: dark)');
44
+
45
+ const getMatchMedia = () => (matchMediaDark.matches ? DARK : LIGHT);
46
+
47
+ let theme = getCookie('theme') || getMatchMedia();
48
+
49
+ const setTheme = (isSetToDark: boolean) => {
50
+ theme = isSetToDark ? DARK : LIGHT;
51
+ setCookie('theme', theme);
52
+ themeToggle?.setAttribute('aria-label', theme);
53
+ };
54
+
55
+ if (!Boolean(themeToggle?.getAttribute('aria-label'))) {
56
+ setTheme(getMatchMedia() === DARK);
57
+ }
58
+
59
+ window.addEventListener('load', () => {
60
+ themeToggle?.addEventListener('click', () => setTheme(theme === LIGHT));
61
+ });
62
+
63
+ matchMediaDark.addEventListener('change', ({ matches: isDark }) =>
64
+ setTheme(isDark),
65
+ );
66
+ </script>
@@ -0,0 +1,55 @@
1
+ ---
2
+ import TabContainer from '@samuelgomez/astro/components/Tabs/TabsContainer.astro';
3
+ import TabPanel from '@samuelgomez/astro/components/Tabs/TabPanel.astro';
4
+ import TabList from '@samuelgomez/astro/components/Tabs/TabList.astro';
5
+ import TabListItem from '@samuelgomez/astro/components/Tabs/TabListItem.astro';
6
+
7
+ const html = await Astro.slots.render('default');
8
+ const css = await Astro.slots.render('css');
9
+
10
+ import { Code } from 'astro/components';
11
+ /* const style = css
12
+ ?.replace("<code>", "")
13
+ ?.replace("</code>", "")
14
+ ?.replace("{", "{\r")
15
+ ?.replace("}", "\r}")
16
+ ?.replace(";", ";\r")
17
+ ?.trim?.(); */
18
+ // const className = `demo-${Date.now() + "_" + Math.floor(Math.random() * 10000)}`;
19
+ const idTab = 'demo-code';
20
+ ---
21
+
22
+ <TabContainer
23
+ className="tabs full"
24
+ id={idTab}
25
+ idTitle={`title-${idTab}`}
26
+ title="Tabs with or without composition"
27
+ >
28
+ <TabList idTitle={`title-${idTab}`}>
29
+ <TabListItem id={idTab} index={0}>Démo</TabListItem>
30
+ <TabListItem id={idTab} index={1}>HTML</TabListItem>
31
+ <TabListItem id={idTab} index={2}>CSS</TabListItem>
32
+ </TabList>
33
+ <TabPanel id={idTab} index={0}>
34
+ <wc-demo></wc-demo>
35
+ </TabPanel>
36
+ <TabPanel id={idTab} index={1}>
37
+ <Code code={html} lang="html" />
38
+ </TabPanel>
39
+ <TabPanel id={idTab} index={2}>
40
+ <Code code={css} lang="css" />
41
+ </TabPanel>
42
+ </TabContainer>
43
+
44
+ <!-- <script define:vars={{ css, html }}>
45
+ customElements.define(
46
+ "wc-demo",
47
+ class WCDemo extends HTMLElement {
48
+ constructor() {
49
+ super();
50
+ const shadowRoot = this.attachShadow({ mode: "open" });
51
+ shadowRoot.innerHTML = `<style>* + *{ color: initial; } ${css}</style><div>${html}</div>`;
52
+ }
53
+ }
54
+ );
55
+ </script> -->
@@ -0,0 +1,28 @@
1
+ ---
2
+ /* const body = await
3
+ console.log(Astro.request.body); */
4
+
5
+ if (Astro.request.method === 'POST') {
6
+ try {
7
+ /* const data = await Astro.request.formData();
8
+ const civility = data.get('civility');
9
+ const firstname = data.get('firstname');
10
+ const lastname = data.get('lastname');
11
+ const birthdate = data.get('birthdate');
12
+ const choice = data.get('choice');
13
+ const comment = data.get('comment'); */
14
+ // Faire quelque chose avec les données
15
+ } catch (error) {
16
+ if (error instanceof Error) {
17
+ console.error(error.message);
18
+ }
19
+ }
20
+ }
21
+ ---
22
+
23
+ <p>Received a {Astro.request.method} request to "{Astro.request.url}".</p>
24
+ <p>
25
+ Received request headers: <code
26
+ >{JSON.stringify(Object.fromEntries(Astro.request.headers))}</code
27
+ >
28
+ </p>
@@ -0,0 +1,19 @@
1
+ export const $ = (
2
+ selector: string,
3
+ parent: Document | HTMLElement = document
4
+ ) => parent.querySelector(selector);
5
+
6
+ export const $$ = (
7
+ selector: string,
8
+ parent: Document | HTMLElement = document
9
+ ) => parent.querySelectorAll(selector);
10
+
11
+ export const getById = (id: string) => document.getElementById(id);
12
+
13
+ export const disabledFields = (
14
+ fields: (HTMLInputElement | HTMLSelectElement)[]
15
+ ) => fields?.forEach((field) => field.setAttribute('disabled', 'true'));
16
+
17
+ export const enabledFields = (
18
+ fields: (HTMLInputElement | HTMLSelectElement)[]
19
+ ) => fields?.forEach((field) => field.removeAttribute('disabled'));
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import isEmptyOrNull, { isEmptyObject, isEmptyArray } from './isEmptyOrNull';
3
+
4
+ type TisEmptyOrNullTest = {
5
+ elt: Parameters<typeof isEmptyOrNull>[0];
6
+ expected: ReturnType<typeof isEmptyOrNull>;
7
+ };
8
+
9
+ describe('isEmptyOrNull', () => {
10
+ it.each`
11
+ elt | expected
12
+ ${undefined} | ${true}
13
+ ${null} | ${true}
14
+ ${''} | ${true}
15
+ ${1982} | ${false}
16
+ ${'1983'} | ${false}
17
+ ${{}} | ${true}
18
+ ${[]} | ${true}
19
+ ${{ name: 'name' }} | ${false}
20
+ ${['name']} | ${false}
21
+ `(
22
+ 'Should return expected : $expected when elt: $elt',
23
+ ({ elt, expected }: TisEmptyOrNullTest) => {
24
+ const result = isEmptyOrNull(elt);
25
+ expect(result).toEqual(expected);
26
+ }
27
+ );
28
+ });
29
+
30
+ describe('isEmptyObject', () => {
31
+ it.each`
32
+ elt | expected
33
+ ${undefined} | ${true}
34
+ ${{}} | ${true}
35
+ ${{ name: 'name' }} | ${false}
36
+ `(
37
+ 'Should return expected : $expected when elt: $elt',
38
+ ({ elt, expected }) => {
39
+ const result = isEmptyObject(elt);
40
+ expect(result).toEqual(expected);
41
+ }
42
+ );
43
+ });
44
+
45
+ describe('isEmptyArray', () => {
46
+ it.each`
47
+ elt | expected
48
+ ${undefined} | ${true}
49
+ ${[]} | ${true}
50
+ ${['name']} | ${false}
51
+ `(
52
+ 'Should return expected : $expected when elt: $elt',
53
+ ({ elt, expected }) => {
54
+ const result = isEmptyArray(elt);
55
+ expect(result).toEqual(expected);
56
+ }
57
+ );
58
+ });
@@ -0,0 +1,6 @@
1
+ export const isEmptyObject = (elt: unknown = {}) => elt !== null && typeof elt === 'object' && Object.keys(elt).length === 0;
2
+ export const isEmptyArray = (elt: unknown = []) => Array.isArray(elt) && elt.length === 0;
3
+
4
+ const isEmptyOrNull = (elt: unknown) => elt === undefined || elt === null || elt === '' || isEmptyArray(elt) || isEmptyObject(elt);
5
+
6
+ export default isEmptyOrNull;
@@ -0,0 +1,20 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { setSlug } from './setSlug';
3
+
4
+ describe('setSlug', () => {
5
+ it.each([
6
+ ['hello world', 'hello-world'],
7
+ ['hello, world!', 'hello-world'],
8
+ ['hello(world)', 'helloworld'],
9
+ ['hello:world', 'helloworld'],
10
+ ['hello@world', 'helloworld'],
11
+ ["hello'world", 'helloworld'],
12
+ ['Hello World', 'hello-world'],
13
+ ['', ''],
14
+ [",():@'", ''],
15
+ [' ', '-----'],
16
+ ['hello, world: this is a test', 'hello-world-this-is-a-test'],
17
+ ])('should convert "%s" to "%s"', (input, expected) => {
18
+ expect(setSlug(input)).toBe(expected);
19
+ });
20
+ });
@@ -0,0 +1,7 @@
1
+ export const setSlug = (label: string) =>
2
+ label
3
+ .replace(/[,():@?!-"’.]/g, '')
4
+ .split(' ')
5
+ .filter(Boolean)
6
+ .join('-')
7
+ .toLocaleLowerCase();
@@ -0,0 +1,2 @@
1
+ export const tocObj = (toc: string[]) =>
2
+ toc.reduce((acc, item) => ({ ...acc, [`${item}`]: item }), {});
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { setClassVariant, type Variant } from './setVariants';
3
+
4
+ describe('setClassVariant', () => {
5
+ const testCases = [
6
+ [{} as Variant, ''],
7
+ [{ variant: 'primary' } as Variant, ''],
8
+ [{ className: null, variant: 'primary' } as Variant, ''],
9
+ [{ className: 'btn' } as Variant, 'btn'],
10
+ [{ className: 'btn', variant: 'primary' }, 'btn btn-primary'],
11
+ [
12
+ { className: 'btn large', variant: 'primary secondary' },
13
+ 'btn large btn-primary btn-secondary',
14
+ ],
15
+ [{ className: '', variant: '' }, ''],
16
+ [{ className: 'btn ', variant: 'primary' }, 'btn btn-primary'],
17
+ [{ className: 'btn', variant: ' primary ' }, 'btn btn-primary'],
18
+ ];
19
+
20
+ it.each(testCases)(
21
+ 'should return the correct class variant for input %j',
22
+ (input, expected) => {
23
+ expect(setClassVariant(input as Variant)).toBe(expected);
24
+ },
25
+ );
26
+ });
@@ -0,0 +1,18 @@
1
+ export type Variant = {
2
+ className?: string | null;
3
+ variant?: string;
4
+ };
5
+
6
+ export const setClassVariant = ({ variant, className }: Variant) => {
7
+ if (!variant) {
8
+ return className ?? null;
9
+ }
10
+
11
+ const classes = className?.trim()?.split(' ') ?? [];
12
+ const variants = variant?.trim()?.split(' ') ?? [];
13
+
14
+ const variantClasses = variants.map(item =>
15
+ classes[0] ? `${classes[0]}-${item}` : item,
16
+ );
17
+ return [...classes, ...variantClasses].join(' ');
18
+ };
@@ -0,0 +1,18 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const {
5
+ stroke = 'currentColor',
6
+ fill = 'currentColor',
7
+ ...props
8
+ } = Astro.props as SvgProps;
9
+ ---
10
+
11
+ <Svg {...props}>
12
+ <path
13
+ stroke={fill}
14
+ stroke-linecap="round"
15
+ stroke-linejoin="round"
16
+ stroke-width="2"
17
+ d="M6 12h6m0 0h6m-6 0v6m0-6V6"></path>
18
+ </Svg>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const {
5
+ stroke = 'currentColor',
6
+ fill = 'none',
7
+ ...props
8
+ } = Astro.props as SvgProps;
9
+ ---
10
+
11
+ <Svg
12
+ {...props}
13
+ stroke={stroke}
14
+ fill={fill}
15
+ stroke-width="2"
16
+ stroke-linecap="round"
17
+ stroke-linejoin="round"
18
+ >
19
+ <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
20
+ ></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
21
+ ></path>
22
+ </Svg>
@@ -0,0 +1,11 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const props = Astro.props as SvgProps;
5
+ ---
6
+
7
+ <Svg {...props}>
8
+ <path
9
+ d="M13.8 24c-.3 0-.7-.1-1-.3-.6-.5-.7-1.5-.2-2.1l6.7-8H1.5C.7 13.5 0 12.8 0 12s.7-1.5 1.5-1.5h17.8l-6.7-8c-.5-.6-.4-1.6.2-2.1.6-.5 1.6-.4 2.1.2L23.6 11c.1.1.2.2.2.3 0 0 0 .1.1.1 0 .1.1.2.1.3v.6c0 .1 0 .2-.1.3v.1c-.1.1-.1.2-.2.3L15 23.5c-.4.3-.8.5-1.2.5z"
10
+ ></path>
11
+ </Svg>
@@ -0,0 +1,35 @@
1
+ ---
2
+ type Props = {
3
+ fill?: string;
4
+ };
5
+
6
+ const { fill } = Astro.props;
7
+ ---
8
+
9
+ <style is:global>
10
+ #astro-logo {
11
+ fill: #000;
12
+ }
13
+ :has([aria-label='dark']) {
14
+ #astro-logo {
15
+ fill: #fff;
16
+ }
17
+ }
18
+ </style>
19
+ <svg
20
+ xmlns="http://www.w3.org/2000/svg"
21
+ width="100"
22
+ height="100"
23
+ viewBox="78 133 100 100"
24
+ xml:space="preserve"
25
+ aria-hidden="true"
26
+ >
27
+ <path
28
+ id="astro-logo"
29
+ d="M142.771 135.391c.815 1.012 1.23 2.377 2.063 5.109L163 200.175a75.587 75.587 0 0 0-21.718-7.353l-11.829-39.97a1.538 1.538 0 0 0-2.953.004l-11.685 39.945a75.6 75.6 0 0 0-21.816 7.364l18.255-59.68c.834-2.727 1.251-4.09 2.067-5.101a6.709 6.709 0 0 1 2.719-2.012c1.205-.484 2.63-.484 5.482-.484h13.038c2.855 0 4.283 0 5.489.485a6.705 6.705 0 0 1 2.722 2.018z"
30
+ ></path>
31
+ <path
32
+ fill={fill || '#FF5D01'}
33
+ d="M144.945 203.015c-2.995 2.561-8.972 4.308-15.856 4.308-8.451 0-15.534-2.632-17.414-6.17-.671 2.028-.823 4.349-.823 5.832 0 0-.442 7.279 4.622 12.343a4.76 4.76 0 0 1 4.76-4.761c4.506 0 4.5 3.932 4.497 7.122v.283c0 4.841 2.96 8.992 7.167 10.741a9.763 9.763 0 0 1-.979-4.278c0-4.617 2.71-6.336 5.86-8.334 2.507-1.592 5.291-3.356 7.211-6.899a13.01 13.01 0 0 0 1.571-6.217 13.09 13.09 0 0 0-.616-3.97z"
34
+ ></path>
35
+ </svg>
@@ -0,0 +1,11 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const props = Astro.props as SvgProps;
5
+ ---
6
+
7
+ <Svg {...props}>
8
+ <path
9
+ d="M8.5 20.5c-.4 0-.8-.2-1.2-.5L.4 13.1c-.6-.6-.6-1.7 0-2.3s1.7-.6 2.3 0l5.8 5.8L21.2 3.9c.6-.6 1.7-.6 2.3 0 .6.6.6 1.7 0 2.3L9.7 20.1c-.3.3-.7.4-1.2.4z"
10
+ ></path>
11
+ </Svg>
@@ -0,0 +1,11 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const props = Astro.props as SvgProps;
5
+ ---
6
+
7
+ <Svg {...props}>
8
+ <path
9
+ d="M12 18.854a1.71 1.71 0 0 1-1.211-.502L.507 8.071A1.713 1.713 0 0 1 2.93 5.648l9.07 9.07 9.07-9.07a1.713 1.713 0 0 1 2.423 2.423L13.212 18.353a1.712 1.712 0 0 1-1.212.501z"
10
+ ></path>
11
+ </Svg>
@@ -0,0 +1,11 @@
1
+ ---
2
+ import Svg, { type SvgProps } from '@samuelgomez/astro/components/Svg/index.astro';
3
+
4
+ const props = Astro.props as SvgProps;
5
+ ---
6
+
7
+ <Svg {...props}>
8
+ <path
9
+ d="M5.132 12.01c.001.438.169.877.504 1.211l10.296 10.268a1.715 1.715 0 0 0 2.42-2.427l-9.083-9.057 9.058-9.083A1.713 1.713 0 0 0 15.9.502L5.632 10.797a1.713 1.713 0 0 0-.5 1.213z"
10
+ ></path>
11
+ </Svg>