Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/BackendGuidesNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const links = enPages
const { logo, sidebar } = page.data;
if (!sidebar.label) throw new Error('Backend guides must always include a sidebar label.');
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
return { title: sidebar.label, href: pageUrl, logo };
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
});
---

Expand Down
33 changes: 14 additions & 19 deletions src/components/BrandLogo.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,26 @@
import { type LogoKey, logos } from '~/data/logos';

export interface Props {
size?: `${number}rem` | `${number}px`;
size?: 'large' | 'default';
shape?: 'circle' | 'rounded';
brand: LogoKey;
}

const { brand, size = '4rem', shape = 'circle' } = Astro.props as Props;
const { file, padding } = logos[brand] || {};

// Make a rough guess at the pixel size to use as width/height attributes
const [, value, unit] = /^(\d*(?:\.\d+)?)(\w+)$/.exec(size) || ['4', 'rem'];
const valueAsNumber = parseFloat(value);
const pixelSize = unit === 'px' ? valueAsNumber : valueAsNumber * 16;
const { brand, size = 'default', shape = 'circle' } = Astro.props;
const { file, padding, bg } = logos[brand] || {};
---

{
file && (
<div class:list={['logo', shape]} style={`--logo-size: ${size}; --logo-padding: ${padding};`}>
<img
src={`/logos/${file}`}
alt=""
loading="lazy"
decoding="async"
width={pixelSize}
height={pixelSize}
/>
<div
class:list={['logo', shape]}
style={{
'--logo-size': { large: '5rem', default: '4rem' }[size],
'--logo-padding': padding,
'--logo-bg': size === 'large' && bg,
}}
>
<img src={`/logos/${file}`} alt="" loading="lazy" decoding="async" width={64} height={64} />
</div>
)
}
Expand All @@ -39,8 +34,8 @@ const pixelSize = unit === 'px' ? valueAsNumber : valueAsNumber * 16;
width: 1em;
height: 1em;
/* Allows logos to be visible in both light/dark. Hardcoded because variant colours adjust to theme */
background-color: hsl(224, 10%, 10%);
border: 1px solid hsl(224, 10%, 23%);
background-color: var(--logo-bg, hsl(224, 10%, 10%));
border: 1px solid hsla(0, 0%, 100%, 0.1);
/* Indicates the brand logo boundaries for forced colors users, transparent is changed to a solid color */
outline: 1px solid transparent;
overflow: hidden;
Expand Down
4 changes: 2 additions & 2 deletions src/components/CMSGuidesNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const links = enPages
const { logo, sidebar } = page.data;
if (!sidebar.label) throw new Error('CMS guides must always include a sidebar label.');
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
return { title: sidebar.label, href: pageUrl, logo };
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
});
---

<section>
<CardsNav minimal links={links} />
<CardsNav size="small" links={links} />
</section>
4 changes: 2 additions & 2 deletions src/components/DeployGuidesNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ const links = enPages
if (!sidebar.label) throw new Error('Deploy guides must always include a sidebar label.');
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
const tags = Object.fromEntries(supports.map((s) => [s, Astro.locals.t(`deploy.${s}Tag`)!]));
return { title: sidebar.label, href: pageUrl, logo, tags };
return { title: sidebar.label, href: pageUrl, logo: { brand: logo }, tags };
});
---

<section>
<CardsNav minimal={minimal} links={links} />
<CardsNav size={minimal ? 'small' : 'default'} links={links} />
</section>
26 changes: 26 additions & 0 deletions src/components/FeaturedCMSGuidesNav.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
import { allPages } from '~/content';
import { isCmsEntry, isEnglishEntry } from '~/content.config';
import { isLogoKey } from '~/data/logos';
import { getLanguageFromURL, stripLangFromSlug } from '~/util/path-utils';
import CardsNav from './NavGrid/CardsNav.astro';

const lang = getLanguageFromURL(Astro.url.pathname);
const featuredCmsGuides = allPages.filter(isCmsEntry).filter((entry) => entry.data.featuredListing);
const enFeaturedCmsGuides = featuredCmsGuides.filter(isEnglishEntry);
---

<CardsNav
size="large"
links={enFeaturedCmsGuides.map(({ id, data }) => {
const slugWithoutLang = stripLangFromSlug(id);
const localizedSlug = `${lang}/${slugWithoutLang}`;
const translation = featuredCmsGuides.find((page) => localizedSlug === page.id);
return {
title: translation?.data.sidebar.label || data.sidebar.label || data.title,
href: `/${localizedSlug}/`,
logo: { brand: isLogoKey(id.split('/').pop()), size: 'large', shape: 'rounded' },
description: translation?.data.featuredListing?.tagline || data.featuredListing!.tagline,
};
})}
/>
4 changes: 2 additions & 2 deletions src/components/IntegrationsNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function categoryLinksFromPages(pages: IntegrationEntry[], category: Integration
'/</span><wbr>' +
name.replaceAll('-', '&#8288;-&#8288;'),
href: pageUrl,
logo: isLogoKey(name),
logo: { brand: isLogoKey(name) },
};
});
}
Expand Down Expand Up @@ -58,7 +58,7 @@ const categories = category ? [category] : allCategories;
Object.values(categories).map((category) => (
<>
<h3>{category.title}</h3>
<CardsNav minimal links={category.links} class="integrations-nav" />
<CardsNav size="small" links={category.links} class="integrations-nav" />
</>
))
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/MediaGuidesNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const links = enPages
const { logo, sidebar } = page.data;
if (!sidebar.label) throw new Error('Media guides must always include a sidebar label.');
const pageUrl = '/' + page.id.replace('en/', `${lang}/`) + '/';
return { title: sidebar.label, href: pageUrl, logo };
return { title: sidebar.label, href: pageUrl, logo: { brand: logo } };
});
---

<section>
<CardsNav minimal links={links} />
<CardsNav size="small" links={links} />
</section>
4 changes: 2 additions & 2 deletions src/components/MigrationGuidesNav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ const links = enPages
.map((page) => {
const pageUrl = page.id.replace('en/', `/${lang}/`) + '/';
const slug = page.id.split('/').pop()?.replace('from-', '');
return { title: page.data.framework, href: pageUrl, logo: isLogoKey(slug) };
return { title: page.data.framework, href: pageUrl, logo: { brand: isLogoKey(slug) } };
});
---

<section>
<CardsNav minimal links={links} />
<CardsNav size="small" links={links} />
</section>
30 changes: 20 additions & 10 deletions src/components/NavGrid/Card.astro
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
---
import type { LogoKey } from '~/data/logos';
import type { ComponentProps, HTMLAttributes } from 'astro/types';
import BrandLogo from '../BrandLogo.astro';
import type { HTMLAttributes } from 'astro/types';

export interface Props extends HTMLAttributes<'li'> {
href: string;
logo?: LogoKey;
logo?: ComponentProps<typeof BrandLogo>;
current?: boolean;
minimal?: boolean;
size?: 'small' | 'default' | 'large';
}

const { href, logo, current, minimal, class: classes, ...attrs } = Astro.props as Props;
const { href, logo, current, size = 'default', class: classes, ...attrs } = Astro.props;
---

<li class:list={['card', minimal && 'card--minimal', classes]} {...attrs}>
{logo && <BrandLogo brand={logo} />}
<li
class:list={['card', { 'card--sm': size === 'small', 'card--lg': size === 'large' }, classes]}
{...attrs}
>
{logo && <BrandLogo {...logo} />}
<div class="stack sl-flex">
<h3>
<a href={href} aria-current={current ? 'page' : 'false'}>
<slot name="title" />
</a>
</h3>
{!minimal && <slot name="details" />}
{size !== 'small' && <slot name="details" />}
</div>
</li>

Expand All @@ -36,11 +38,19 @@ const { href, logo, current, minimal, class: classes, ...attrs } = Astro.props a
align-items: center;
border-radius: 0.5rem;
}
.card--minimal {
.card--sm {
grid-template-columns: 1fr;
justify-items: center;
text-align: center;
}
.card--lg {
gap: 1rem;
align-items: flex-start;
line-height: 1.5;
}
.card--lg .stack {
gap: 0.25rem;
}

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

.card--minimal h3 {
.card--sm h3 {
font-size: var(--sl-text-body);
}

Expand Down
15 changes: 8 additions & 7 deletions src/components/NavGrid/CardsNav.astro
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
import type { LogoKey } from '~/data/logos';
import type { ComponentProps } from 'astro/types';
import Badge from '~/components/Badge.astro';
import Card from './Card.astro';
import Grid from './Grid.astro';
import Badge from '~/components/Badge.astro';

export interface Props {
minimal?: boolean;
size?: 'small' | 'default' | 'large';
links: {
title: string;
description?: string;
href: string;
logo?: LogoKey;
logo?: ComponentProps<typeof Card>['logo'];
/** Map of tag IDs to translated tag display text, e.g. `{ static: 'Statisch' }`. */
tags?: Record<string, string>;
/** The language of the content if it differs from the main page language. */
Expand All @@ -19,18 +19,18 @@ export interface Props {
class?: string;
}

const { links, minimal = false, class: classes } = Astro.props as Props;
const { links, size, class: classes } = Astro.props as Props;

const currentPage = new URL(Astro.request.url).pathname;
---

<section class:list={['cards-nav', classes, 'not-content']}>
<slot />
<Grid minimal={minimal}>
<Grid {size}>
{
links.map(({ description, href, logo, title, tags, lang }) => (
<Card
{...{ minimal, logo, href, lang }}
{...{ size, logo, href, lang }}
current={currentPage.includes(href)}
class={Object.keys(tags || {}).join(' ')}
>
Expand All @@ -55,6 +55,7 @@ const currentPage = new URL(Astro.request.url).pathname;
.description {
color: var(--sl-color-gray-2);
font-size: var(--sl-text-body-sm);
text-wrap: pretty;
}

.tags {
Expand Down
16 changes: 12 additions & 4 deletions src/components/NavGrid/Grid.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
---
export interface Props {
minimal?: boolean;
size?: 'small' | 'default' | 'large';
}

const { minimal } = Astro.props as Props;
const { size } = Astro.props as Props;
---

<ul class:list={['fluid-grid', { 'fluid-grid--minimal': minimal }]}>
<ul
class:list={[
'fluid-grid',
{ 'fluid-grid--sm': size === 'small', 'fluid-grid--lg': size === 'large' },
]}
>
<slot />
</ul>

Expand All @@ -30,8 +35,11 @@ const { minimal } = Astro.props as Props;
}
}

.fluid-grid--minimal {
.fluid-grid--sm {
--column-min-width: 8rem;
gap: 1.5rem 0.75rem;
}
.fluid-grid--lg {
--column-min-width: 18rem;
}
</style>
18 changes: 11 additions & 7 deletions src/components/starlight/MarkdownContent.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
---
import '@astrojs/starlight/style/markdown.css';
import { getPageCategory } from '~/util/getPageCategory';
import BackendGuidesNav from '../BackendGuidesNav.astro';
import CMSGuidesNav from '../CMSGuidesNav.astro';
import DeployGuidesNav from '../DeployGuidesNav.astro';
import MediaGuidesNav from '../MediaGuidesNav.astro';
import FeaturedCMSGuidesNav from '../FeaturedCMSGuidesNav.astro';
import IntegrationsNav from '../IntegrationsNav.astro';
import MediaGuidesNav from '../MediaGuidesNav.astro';
import MigrationGuidesNav from '../MigrationGuidesNav.astro';
import { getPageCategory } from '~/util/getPageCategory';

const { entry } = Astro.locals.starlightRoute;
---
Expand All @@ -18,31 +19,34 @@ const { entry } = Astro.locals.starlightRoute;
entry.data.type === 'backend' && (
<>
<h2>{Astro.locals.t('backend.navTitle')}</h2>
<BackendGuidesNav minimal={true} />
<BackendGuidesNav minimal />
</>
)
}
{
entry.data.type === 'cms' && (
<>
<h2>{Astro.locals.t('cms.navTitle')}</h2>
<CMSGuidesNav minimal={true} />
<h3>{Astro.locals.t('cms.featuredSubheading')}</h3>
<FeaturedCMSGuidesNav />
<h3>{Astro.locals.t('cms.allSubheading')}</h3>
<CMSGuidesNav minimal />
</>
)
}
{
entry.data.type === 'deploy' && (
<>
<h2>{Astro.locals.t('deploy.altSectionTitle')}</h2>
<DeployGuidesNav minimal={true} />
<DeployGuidesNav minimal />
</>
)
}
{
entry.data.type === 'media' && (
<>
<h2>{Astro.locals.t('media.navTitle')}</h2>
<MediaGuidesNav minimal={true} />
<MediaGuidesNav minimal />
</>
)
}
Expand All @@ -58,7 +62,7 @@ const { entry } = Astro.locals.starlightRoute;
entry.data.type === 'migration' && (
<>
<h2>{Astro.locals.t('migration.navTitle')}</h2>
<MigrationGuidesNav minimal={true} />
<MigrationGuidesNav minimal />
</>
)
}
Expand Down
5 changes: 5 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export const cmsSchema = baseSchema.extend({
type: z.literal('cms'),
stub: z.boolean().default(false),
logo: z.enum(logoKeys),
featuredListing: z
.object({
tagline: z.string().min(30).max(160),
})
.optional(),
});

export const mediaSchema = baseSchema.extend({
Expand Down
2 changes: 2 additions & 0 deletions src/content/docs/en/guides/cms/cloudcannon.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type: cms
stub: true
logo: cloudcannon
i18nReady: true
featuredListing:
tagline: Git-based CMS built for speed, security, and zero headaches.
---

import Grid from '~/components/FluidGrid.astro';
Expand Down
Loading