@samuelgomez/astro 0.1.2 → 0.1.3
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.
- package/package.json +1 -1
- package/src/components/Accordion/index.astro +26 -19
- package/src/components/Box/index.astro +13 -4
- package/src/components/DebugGrid/index.astro +6 -6
- package/src/components/FormattedDate/index.astro +3 -2
- package/src/components/Home/CardsBlog.astro +34 -17
- package/src/components/Home/LastPostAccordion.astro +54 -0
- package/src/components/Link/index.astro +2 -1
- package/src/components/Nav/NavToggle.astro +7 -5
- package/src/components/Social/index.astro +33 -14
- package/src/components/Title/index.astro +10 -2
- package/src/components/layout/Footer.astro +11 -1
- package/src/components/layout/Header.astro +2 -1
- package/src/icons/LogoSG.astro +16 -5
package/package.json
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
3
|
|
|
4
|
-
export type AccordionProps = HTMLAttributes<'details'
|
|
4
|
+
export type AccordionProps = HTMLAttributes<'details'> & {
|
|
5
|
+
hasIcon?: boolean;
|
|
6
|
+
};
|
|
5
7
|
|
|
6
|
-
const props = Astro.props as AccordionProps;
|
|
8
|
+
const { hasIcon = true, ...props } = Astro.props as AccordionProps;
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
<details {...props}>
|
|
10
|
-
<summary
|
|
11
|
-
><slot name="summary"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
<summary class="summary"
|
|
13
|
+
><slot name="summary" />{
|
|
14
|
+
hasIcon && (
|
|
15
|
+
<slot name="icon">
|
|
16
|
+
<svg
|
|
17
|
+
class="chevron"
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
+
width="24"
|
|
20
|
+
height="24"
|
|
21
|
+
viewBox="0 0 24 24"
|
|
22
|
+
fill="none"
|
|
23
|
+
stroke="currentColor"
|
|
24
|
+
stroke-width="2"
|
|
25
|
+
stroke-linecap="round"
|
|
26
|
+
stroke-linejoin="round"
|
|
27
|
+
class="feather feather-chevron-down"
|
|
28
|
+
>
|
|
29
|
+
<polyline points="6 9 12 15 18 9" />
|
|
30
|
+
</svg>
|
|
31
|
+
</slot>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
27
34
|
</summary>
|
|
28
35
|
<div>
|
|
29
36
|
<slot />
|
|
@@ -33,13 +33,22 @@ const ariaLabelledBy = title ? setSlug(title) : null;
|
|
|
33
33
|
const BoxTag = tag ?? ('article' as HTMLTag);
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
<BoxTag
|
|
36
|
+
<BoxTag
|
|
37
|
+
aria-labelledby={ariaLabelledBy}
|
|
38
|
+
itemscope
|
|
39
|
+
itemtype="http://schema.org/Article"
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
37
42
|
<slot name="before-icon" />
|
|
38
43
|
|
|
39
44
|
<WrapperOrNot condition={Astro.slots.has('before-icon') && Boolean(content)}>
|
|
40
45
|
<slot name="image" />
|
|
41
|
-
{title && <Title level={titleLevel} label={title} noLink />}
|
|
42
|
-
{
|
|
43
|
-
|
|
46
|
+
{title && <Title level={titleLevel} label={title} noLink itemprop="name" />}
|
|
47
|
+
{
|
|
48
|
+
pubDate && (
|
|
49
|
+
<FormattedDate date={new Date(pubDate)} itemprop="datePublished" />
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
{Boolean(content) && <Fragment set:html={content} itemprop="text" />}
|
|
44
53
|
</WrapperOrNot>
|
|
45
54
|
</BoxTag>
|
|
@@ -49,17 +49,17 @@ import Grid from '@samuelgomez/astro/icons/Grid.astro';
|
|
|
49
49
|
height: 100%;
|
|
50
50
|
|
|
51
51
|
main {
|
|
52
|
-
--name-xs: '
|
|
52
|
+
--name-xs: 'xs : < 40rem (640px)';
|
|
53
53
|
--color-bg-cols-xs: var(--pp2);
|
|
54
|
-
--name-sm: 'sm : 640px
|
|
54
|
+
--name-sm: 'sm : >=40rem (640px)';
|
|
55
55
|
--color-bg-cols-sm: var(--bl2);
|
|
56
|
-
--name-md: 'md :
|
|
56
|
+
--name-md: 'md : >= 48rem (768px)';
|
|
57
57
|
--color-bg-cols-md: var(--og2);
|
|
58
|
-
--name-lg: 'lg :
|
|
58
|
+
--name-lg: 'lg : >= 64rem (1024px)';
|
|
59
59
|
--color-bg-cols-lg: var(--gn1);
|
|
60
|
-
--name-xl: 'xl :
|
|
60
|
+
--name-xl: 'xl : >= 80rem (1280px)';
|
|
61
61
|
--color-bg-cols-xl: var(--rd1);
|
|
62
|
-
--name-2xl: '2xl :
|
|
62
|
+
--name-2xl: '2xl : >= 96rem (1536px)';
|
|
63
63
|
--color-bg-cols-2xl: var(--tk6);
|
|
64
64
|
|
|
65
65
|
position: relative;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
type Props = {
|
|
3
3
|
date: Date;
|
|
4
|
+
itemprop?: string;
|
|
4
5
|
};
|
|
5
6
|
|
|
6
|
-
const { date } = Astro.props;
|
|
7
|
+
const { date, itemprop } = Astro.props;
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
<time datetime={date.toISOString()}>
|
|
10
|
+
<time datetime={date.toISOString()} itemprop={itemprop}>
|
|
10
11
|
{
|
|
11
12
|
date.toLocaleDateString('fr-fr', {
|
|
12
13
|
year: 'numeric',
|
|
@@ -1,38 +1,55 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Link from '@samuelgomez/astro/components/Link/index.astro';
|
|
3
|
-
import BoxPost from '@samuelgomez/astro/components/BoxPost/index.astro';
|
|
4
3
|
import ChevronRight from '@samuelgomez/astro/icons/ChevronRight.astro';
|
|
5
|
-
import { getCollection } from 'astro:content';
|
|
6
|
-
import
|
|
4
|
+
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
5
|
+
import GithubContributions from '@samuelgomez/astro/components/GithubContributions/index.astro';
|
|
6
|
+
import LastPostAccordion from '@samuelgomez/astro/components/Home/LastPostAccordion.astro';
|
|
7
7
|
import { projectAuth } from '@firebase/config';
|
|
8
|
+
|
|
8
9
|
const { currentUser } = projectAuth;
|
|
9
10
|
|
|
10
|
-
let posts = await getCollection('blog');
|
|
11
|
+
let posts = (await getCollection('blog')) as CollectionEntry<'blog'>[];
|
|
11
12
|
|
|
12
13
|
if (!currentUser) {
|
|
13
14
|
posts = posts.filter(({ data }) => data.published);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
17
|
+
let postsLight = posts.map((post) => ({
|
|
18
|
+
title: post.data.title,
|
|
19
|
+
slug: post.slug,
|
|
20
|
+
pubDate: post.data.pubDate,
|
|
21
|
+
type: post.data.type,
|
|
22
|
+
image: post.data.heroImage,
|
|
23
|
+
description: post.data.description,
|
|
24
|
+
heroImage: post.data.heroImage,
|
|
25
|
+
alt: post.data.alt,
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
// Grouper les posts par catégorie et récupérer le dernier de chaque
|
|
29
|
+
const postsByCategory = Object.groupBy(
|
|
30
|
+
postsLight,
|
|
31
|
+
({ type }) => type || 'uncategorized',
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const latestPostsByCategory = Object.values(postsByCategory)
|
|
35
|
+
.filter((latestsposts) => latestsposts !== undefined)
|
|
36
|
+
.map(
|
|
37
|
+
(latestsposts) =>
|
|
38
|
+
latestsposts.sort((a, b) => b.pubDate.valueOf() - a.pubDate.valueOf())[0],
|
|
39
|
+
);
|
|
19
40
|
---
|
|
20
41
|
|
|
21
42
|
<section>
|
|
22
43
|
<header>
|
|
23
|
-
<LogoSG size="100" />
|
|
24
44
|
<h2>Derniers articles</h2>
|
|
45
|
+
<GithubContributions />
|
|
25
46
|
<p>Voici les derniers articles de blog sur le développements Front-end.</p>
|
|
26
47
|
</header>
|
|
27
|
-
<
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
</BoxPost>
|
|
33
|
-
))
|
|
34
|
-
}
|
|
35
|
-
</section>
|
|
48
|
+
<LastPostAccordion
|
|
49
|
+
items={latestPostsByCategory}
|
|
50
|
+
name="lastposts"
|
|
51
|
+
category="blog"
|
|
52
|
+
/>
|
|
36
53
|
<footer>
|
|
37
54
|
<Link href="/blog">
|
|
38
55
|
Voir mes articles Front-end<ChevronRight slot="after-link" />
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Accordion from '@samuelgomez/astro/components/Accordion/index.astro';
|
|
3
|
+
import Title from '@samuelgomez/astro/components/Title/index.astro';
|
|
4
|
+
import Link from '@samuelgomez/astro/components/Link/index.astro';
|
|
5
|
+
import ChevronRight from '@samuelgomez/astro/icons/ChevronRight.astro';
|
|
6
|
+
import FormattedDate from '@samuelgomez/astro/components/FormattedDate/index.astro';
|
|
7
|
+
|
|
8
|
+
type AccordionVerticalProps = {
|
|
9
|
+
items: {
|
|
10
|
+
slug: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
pubDate: Date;
|
|
14
|
+
type?: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
}[];
|
|
17
|
+
name: string;
|
|
18
|
+
category: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const { items, name, category } = Astro.props as AccordionVerticalProps;
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
<section>
|
|
25
|
+
<div>
|
|
26
|
+
{
|
|
27
|
+
items.map(({ slug, title, description, pubDate, type }) => (
|
|
28
|
+
<Accordion
|
|
29
|
+
name={name}
|
|
30
|
+
open
|
|
31
|
+
hasIcon={false}
|
|
32
|
+
style={`--type-color: var(--${type}-color);`}
|
|
33
|
+
itemscope
|
|
34
|
+
itemtype="http://schema.org/Article"
|
|
35
|
+
>
|
|
36
|
+
<strong slot="summary" itemprop="genre">
|
|
37
|
+
{type}
|
|
38
|
+
</strong>
|
|
39
|
+
{title && <Title level={3} label={title} noLink itemprop="name" />}
|
|
40
|
+
{pubDate && (
|
|
41
|
+
<FormattedDate date={new Date(pubDate)} itemprop="datePublished" />
|
|
42
|
+
)}
|
|
43
|
+
<p itemprop="description">{description}</p>
|
|
44
|
+
{Boolean(slug) && (
|
|
45
|
+
<Link href={`${category ? `/${category}/${slug}` : `/${slug}`}`}>
|
|
46
|
+
Voir {title}
|
|
47
|
+
<ChevronRight slot="after-link" />
|
|
48
|
+
</Link>
|
|
49
|
+
)}
|
|
50
|
+
</Accordion>
|
|
51
|
+
))
|
|
52
|
+
}
|
|
53
|
+
</div>
|
|
54
|
+
</section>
|
|
@@ -18,7 +18,8 @@ const content = await Astro.slots.render('default');
|
|
|
18
18
|
<a
|
|
19
19
|
href={href}
|
|
20
20
|
aria-current={isCurrent ? 'page' : null}
|
|
21
|
-
rel={isExternal ? 'noopener' : null}
|
|
21
|
+
rel={isExternal ? 'nofollow noopener' : null}
|
|
22
|
+
itemprop="url"
|
|
22
23
|
{...props}
|
|
23
24
|
>
|
|
24
25
|
<slot name="before-link" />
|
|
@@ -5,7 +5,6 @@ const { 'aria-controls': ariaControls } = Astro.props;
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Button
|
|
8
|
-
class="burger"
|
|
9
8
|
variant="ghost"
|
|
10
9
|
aria-label="Toggle Navigation"
|
|
11
10
|
aria-expanded="false"
|
|
@@ -17,9 +16,12 @@ const { 'aria-controls': ariaControls } = Astro.props;
|
|
|
17
16
|
</Button>
|
|
18
17
|
|
|
19
18
|
<script>
|
|
20
|
-
const main = document.querySelector('main');
|
|
21
|
-
const footer = document.querySelector('footer');
|
|
22
|
-
document
|
|
19
|
+
const main = document.querySelector('body > main');
|
|
20
|
+
const footer = document.querySelector('body > footer');
|
|
21
|
+
const burger = document.querySelector(
|
|
22
|
+
'body > header > button[aria-expanded]'
|
|
23
|
+
);
|
|
24
|
+
burger?.addEventListener('click', (e) => {
|
|
23
25
|
const button = e?.currentTarget as HTMLButtonElement;
|
|
24
26
|
button.setAttribute(
|
|
25
27
|
'aria-expanded',
|
|
@@ -28,7 +30,7 @@ const { 'aria-controls': ariaControls } = Astro.props;
|
|
|
28
30
|
main?.toggleAttribute('inert');
|
|
29
31
|
footer?.toggleAttribute('inert');
|
|
30
32
|
});
|
|
31
|
-
|
|
33
|
+
burger?.addEventListener('keydown', (e) => {
|
|
32
34
|
const keyboardEvent = e as KeyboardEvent;
|
|
33
35
|
const button = e?.currentTarget as HTMLButtonElement;
|
|
34
36
|
if (keyboardEvent.key === 'Escape') {
|
|
@@ -4,19 +4,38 @@ import Twitter from '@samuelgomez/astro/icons/Twitter.astro';
|
|
|
4
4
|
import Github from '@samuelgomez/astro/icons/Github2.astro';
|
|
5
5
|
import Instagram from '@samuelgomez/astro/icons/Instagram.astro';
|
|
6
6
|
import Link from '@samuelgomez/astro/components/Link/index.astro';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
github = false,
|
|
10
|
+
linkedin = false,
|
|
11
|
+
twitter = false,
|
|
12
|
+
instagram = false,
|
|
13
|
+
} = Astro.props;
|
|
7
14
|
---
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
{
|
|
17
|
+
(github || linkedin || twitter || instagram) && (
|
|
18
|
+
<menu>
|
|
19
|
+
{github && (
|
|
20
|
+
<Link href="https://github.com/samuel-gomez">
|
|
21
|
+
<Github slot="after-link" title="Github de Samuel Gomez" />
|
|
22
|
+
</Link>
|
|
23
|
+
)}
|
|
24
|
+
{linkedin && (
|
|
25
|
+
<Link href="https://www.linkedin.com/in/samuel-gomez-developpeur-web/">
|
|
26
|
+
<Linkedin slot="after-link" title="Linkedin de Samuel Gomez" />
|
|
27
|
+
</Link>
|
|
28
|
+
)}
|
|
29
|
+
{twitter && (
|
|
30
|
+
<Link href="https://twitter.com/gamuez">
|
|
31
|
+
<Twitter slot="after-link" title="Twitter de Samuel Gomez" />
|
|
32
|
+
</Link>
|
|
33
|
+
)}
|
|
34
|
+
{instagram && (
|
|
35
|
+
<Link href="https://www.instagram.com/gamuez_art/">
|
|
36
|
+
<Instagram slot="after-link" title="Instagram de Samuel Gomez" />
|
|
37
|
+
</Link>
|
|
38
|
+
)}
|
|
39
|
+
</menu>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -11,9 +11,17 @@ type Props = {
|
|
|
11
11
|
level?: titleLevel;
|
|
12
12
|
noLink?: boolean;
|
|
13
13
|
id?: string;
|
|
14
|
+
itemprop?: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
label,
|
|
19
|
+
level = 1,
|
|
20
|
+
noLink,
|
|
21
|
+
id,
|
|
22
|
+
itemprop = 'headline',
|
|
23
|
+
...props
|
|
24
|
+
} = Astro.props;
|
|
17
25
|
|
|
18
26
|
const htmlLabel = await Astro.slots.render('default');
|
|
19
27
|
|
|
@@ -24,7 +32,7 @@ const title = label || htmlLabel.toString();
|
|
|
24
32
|
const Heading = `h${level}` as HTMLTag;
|
|
25
33
|
---
|
|
26
34
|
|
|
27
|
-
<Heading {...props} id={idHeading}>
|
|
35
|
+
<Heading {...props} id={idHeading} itemprop={itemprop}>
|
|
28
36
|
{
|
|
29
37
|
!noLink && idHeading && (
|
|
30
38
|
<Link href={`#${idHeading}`}>
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
const datetime = new Date();
|
|
3
|
+
const formattedDate = datetime.toISOString().split('T')[0];
|
|
4
|
+
const year = datetime.getFullYear();
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
<footer>
|
|
2
|
-
<p
|
|
8
|
+
<p>
|
|
9
|
+
© Samuel Gomez <time datetime={formattedDate} itemprop="copyrightYear"
|
|
10
|
+
>{year}</time
|
|
11
|
+
>
|
|
12
|
+
</p>
|
|
3
13
|
</footer>
|
|
@@ -8,10 +8,11 @@ import { getEntry } from 'astro:content';
|
|
|
8
8
|
import { setSlug } from '@samuelgomez/astro/helpers/setSlug';
|
|
9
9
|
|
|
10
10
|
const mainMenu = await getEntry('menu', 'main');
|
|
11
|
-
const { userEmail } = Astro.locals;
|
|
12
11
|
|
|
13
12
|
const LABEL = 'Menu de navigation principal';
|
|
14
13
|
const ID = `id-${setSlug(LABEL)}`;
|
|
14
|
+
|
|
15
|
+
const { userEmail } = Astro.props;
|
|
15
16
|
---
|
|
16
17
|
|
|
17
18
|
<header>
|
package/src/icons/LogoSG.astro
CHANGED
|
@@ -4,9 +4,20 @@ type Props = {
|
|
|
4
4
|
size?: string;
|
|
5
5
|
fill?: string;
|
|
6
6
|
opacity?: string;
|
|
7
|
+
startColor?: string;
|
|
8
|
+
endColor?: string;
|
|
7
9
|
};
|
|
10
|
+
|
|
8
11
|
const FILL = "url('#logoSG-gradient')";
|
|
9
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
title,
|
|
14
|
+
size = '32',
|
|
15
|
+
fill = FILL,
|
|
16
|
+
opacity = '1',
|
|
17
|
+
startColor = '#7A5FFF',
|
|
18
|
+
endColor = '#01FF89',
|
|
19
|
+
} = Astro.props;
|
|
20
|
+
|
|
10
21
|
const titleId = Boolean(title) ? `${crypto.randomUUID()}` : null;
|
|
11
22
|
---
|
|
12
23
|
|
|
@@ -42,19 +53,19 @@ const titleId = Boolean(title) ? `${crypto.randomUUID()}` : null;
|
|
|
42
53
|
x2="50%"
|
|
43
54
|
y2="100%"
|
|
44
55
|
>
|
|
45
|
-
<stop offset="0%" stop-color=
|
|
56
|
+
<stop offset="0%" stop-color={startColor}>
|
|
46
57
|
<animate
|
|
47
58
|
attributeName="stop-color"
|
|
48
|
-
values=
|
|
59
|
+
values={`${startColor}; ${endColor}; ${startColor}`}
|
|
49
60
|
dur="4s"
|
|
50
61
|
repeatCount="indefinite"
|
|
51
62
|
/>
|
|
52
63
|
</stop>
|
|
53
64
|
|
|
54
|
-
<stop offset="100%" stop-color=
|
|
65
|
+
<stop offset="100%" stop-color={endColor}>
|
|
55
66
|
<animate
|
|
56
67
|
attributeName="stop-color"
|
|
57
|
-
values=
|
|
68
|
+
values={`${endColor}; ${startColor}; ${endColor}`}
|
|
58
69
|
dur="4s"
|
|
59
70
|
repeatCount="indefinite"
|
|
60
71
|
/>
|