Remove :global()

This commit is contained in:
DrMint 2024-05-27 20:48:00 +02:00
parent 950363785c
commit c73f586cc6
17 changed files with 279 additions and 220 deletions

View File

@ -249,3 +249,57 @@ It will produce
`Return to Home` `Return to Home`
`Return back` `Return back`
## Understand Astro's scoped CSS
By default, everything is scoped to the current custom component. This mean you can't style a custom child component.
If you do want to style a custom child component, there are two ways:
- Using :global()
- Passing a class to the child component
Passing a class will enable two things on one element of the child component (typically the root element):
- It will now have the class
- It will also have the parent component CID (Astro's Scope-CSS ID)
### Example
We have two components:
```html
// Component A
<div data-astro-cid-hnifvupa>
<p>This is Component A</p>
<ComponentB />
</div>
// Component B
<div data-astro-cid-ywfdi5qi>
<p>This is Component B</p>
</div>
```
Now if Component A pass a class "test" to Component B:
```html
<div data-astro-cid-hnifvupa>
<p>This is Component A</p>
<ComponentB class="test" />
</div>
```
The resulting Component B will be:
```
<div class="test" data-astro-cid-hnifvupa data-astro-cid-ywfdi5qi>
<p>This is Component B</p>
</div>
```
Things to consider:
- The root element of Component B (the one where we applied the CID) is now in the scope of Component A's CSS.
- The opposite isn't true: Component B's scoped CSS cannot affect Component A.

View File

@ -80,10 +80,6 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
padding: 3px; /* This way focus outline isn't cropped by overflow-x */ padding: 3px; /* This way focus outline isn't cropped by overflow-x */
gap: 8px; gap: 8px;
margin-left: -0.8em; margin-left: -0.8em;
& > :global(*) {
flex-shrink: 0;
}
} }
& > #toolbar { & > #toolbar {
@ -113,16 +109,16 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
display: flex; display: flex;
gap: 12px; gap: 12px;
& > :global(.m-only) { & > .m-only {
display: none; display: none;
} }
@media (max-width: 40rem) { @media (max-width: 40rem) {
& > :global(.m-only) { & > .m-only {
display: flex; display: flex;
} }
& > :global(.m-not) { & > .m-not {
display: none; display: none;
} }
} }

View File

@ -10,7 +10,7 @@ interface Props {
class?: string | undefined; class?: string | undefined;
} }
const { withTitle, class: className } = Astro.props; const { withTitle, ...otherProps } = Astro.props;
const { t } = await getI18n(Astro.locals.currentLocale); const { t } = await getI18n(Astro.locals.currentLocale);
const { currentCurrency } = Astro.locals; const { currentCurrency } = Astro.locals;
@ -18,7 +18,7 @@ const { currentCurrency } = Astro.locals;
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<Tooltip trigger="click" class={className}> <Tooltip trigger="click" {...otherProps.class ? otherProps : {}}>
<div id="content" slot="tooltip-content"> <div id="content" slot="tooltip-content">
{ {
cache.currencies.map((id) => ( cache.currencies.map((id) => (

View File

@ -10,7 +10,7 @@ interface Props {
class?: string | undefined; class?: string | undefined;
} }
const { withTitle, class: className } = Astro.props; const { withTitle, ...otherProps } = Astro.props;
const { currentLocale } = Astro.locals; const { currentLocale } = Astro.locals;
const { t } = await getI18n(currentLocale); const { t } = await getI18n(currentLocale);
@ -18,7 +18,7 @@ const { t } = await getI18n(currentLocale);
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<Tooltip trigger="click" class={className}> <Tooltip trigger="click" {...otherProps.class ? otherProps : {}}>
<div id="content" slot="tooltip-content"> <div id="content" slot="tooltip-content">
{ {
cache.locales.map(({ id }) => ( cache.locales.map(({ id }) => (

View File

@ -3,16 +3,18 @@ import type { EndpointAudio } from "src/shared/payload/payload-sdk";
interface Props { interface Props {
audio: EndpointAudio; audio: EndpointAudio;
class?: string | undefined;
} }
const { const {
audio: { url, mimeType }, audio: { url, mimeType },
...otherProps
} = Astro.props; } = Astro.props;
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<audio controls> <audio controls {...otherProps.class ? otherProps : {}}>
<source src={url} type={mimeType} /> <source src={url} type={mimeType} />
</audio> </audio>

View File

@ -2,20 +2,28 @@
interface Props { interface Props {
href?: string | undefined; href?: string | undefined;
disableRoundedTop?: boolean; disableRoundedTop?: boolean;
class?: string | undefined;
} }
const { href, disableRoundedTop = false } = Astro.props; const { href, disableRoundedTop = false, class: className, ...otherProps } = Astro.props;
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
{ {
href !== undefined ? ( href !== undefined ? (
<a href={href} id="card" class:list={{ "rounded-top": !disableRoundedTop }}> <a
href={href}
id="card"
class:list={[className, { "rounded-top": !disableRoundedTop }]}
{...(className ? otherProps : {})}>
<slot /> <slot />
</a> </a>
) : ( ) : (
<div id="card" class:list={{ "rounded-top": !disableRoundedTop }}> <div
id="card"
class:list={[className, { "rounded-top": !disableRoundedTop }]}
{...(className ? otherProps : {})}>
<slot /> <slot />
</div> </div>
) )
@ -37,9 +45,8 @@ const { href, disableRoundedTop = false } = Astro.props;
border: 1px solid var(--color-base-300); border: 1px solid var(--color-base-300);
box-shadow: 0 1px 2px 0 var(--color-shadow-2); box-shadow: 0 1px 2px 0 var(--color-shadow-2);
background-color: color-mix(in srgb, var(--color-elevation-2) 30%, transparent); background-color: color-mix(in srgb, var(--color-elevation-2) 30%, transparent);
}
a#card { &a {
transition-duration: 150ms; transition-duration: 150ms;
transition-property: border-color, box-shadow, background-color; transition-property: border-color, box-shadow, background-color;
@ -58,4 +65,5 @@ const { href, disableRoundedTop = false } = Astro.props;
outline-color: var(--color-base-1000); outline-color: var(--color-base-1000);
} }
} }
}
</style> </style>

View File

@ -42,8 +42,10 @@ const {
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<Card href={href} disableRoundedTop={disableRoundedTop && thumbnail !== undefined}> <Card
<div id="card"> href={href}
disableRoundedTop={disableRoundedTop && thumbnail !== undefined}
class="generic_preview-card">
{ {
thumbnail && ( thumbnail && (
<img <img
@ -58,7 +60,10 @@ const {
) )
} }
<div id="icon-container" class:list={{ "thumbnail-alt": !thumbnail }} title={iconHoverLabel}> <div
id="icon-container"
class:list={{ "thumbnail-alt": !thumbnail, "rounded-top": !disableRoundedTop }}
title={iconHoverLabel}>
<Icon name={icon} width={32} height={32} /> <Icon name={icon} width={32} height={32} />
</div> </div>
@ -96,29 +101,22 @@ const {
) )
} }
</div> </div>
</div>
</Card> </Card>
{/* ------------------------------------------- CSS -------------------------------------------- */} {/* ------------------------------------------- CSS -------------------------------------------- */}
<style> <style>
:global(a > #card) { .generic_preview-card {
& > #card > div > p > #title { position: relative;
transition-duration: 150ms; width: unset;
transition-property: color;
}
&:hover > #card > div > p { &a:hover > #footer > p {
color: var(--color-base-750); color: var(--color-base-750);
} }
&:active > #card > div > p { &a:active > #footer > p {
color: var(--color-base-1000); color: var(--color-base-1000);
} }
}
#card {
position: relative;
& > img { & > img {
width: 100%; width: 100%;
@ -140,7 +138,7 @@ const {
display: grid; display: grid;
place-content: center; place-content: center;
& > :global(svg) { & > svg {
width: 64px; width: 64px;
height: 64px; height: 64px;
} }
@ -155,9 +153,13 @@ const {
background-color: color-mix(in srgb, var(--color-elevation-2) 60%, transparent); background-color: color-mix(in srgb, var(--color-elevation-2) 60%, transparent);
} }
&.rounded-top {
border-radius: 0.7em; border-radius: 0.7em;
} }
border-bottom-right-radius: 0.7em;
}
& > #footer { & > #footer {
padding: 1em; padding: 1em;
display: flex; display: flex;
@ -165,6 +167,7 @@ const {
gap: 1.2em; gap: 1.2em;
& > p { & > p {
transition: 150ms color;
display: grid; display: grid;
& > #pretitle { & > #pretitle {

View File

@ -4,12 +4,12 @@ interface Props {
trigger?: string | undefined; trigger?: string | undefined;
} }
const { class: className, trigger } = Astro.props; const { trigger, ...otherProps } = Astro.props;
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<tippy-tooltip class={className} trigger={trigger}> <tippy-tooltip trigger={trigger} {...otherProps.class ? otherProps : {}}>
<template><slot name="tooltip-content" /></template> <template><slot name="tooltip-content" /></template>
<slot /> <slot />
</tippy-tooltip> </tippy-tooltip>

View File

@ -4,16 +4,22 @@ import { formatLocale } from "src/utils/format";
interface Props { interface Props {
video: EndpointVideo; video: EndpointVideo;
class?: string | undefined;
} }
const { const {
video: { url, thumbnail, mimeType, subtitles }, video: { url, thumbnail, mimeType, subtitles },
...otherProps
} = Astro.props; } = Astro.props;
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<video controls poster={thumbnail?.url} crossorigin="anonymous"> <video
controls
poster={thumbnail?.url}
crossorigin="anonymous"
{...otherProps.class ? otherProps : {}}>
<source src={url} type={mimeType} /> <source src={url} type={mimeType} />
{ {
subtitles.map(({ language, url }) => ( subtitles.map(({ language, url }) => (

View File

@ -57,6 +57,16 @@ const { img, name, href } = Astro.props;
border-radius: 12px; border-radius: 12px;
padding: 10%;
@media (max-width: 40rem) {
padding: 5%;
}
@media (max-width: 22rem) {
padding: 10%;
}
user-select: none; user-select: none;
aspect-ratio: 16/9; aspect-ratio: 16/9;
width: 100%; width: 100%;

View File

@ -34,8 +34,7 @@ const { title, description, notes, credits } = getLocalizedMatch(translations);
{" " /* TODO: To be removed when https://github.com/withastro/astro/issues/11103 is fixed */} {" " /* TODO: To be removed when https://github.com/withastro/astro/issues/11103 is fixed */}
<MasoTarget> <MasoTarget>
<Card> <Card class="timeline_partial-card">
<div class="event">
<div id="content"> <div id="content">
{title && <h4 class="font-xl">{title}</h4>} {title && <h4 class="font-xl">{title}</h4>}
{description && <RichText content={description} />} {description && <RichText content={description} />}
@ -51,14 +50,13 @@ const { title, description, notes, credits } = getLocalizedMatch(translations);
getLocalizedUrl(`/api/timeline/partial?id=${id}&index=${index}&lang=${locale}`)} getLocalizedUrl(`/api/timeline/partial?id=${id}&index=${index}&lang=${locale}`)}
/> />
</div> </div>
</div>
</Card> </Card>
</MasoTarget> </MasoTarget>
{/* ------------------------------------------- CSS -------------------------------------------- */} {/* ------------------------------------------- CSS -------------------------------------------- */}
<style> <style>
.event { .timeline_partial-card {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1em; gap: 1em;

View File

@ -78,7 +78,7 @@ const metaAttributes = [
audio, audio,
}}> }}>
<div id="container"> <div id="container">
<AudioPlayer audio={audio} /> <AudioPlayer audio={audio} class="audio_id-audio-player" />
<div id="info"> <div id="info">
{ {
@ -107,7 +107,7 @@ const metaAttributes = [
margin-top: 6em; margin-top: 6em;
align-items: center; align-items: center;
> :global(audio) { > .audio_id-audio-player {
width: 100%; width: 100%;
} }

View File

@ -37,8 +37,7 @@ const href = (() => {
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<Card href={href}> <Card href={href} class="content_row-card">
<div id="row">
<div id="title"> <div id="title">
{ {
content.relationTo === Collections.GenericContents ? ( content.relationTo === Collections.GenericContents ? (
@ -105,14 +104,20 @@ const href = (() => {
</div> </div>
) )
} }
</div>
</Card> </Card>
{/* ------------------------------------------- CSS -------------------------------------------- */} {/* ------------------------------------------- CSS -------------------------------------------- */}
<style> <style>
:global(a > #card) { .content_row-card {
& > #row > #title { padding: 1.5em;
display: grid;
grid-template-columns: auto 1fr auto;
gap: 1em;
align-items: center;
&a > #title {
transition-duration: 150ms; transition-duration: 150ms;
transition-property: text-decoration-color, color; transition-property: text-decoration-color, color;
@ -120,24 +125,15 @@ const href = (() => {
text-decoration-color: transparent; text-decoration-color: transparent;
} }
&:hover > #row > #title { &a:hover > #title {
color: var(--color-base-750); color: var(--color-base-750);
text-decoration-color: var(--color-base-650); text-decoration-color: var(--color-base-650);
} }
&:active > #row > #title { &a:active > #title {
color: var(--color-base-1000); color: var(--color-base-1000);
text-decoration-color: var(--color-base-1000); text-decoration-color: var(--color-base-1000);
} }
}
#row {
padding: 1.5em;
display: grid;
grid-template-columns: auto 1fr auto;
gap: 1em;
align-items: center;
& > #title { & > #title {
font-variation-settings: "wght" 600; font-variation-settings: "wght" 600;

View File

@ -11,6 +11,7 @@ interface Props {
title: string; title: string;
subtitle: string; subtitle: string;
href: string; href: string;
class?: string | undefined;
} }
const { const {
@ -18,12 +19,13 @@ const {
title, title,
subtitle, subtitle,
href, href,
...otherProps
} = Astro.props; } = Astro.props;
--- ---
{/* ------------------------------------------- HTML ------------------------------------------- */} {/* ------------------------------------------- HTML ------------------------------------------- */}
<a href={href}> <a href={href} {...otherProps.class ? otherProps : {}}>
<img <img
src={url} src={url}
srcset={sizesToSrcset(sizes)} srcset={sizesToSrcset(sizes)}

View File

@ -176,6 +176,7 @@ if (price) {
{ {
gallery && ( gallery && (
<ImageTile <ImageTile
class="collectibles_id-image_tile"
image={gallery.thumbnail} image={gallery.thumbnail}
title={t("collectibles.gallery.title")} title={t("collectibles.gallery.title")}
subtitle={t("collectibles.gallery.subtitle", { count: gallery.count })} subtitle={t("collectibles.gallery.subtitle", { count: gallery.count })}
@ -187,6 +188,7 @@ if (price) {
{ {
scans && ( scans && (
<ImageTile <ImageTile
class="collectibles_id-image_tile"
image={scans.thumbnail} image={scans.thumbnail}
title={t("collectibles.scans.title")} title={t("collectibles.scans.title")}
subtitle={t("collectibles.scans.subtitle", { count: scans.count })} subtitle={t("collectibles.scans.subtitle", { count: scans.count })}
@ -277,18 +279,16 @@ if (price) {
gap: 2.5em; gap: 2.5em;
width: 100%; width: 100%;
> :global(a) { @media (max-width: 23rem) {
> .collectibles_id-image_tile {
aspect-ratio: 2 / 1; aspect-ratio: 2 / 1;
} }
}
@media (min-width: 23rem) { @media (min-width: 23rem) {
gap: clamp(1em, 0.5em + 3vw, 2em); gap: clamp(1em, 0.5em + 3vw, 2em);
flex-direction: row; flex-direction: row;
> :global(a) {
aspect-ratio: 1 / 1;
}
@media (min-width: 52rem) { @media (min-width: 52rem) {
max-width: 15rem; max-width: 15rem;
flex-direction: column; flex-direction: column;

View File

@ -200,24 +200,8 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
margin-bottom: 24px; margin-bottom: 24px;
} }
& > a > :global(.section-button) {
margin-bottom: 24px;
}
&#library { &#library {
& > .grid { & > .grid {
& > :global(a) {
padding: 10%;
@media (max-width: 40rem) {
padding: 5%;
}
@media (max-width: 22rem) {
padding: 10%;
}
}
@media (max-width: 40rem) { @media (max-width: 40rem) {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }

View File

@ -77,7 +77,7 @@ const metaAttributes = [
video, video,
}}> }}>
<div id="container"> <div id="container">
<VideoPlayer video={video} /> <VideoPlayer class="video_id-video-player" video={video} />
<div id="info"> <div id="info">
{ {
@ -105,15 +105,15 @@ const metaAttributes = [
gap: 6em; gap: 6em;
align-items: center; align-items: center;
> :global(video) {
max-height: 60vh;
width: auto;
}
h1 { h1 {
max-width: 35em; max-width: 35em;
} }
& > .video_id-video-player {
max-height: 60vh;
width: auto;
}
& > #info { & > #info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;