Skip to content

Commit 19e9372

Browse files
Slashgearclaudemickaelalvs
authored
feat: add press kit page (#595)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Mickaël Alves <alves.mckl@gmail.com>
1 parent faedf68 commit 19e9372

37 files changed

Lines changed: 1199 additions & 464 deletions

app/presse/PressKit.module.css

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
.intro {
2+
color: var(--font-color-default);
3+
max-width: 720px;
4+
line-height: 1.7;
5+
}
6+
7+
.section {
8+
margin-top: 3rem;
9+
}
10+
11+
.descriptionBlock {
12+
display: flex;
13+
flex-direction: column;
14+
gap: 0.75rem;
15+
color: var(--font-color-default);
16+
max-width: 720px;
17+
line-height: 1.7;
18+
margin-top: 1rem;
19+
}
20+
21+
.logoGrid {
22+
display: grid;
23+
grid-template-columns: 1fr;
24+
gap: 1.5rem;
25+
margin-top: 1rem;
26+
}
27+
28+
@media (min-width: 768px) {
29+
.logoGrid {
30+
grid-template-columns: repeat(2, 1fr);
31+
}
32+
}
33+
34+
.colorGrid {
35+
display: flex;
36+
flex-direction: column;
37+
gap: 1.5rem;
38+
margin-top: 1rem;
39+
}
40+
41+
@media (min-width: 600px) {
42+
.colorGrid {
43+
flex-direction: row;
44+
}
45+
}
46+
47+
.guidelineColumn {
48+
background-color: var(--background-card);
49+
border: 1px solid var(--border-light);
50+
border-radius: 12px;
51+
padding: 1.25rem;
52+
margin-top: 1rem;
53+
max-width: 600px;
54+
}
55+
56+
.guidelineList {
57+
display: flex;
58+
flex-direction: column;
59+
gap: 0.5rem;
60+
}
61+
62+
.guidelineItem {
63+
display: flex;
64+
align-items: baseline;
65+
gap: 0.5rem;
66+
font-size: 0.875rem;
67+
color: var(--font-color-default);
68+
line-height: 1.5;
69+
}
70+
71+
.guidelineIconDo {
72+
color: #4ade80;
73+
flex-shrink: 0;
74+
}

app/presse/opengraph-image.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ImageResponse } from 'next/og';
2+
import { SimpleText } from '../../modules/og/SimpleText';
3+
4+
export const runtime = 'edge';
5+
6+
export const alt = 'Kit Presse LyonJS';
7+
export const size = {
8+
width: 1200,
9+
height: 630,
10+
};
11+
export const contentType = 'image/png';
12+
13+
export default async function Image() {
14+
return new ImageResponse(<SimpleText text="Kit Presse" />, {
15+
...size,
16+
});
17+
}

app/presse/page.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Metadata } from 'next';
2+
import { Heading } from '../../modules/atoms/heading/Heading';
3+
import { LogoCard } from '../../modules/press-kit/LogoCard';
4+
import { ColorSwatch } from '../../modules/press-kit/ColorSwatch';
5+
import { logos, brandColors, guidelines } from '../../data/press-kit';
6+
import styles from './PressKit.module.css';
7+
8+
const title = 'LyonJS | Kit Presse';
9+
const description =
10+
"Retrouvez les logos, couleurs, description et consignes d'utilisation de la marque LyonJS pour vos supports de communication.";
11+
12+
export const metadata: Metadata = {
13+
title,
14+
description,
15+
twitter: {
16+
title,
17+
description,
18+
},
19+
openGraph: {
20+
title,
21+
description,
22+
},
23+
};
24+
25+
export default function PressePage() {
26+
return (
27+
<main>
28+
<Heading Component="h1">Kit Presse</Heading>
29+
<p className={styles.intro}>
30+
Retrouvez ici les ressources visuelles de LyonJS&nbsp;: logos, couleurs, description et consignes
31+
d&apos;utilisation. N&apos;hésitez pas à les utiliser pour vos articles, présentations ou supports de
32+
communication.
33+
</p>
34+
35+
<section className={styles.section}>
36+
<Heading Component="h2">A propos du LyonJS</Heading>
37+
<div className={styles.descriptionBlock}>
38+
<p>
39+
LyonJS est la communauté lyonnaise autour de JavaScript et de son écosystème. Elle organise des meetups
40+
mensuels ouverts et gratuits dédiés aux technologies Web et JavaScript/TypeScript.
41+
</p>
42+
<p>
43+
Chaque événement propose des conférences suivies d&apos;un moment convivial pour permettre aux participants
44+
d&apos;échanger et de poursuivre les discussions.
45+
</p>
46+
</div>
47+
</section>
48+
49+
<section className={styles.section}>
50+
<Heading Component="h2">Logos</Heading>
51+
<div className={styles.logoGrid}>
52+
{logos.map((logo) => (
53+
<LogoCard key={logo.name} logo={logo} />
54+
))}
55+
</div>
56+
</section>
57+
58+
<section className={styles.section}>
59+
<Heading Component="h2">Couleurs</Heading>
60+
<div className={styles.colorGrid}>
61+
{brandColors.map((color) => (
62+
<ColorSwatch key={color.hex} color={color} />
63+
))}
64+
</div>
65+
</section>
66+
67+
<section className={styles.section}>
68+
<Heading Component="h2">Consignes d&apos;utilisation</Heading>
69+
<div className={styles.guidelineColumn}>
70+
<div className={styles.guidelineList}>
71+
{guidelines.map((item) => (
72+
<div key={item.text} className={styles.guidelineItem}>
73+
<span className={styles.guidelineIconDo}>&#10003;</span>
74+
<span>{item.text}</span>
75+
</div>
76+
))}
77+
</div>
78+
</div>
79+
</section>
80+
</main>
81+
);
82+
}

app/sitemap.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
4545
changeFrequency: 'monthly',
4646
priority: 0.5,
4747
},
48+
{
49+
url: `${BASE_URL}/presse`,
50+
lastModified: new Date(),
51+
changeFrequency: 'yearly',
52+
priority: 0.4,
53+
},
4854
...Array.from(years)
4955
.toReversed()
5056
.map((year) => {

data/press-kit.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
export type LogoVariant = {
2+
format: string;
3+
filePath: string;
4+
previewPath?: string;
5+
};
6+
7+
export type LogoAsset = {
8+
name: string;
9+
description: string;
10+
variants: LogoVariant[];
11+
};
12+
13+
export type BrandColor = {
14+
name: string;
15+
description: string;
16+
hex: string;
17+
hsl: string;
18+
cssVariable: string;
19+
};
20+
21+
export type GuidelineItem = {
22+
text: string;
23+
};
24+
25+
export const logos: LogoAsset[] = [
26+
{
27+
name: 'Logo complet',
28+
description: 'Logo avec le texte "LyonJS". Version principale à privilégier.',
29+
variants: [
30+
{ format: 'SVG', filePath: '/press-kit/lyon-js-complet.svg', previewPath: '/press-kit/lyon-js-complet.svg' },
31+
{ format: 'PNG 128', filePath: '/press-kit/lyon-js-complet-128.png' },
32+
{ format: 'PNG 256', filePath: '/press-kit/lyon-js-complet-256.png' },
33+
{ format: 'PNG 512', filePath: '/press-kit/lyon-js-complet-512.png' },
34+
{ format: 'PNG 1024', filePath: '/press-kit/lyon-js-complet-1024.png' },
35+
{ format: 'WebP 128', filePath: '/press-kit/lyon-js-complet-128.webp' },
36+
{ format: 'WebP 256', filePath: '/press-kit/lyon-js-complet-256.webp' },
37+
{ format: 'WebP 512', filePath: '/press-kit/lyon-js-complet-512.webp' },
38+
{ format: 'WebP 1024', filePath: '/press-kit/lyon-js-complet-1024.webp' },
39+
],
40+
},
41+
{
42+
name: 'Icône seule',
43+
description: "Logo sans texte. À utiliser quand l'espace est limité (avatar, favicon…).",
44+
variants: [
45+
{ format: 'SVG', filePath: '/press-kit/lyon-js.svg', previewPath: '/press-kit/lyon-js.svg' },
46+
{ format: 'PNG 128', filePath: '/press-kit/lyon-js-128.png' },
47+
{ format: 'PNG 256', filePath: '/press-kit/lyon-js-256.png' },
48+
{ format: 'PNG 512', filePath: '/press-kit/lyon-js-512.png' },
49+
{ format: 'PNG 1024', filePath: '/press-kit/lyon-js-1024.png' },
50+
{ format: 'WebP 128', filePath: '/press-kit/lyon-js-128.webp' },
51+
{ format: 'WebP 256', filePath: '/press-kit/lyon-js-256.webp' },
52+
{ format: 'WebP 512', filePath: '/press-kit/lyon-js-512.webp' },
53+
{ format: 'WebP 1024', filePath: '/press-kit/lyon-js-1024.webp' },
54+
],
55+
},
56+
];
57+
58+
export const brandColors: BrandColor[] = [
59+
{
60+
name: 'Jaune LyonJS',
61+
description: 'Couleur principale de la marque',
62+
hex: '#EDD533',
63+
hsl: 'hsl(52, 83%, 62%)',
64+
cssVariable: '--yellow-0',
65+
},
66+
{
67+
name: 'Noir LyonJS',
68+
description: 'Couleur secondaire de la marque',
69+
hex: '#323330',
70+
hsl: 'hsl(60, 5%, 19%)',
71+
cssVariable: '--black-0',
72+
},
73+
];
74+
75+
export const guidelines: GuidelineItem[] = [
76+
{ text: 'Utiliser le logo sur un fond sombre pour un meilleur contraste' },
77+
{ text: 'Respecter une zone de protection autour du logo (min. 50% de sa hauteur)' },
78+
{ text: 'Utiliser les couleurs officielles de la charte' },
79+
{ text: "Pointer vers lyonjs.org lors de l'utilisation du logo" },
80+
];

0 commit comments

Comments
 (0)