Skip to content

Commit 9d57eaf

Browse files
delucissarah11918HiDeoo
authored
Add featured CMS grid to navigation (#13247)
Co-authored-by: sarahrainsberger <sarahrainsberger@gmail.com> Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
1 parent 4cba280 commit 9d57eaf

18 files changed

+132
-63
lines changed

src/components/BackendGuidesNav.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const links = enPages
1414
const { logo, sidebar } = page.data;
1515
if (!sidebar.label) throw new Error('Backend guides must always include a sidebar label.');
1616
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
17-
return { title: sidebar.label, href: pageUrl, logo };
17+
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
1818
});
1919
---
2020

src/components/BrandLogo.astro

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,26 @@
22
import { type LogoKey, logos } from '~/data/logos';
33
44
export interface Props {
5-
size?: `${number}rem` | `${number}px`;
5+
size?: 'large' | 'default';
66
shape?: 'circle' | 'rounded';
77
brand: LogoKey;
88
}
99
10-
const { brand, size = '4rem', shape = 'circle' } = Astro.props as Props;
11-
const { file, padding } = logos[brand] || {};
12-
13-
// Make a rough guess at the pixel size to use as width/height attributes
14-
const [, value, unit] = /^(\d*(?:\.\d+)?)(\w+)$/.exec(size) || ['4', 'rem'];
15-
const valueAsNumber = parseFloat(value);
16-
const pixelSize = unit === 'px' ? valueAsNumber : valueAsNumber * 16;
10+
const { brand, size = 'default', shape = 'circle' } = Astro.props;
11+
const { file, padding, bg } = logos[brand] || {};
1712
---
1813

1914
{
2015
file && (
21-
<div class:list={['logo', shape]} style={`--logo-size: ${size}; --logo-padding: ${padding};`}>
22-
<img
23-
src={`/logos/${file}`}
24-
alt=""
25-
loading="lazy"
26-
decoding="async"
27-
width={pixelSize}
28-
height={pixelSize}
29-
/>
16+
<div
17+
class:list={['logo', shape]}
18+
style={{
19+
'--logo-size': { large: '5rem', default: '4rem' }[size],
20+
'--logo-padding': padding,
21+
'--logo-bg': size === 'large' && bg,
22+
}}
23+
>
24+
<img src={`/logos/${file}`} alt="" loading="lazy" decoding="async" width={64} height={64} />
3025
</div>
3126
)
3227
}
@@ -39,8 +34,8 @@ const pixelSize = unit === 'px' ? valueAsNumber : valueAsNumber * 16;
3934
width: 1em;
4035
height: 1em;
4136
/* Allows logos to be visible in both light/dark. Hardcoded because variant colours adjust to theme */
42-
background-color: hsl(224, 10%, 10%);
43-
border: 1px solid hsl(224, 10%, 23%);
37+
background-color: var(--logo-bg, hsl(224, 10%, 10%));
38+
border: 1px solid hsla(0, 0%, 100%, 0.1);
4439
/* Indicates the brand logo boundaries for forced colors users, transparent is changed to a solid color */
4540
outline: 1px solid transparent;
4641
overflow: hidden;

src/components/CMSGuidesNav.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ const links = enPages
1414
const { logo, sidebar } = page.data;
1515
if (!sidebar.label) throw new Error('CMS guides must always include a sidebar label.');
1616
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
17-
return { title: sidebar.label, href: pageUrl, logo };
17+
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
1818
});
1919
---
2020

2121
<section>
22-
<CardsNav minimal links={links} />
22+
<CardsNav size="small" links={links} />
2323
</section>

src/components/DeployGuidesNav.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ const links = enPages
2121
if (!sidebar.label) throw new Error('Deploy guides must always include a sidebar label.');
2222
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
2323
const tags = Object.fromEntries(supports.map((s) => [s, Astro.locals.t(`deploy.${s}Tag`)!]));
24-
return { title: sidebar.label, href: pageUrl, logo, tags };
24+
return { title: sidebar.label, href: pageUrl, logo: { brand: logo }, tags };
2525
});
2626
---
2727

2828
<section>
29-
<CardsNav minimal={minimal} links={links} />
29+
<CardsNav size={minimal ? 'small' : 'default'} links={links} />
3030
</section>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
import { allPages } from '~/content';
3+
import { isCmsEntry, isEnglishEntry } from '~/content.config';
4+
import { isLogoKey } from '~/data/logos';
5+
import { getLanguageFromURL, stripLangFromSlug } from '~/util/path-utils';
6+
import CardsNav from './NavGrid/CardsNav.astro';
7+
8+
const lang = getLanguageFromURL(Astro.url.pathname);
9+
const featuredCmsGuides = allPages.filter(isCmsEntry).filter((entry) => entry.data.featuredListing);
10+
const enFeaturedCmsGuides = featuredCmsGuides.filter(isEnglishEntry);
11+
---
12+
13+
<CardsNav
14+
size="large"
15+
links={enFeaturedCmsGuides.map(({ id, data }) => {
16+
const slugWithoutLang = stripLangFromSlug(id);
17+
const localizedSlug = `${lang}/${slugWithoutLang}`;
18+
const translation = featuredCmsGuides.find((page) => localizedSlug === page.id);
19+
return {
20+
title: translation?.data.sidebar.label || data.sidebar.label || data.title,
21+
href: `/${localizedSlug}/`,
22+
logo: { brand: isLogoKey(id.split('/').pop()), size: 'large', shape: 'rounded' },
23+
description: translation?.data.featuredListing?.tagline || data.featuredListing!.tagline,
24+
};
25+
})}
26+
/>

src/components/IntegrationsNav.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function categoryLinksFromPages(pages: IntegrationEntry[], category: Integration
2828
'/</span><wbr>' +
2929
name.replaceAll('-', '&#8288;-&#8288;'),
3030
href: pageUrl,
31-
logo: isLogoKey(name),
31+
logo: { brand: isLogoKey(name) },
3232
};
3333
});
3434
}
@@ -58,7 +58,7 @@ const categories = category ? [category] : allCategories;
5858
Object.values(categories).map((category) => (
5959
<>
6060
<h3>{category.title}</h3>
61-
<CardsNav minimal links={category.links} class="integrations-nav" />
61+
<CardsNav size="small" links={category.links} class="integrations-nav" />
6262
</>
6363
))
6464
}

src/components/MediaGuidesNav.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ const links = enPages
1414
const { logo, sidebar } = page.data;
1515
if (!sidebar.label) throw new Error('Media guides must always include a sidebar label.');
1616
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
17-
return { title: sidebar.label, href: pageUrl, logo };
17+
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
1818
});
1919
---
2020

2121
<section>
22-
<CardsNav minimal links={links} />
22+
<CardsNav size="small" links={links} />
2323
</section>

src/components/MigrationGuidesNav.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ const links = enPages
1717
.map((page) => {
1818
const pageUrl = page.id.replace('en/', `/${lang}/`) + '/';
1919
const slug = page.id.split('/').pop()?.replace('from-', '');
20-
return { title: page.data.framework, href: pageUrl, logo: isLogoKey(slug) };
20+
return { title: page.data.framework, href: pageUrl, logo: { brand: isLogoKey(slug) } };
2121
});
2222
---
2323

2424
<section>
25-
<CardsNav minimal links={links} />
25+
<CardsNav size="small" links={links} />
2626
</section>

src/components/NavGrid/Card.astro

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
---
2-
import type { LogoKey } from '~/data/logos';
2+
import type { ComponentProps, HTMLAttributes } from 'astro/types';
33
import BrandLogo from '../BrandLogo.astro';
4-
import type { HTMLAttributes } from 'astro/types';
54
65
export interface Props extends HTMLAttributes<'li'> {
76
href: string;
8-
logo?: LogoKey;
7+
logo?: ComponentProps<typeof BrandLogo>;
98
current?: boolean;
10-
minimal?: boolean;
9+
size?: 'small' | 'default' | 'large';
1110
}
1211
13-
const { href, logo, current, minimal, class: classes, ...attrs } = Astro.props as Props;
12+
const { href, logo, current, size = 'default', class: classes, ...attrs } = Astro.props;
1413
---
1514

16-
<li class:list={['card', minimal && 'card--minimal', classes]} {...attrs}>
17-
{logo && <BrandLogo brand={logo} />}
15+
<li
16+
class:list={['card', { 'card--sm': size === 'small', 'card--lg': size === 'large' }, classes]}
17+
{...attrs}
18+
>
19+
{logo && <BrandLogo {...logo} />}
1820
<div class="stack sl-flex">
1921
<h3>
2022
<a href={href} aria-current={current ? 'page' : 'false'}>
2123
<slot name="title" />
2224
</a>
2325
</h3>
24-
{!minimal && <slot name="details" />}
26+
{size !== 'small' && <slot name="details" />}
2527
</div>
2628
</li>
2729

@@ -36,11 +38,19 @@ const { href, logo, current, minimal, class: classes, ...attrs } = Astro.props a
3638
align-items: center;
3739
border-radius: 0.5rem;
3840
}
39-
.card--minimal {
41+
.card--sm {
4042
grid-template-columns: 1fr;
4143
justify-items: center;
4244
text-align: center;
4345
}
46+
.card--lg {
47+
gap: 1rem;
48+
align-items: flex-start;
49+
line-height: 1.5;
50+
}
51+
.card--lg .stack {
52+
gap: 0.25rem;
53+
}
4454

4555
.card:hover,
4656
.card:focus-within {
@@ -65,7 +75,7 @@ const { href, logo, current, minimal, class: classes, ...attrs } = Astro.props a
6575
font-weight: 600;
6676
}
6777

68-
.card--minimal h3 {
78+
.card--sm h3 {
6979
font-size: var(--sl-text-body);
7080
}
7181

src/components/NavGrid/CardsNav.astro

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
---
2-
import type { LogoKey } from '~/data/logos';
2+
import type { ComponentProps } from 'astro/types';
3+
import Badge from '~/components/Badge.astro';
34
import Card from './Card.astro';
45
import Grid from './Grid.astro';
5-
import Badge from '~/components/Badge.astro';
66
77
export interface Props {
8-
minimal?: boolean;
8+
size?: 'small' | 'default' | 'large';
99
links: {
1010
title: string;
1111
description?: string;
1212
href: string;
13-
logo?: LogoKey;
13+
logo?: ComponentProps<typeof Card>['logo'];
1414
/** Map of tag IDs to translated tag display text, e.g. `{ static: 'Statisch' }`. */
1515
tags?: Record<string, string>;
1616
/** The language of the content if it differs from the main page language. */
@@ -19,18 +19,18 @@ export interface Props {
1919
class?: string;
2020
}
2121
22-
const { links, minimal = false, class: classes } = Astro.props as Props;
22+
const { links, size, class: classes } = Astro.props as Props;
2323
2424
const currentPage = new URL(Astro.request.url).pathname;
2525
---
2626

2727
<section class:list={['cards-nav', classes, 'not-content']}>
2828
<slot />
29-
<Grid minimal={minimal}>
29+
<Grid {size}>
3030
{
3131
links.map(({ description, href, logo, title, tags, lang }) => (
3232
<Card
33-
{...{ minimal, logo, href, lang }}
33+
{...{ size, logo, href, lang }}
3434
current={currentPage.includes(href)}
3535
class={Object.keys(tags || {}).join(' ')}
3636
>
@@ -55,6 +55,7 @@ const currentPage = new URL(Astro.request.url).pathname;
5555
.description {
5656
color: var(--sl-color-gray-2);
5757
font-size: var(--sl-text-body-sm);
58+
text-wrap: pretty;
5859
}
5960

6061
.tags {

0 commit comments

Comments
 (0)