From 8e4ed92ececef4d4f47d9dc23dfbdbb99685e28f Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Wed, 19 Aug 2026 14:12:02 -0400 Subject: [PATCH] feat(styles): add new component and global CSS files --- src/styles/blocks/search.css | 92 +++++++++++++++++ src/styles/components/admonition.css | 65 ++++++++++++ src/styles/components/github-card.css | 79 +++++++++++++++ src/styles/global.css | 141 ++++++++++++++++++++++++++ 4 files changed, 377 insertions(+) create mode 100644 src/styles/blocks/search.css create mode 100644 src/styles/components/admonition.css create mode 100644 src/styles/components/github-card.css create mode 100644 src/styles/global.css diff --git a/src/styles/blocks/search.css b/src/styles/blocks/search.css new file mode 100644 index 0000000..e92dc30 --- /dev/null +++ b/src/styles/blocks/search.css @@ -0,0 +1,92 @@ +@import "@pagefind/component-ui/css" layer(pagefind); + +:root { + --pf-text-muted: var(--color-global-text); + --pf-background: var(--color-global-bg); + --pf-border-focus: var(--color-accent-2); + --pf-outline-focus: var(--color-accent); + --pf-outline-offset: none; + --pf-font: var(--font-mono); + --pf-text: var(--color-global-text); + --pf-text-secondary: var(--color-muted); + --pf-skeleton: var(--color-global-bg); + --pf-icon-search: url("data:image/svg+xml,%3Csvg fill='none' height='16' width='16' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath d='M0 0h24v24H0z' stroke='none'%3E%3C/path%3E%3Cpath d='M3 10a7 7 0 1 0 14 0 7 7 0 1 0-14 0M21 21l-6-6'%3E%3C/path%3E%3C/svg%3E"); +} + +.pf-trigger-btn { + --pf-background: #0000; + --pf-border-focus: #0000; + --pf-hover: var(--color-accent); + display: flex; + justify-content: center; + align-items: center; + width: calc(var(--spacing) * 9); + height: calc(var(--spacing) * 9); + padding: 8px; + accent-color: var(--color-accent); + border: 0; + border-radius: 0; + + &:hover { + @media (hover: hover) { + --pf-text-muted: var(--color-accent); + color: var(--color-accent); + } + } + &:focus-visible { + outline: auto; + } + + .pf-trigger-icon { + width: calc(var(--spacing) * 7); + height: calc(var(--spacing) * 7); + } +} + +dialog.pf-modal::backdrop { + backdrop-filter: blur(8px); +} + +.pf-modal-body { + --pf-hover: var(--color-global-bg); + + .pf-result-link, + .pf-heading-link { + background-size: 100% 6px; + background-position: bottom; + background-repeat: repeat-x; + background-image: linear-gradient( + transparent, + transparent 5px, + var(--color-global-text) 5px, + var(--color-global-text) + ); + + &:hover { + text-decoration: none; + background-image: linear-gradient( + transparent, + transparent 4px, + var(--color-link) 4px, + var(--color-link) + ); + } + } + + .pf-heading-link { + align-self: flex-start; + } + + .pf-heading-excerpt { + mark { + --pf-mark: var(--color-accent-2); + font-weight: var(--font-weight-semibold); + } + } +} + +.pf-keyboard-hints { + kbd { + color: var(--color-zinc-800); + } +} diff --git a/src/styles/components/admonition.css b/src/styles/components/admonition.css new file mode 100644 index 0000000..429a79f --- /dev/null +++ b/src/styles/components/admonition.css @@ -0,0 +1,65 @@ +.admonition { + --admonition-color: var(--tw-prose-quotes); + @apply border-s-2 border-(--admonition-color) py-4 ps-4; + + .admonition-title { + @apply my-0! flex items-center gap-2 text-base font-bold text-(--admonition-color) capitalize; + &:before { + @apply inline-block h-4 w-4 shrink-0 overflow-visible bg-(--admonition-color) align-middle content-['']; + mask-size: contain; + mask-position: center; + mask-repeat: no-repeat; + } + } + + .admonition-content { + > :last-child { + @apply mb-0!; + } + } + + &[data-admonition-type="note"] { + --admonition-color: var(--color-blue-400); + @apply bg-blue-400/5; + + .admonition-title::before { + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath fill='var(--admonitions-color-tip)' d='M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'%3E%3C/path%3E%3C/svg%3E"); + } + } + + &[data-admonition-type="tip"] { + --admonition-color: var(--color-lime-500); + @apply bg-lime-500/5; + + .admonition-title::before { + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z'%3E%3C/path%3E%3C/svg%3E"); + } + } + + &[data-admonition-type="important"] { + --admonition-color: var(--color-purple-400); + @apply bg-purple-400/5; + + .admonition-title::before { + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'%3E%3C/path%3E%3C/svg%3E"); + } + } + + &[data-admonition-type="caution"] { + --admonition-color: var(--color-orange-400); + @apply bg-orange-400/5; + + .admonition-title::before { + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z'%3E%3C/path%3E%3C/svg%3E"); + } + } + + &[data-admonition-type="warning"] { + --admonition-color: var(--color-red-500); + @apply bg-red-500/5; + + .admonition-title::before { + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' width='16' height='16' aria-hidden='true'%3E%3Cpath d='M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z'%3E%3C/path%3E%3C/svg%3E"); + } + } +} diff --git a/src/styles/components/github-card.css b/src/styles/components/github-card.css new file mode 100644 index 0000000..86c4468 --- /dev/null +++ b/src/styles/components/github-card.css @@ -0,0 +1,79 @@ +.github-card { + @apply bg-global-text/5 rounded-md px-4 py-3; + + .gh-title { + @apply relative flex items-center gap-2 text-base; + + .gh-avatar { + @apply bg-global-text/20 h-6 w-6 flex-none rounded-full bg-none bg-cover bg-center; + } + .gh-text { + @apply line-clamp-2; + &:after { + @apply absolute inset-0 content-['']; + } + } + .gh-icon { + @apply bg-global-text pointer-events-none ms-auto h-6 w-6 flex-none; + mask: + url("data:image/svg+xml;utf8,"); + } + .gh-forks { + --chip-image: url("data:image/svg+xml;utf8,"); + } + .gh-license { + --chip-image: url("data:image/svg+xml;utf8,"); + } + .gh-followers { + --chip-image: url("data:image/svg+xml;utf8,"); + } + .gh-repositories { + --chip-image: url("data:image/svg+xml;utf8,"); + } + .gh-language, + .gh-region { + @apply ms-auto; + } + } + + &.gh-loading { + .gh-title .gh-avatar, + .gh-description, + .gh-chips span { + @apply bg-global-text/50 animate-pulse rounded-xl text-transparent; + } + .gh-chips span:before { + @apply bg-transparent; + } + } + + &.gh-error { + .gh-avatar, + .gh-description, + .gh-chips { + @apply hidden; + } + } +} diff --git a/src/styles/global.css b/src/styles/global.css new file mode 100644 index 0000000..3c84d9b --- /dev/null +++ b/src/styles/global.css @@ -0,0 +1,141 @@ +@layer theme, base, pagefind, components, utilities; + +@import "tailwindcss/theme.css" layer(theme); +@import "tailwindcss/preflight.css" layer(base); +@import "tailwindcss/utilities.css" layer(utilities); + +/* tailwind to ignore satori generated og-image */ +@source not "../pages/og-image"; +/* config for tailwindcss-typography plugin */ +@config "../../tailwind.config.ts"; + +/* use a selector-based strategy for dark mode */ +@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *)); + +/* register custom colour properties */ +@property --color-global-bg { + syntax: ""; + inherits: true; + initial-value: oklch(98.48% 0 0); +} +@property --color-global-text { + syntax: ""; + inherits: true; + initial-value: oklch(26.99% 0.0096 235.05); +} +@property --color-muted { + syntax: ""; + inherits: true; + initial-value: oklch(44.6% 0.03 256.802); +} +@property --color-link { + syntax: ""; + inherits: true; + initial-value: oklch(55.44% 0.0431 185.69); +} +@property --color-accent { + syntax: ""; + inherits: true; + initial-value: oklch(55.27% 0.195 19.06); +} +@property --color-accent-2 { + syntax: ""; + inherits: true; + initial-value: oklch(18.15% 0 0); +} +@property --color-quote { + syntax: ""; + inherits: true; + initial-value: oklch(55.27% 0.195 19.06); +} + +/* you could refactor below to use light-dark(), depending on your target audience */ +@theme { + --color-global-bg: oklch(98.48% 0 0); + --color-global-text: oklch(26.99% 0.0096 235.05); + --color-muted: oklch(44.6% 0.03 256.802); + --color-link: oklch(55.44% 0.0431 185.69); + --color-accent: oklch(55.27% 0.195 19.06); + --color-accent-2: oklch(18.15% 0 0); + --color-quote: oklch(55.27% 0.195 19.06); +} + +@layer base { + html { + color-scheme: light dark; + accent-color: var(--color-accent); + scrollbar-gutter: stable; + + &[data-theme="light"] { + color-scheme: light; + } + + &[data-theme="dark"] { + color-scheme: dark; + --color-global-bg: oklch(23.64% 0.0045 248); + --color-global-text: oklch(83.54% 0 264); + --color-muted: oklch(70.7% 0.022 261.325); + --color-link: oklch(70.44% 0.1133 349); + --color-accent: oklch(70.91% 0.1415 163.7); + --color-accent-2: oklch(94.66% 0 0); + --color-quote: oklch(94.8% 0.106 136.49); + } + + --color-mode-transition-duration: 300ms; + --color-mode-transition-easing: ease-in-out; + + transition: + --color-global-bg var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-global-text var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-muted var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-link var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-accent var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-accent-2 var(--color-mode-transition-duration) var(--color-mode-transition-easing), + --color-quote var(--color-mode-transition-duration) var(--color-mode-transition-easing); + } + + :target { + scroll-margin-block: 5ex; + } + + @view-transition { + navigation: auto; + } + + /* Astro image responsive styles, modified from -> https://docs.astro.build/en/guides/images/#responsive-image-styles */ + :where([data-astro-image]) { + object-fit: var(--fit); + object-position: var(--pos); + } + [data-astro-image="full-width"] { + width: 100%; + } + [data-astro-image="constrained"] { + max-width: 100%; + } +} + +@layer components { + @import "./components/admonition.css"; + @import "./components/github-card.css"; + + .cactus-link { + @apply hover:decoration-link underline underline-offset-2 hover:decoration-2; + } + + .title { + @apply text-accent-2 text-2xl font-semibold; + } +} + +@utility prose { + --tw-prose-body: var(--color-global-text); + --tw-prose-bold: var(--color-global-text); + --tw-prose-bullets: var(--color-global-text); + --tw-prose-code: var(--color-global-text); + --tw-prose-headings: var(--color-accent-2); + --tw-prose-hr: 0.5px dashed #666; + --tw-prose-links: var(--color-global-text); + --tw-prose-quotes: var(--color-quote); + --tw-prose-th-borders: #666; +}