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
8 changes: 6 additions & 2 deletions site/vendor/pages-theme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Import from `@casoon/pages-theme/components` in `.astro` files; available direct
| Component | Use |
| --- | --- |
| `Hero` | Title, lead, default slot (install, badges), `output` slot (real output); `layout`, `command` and `tone` pick the variant |
| `Install` | Install command per ecosystem, CSS-only tabs, copy button |
| `Install` | Install command per ecosystem, CSS-only tabs, copy button; long commands wrap at spaces and after a `/` |
| `Badge`, `Badges` | Static badges (no external badge services) |
| `Facts` | Verifiable key figures |
| `Features` | 3–5 core points |
Expand Down Expand Up @@ -159,6 +159,9 @@ files.
| Colour field | `tone="invert"` on any layout | `Terminal`, or whatever the project shows |
| Editorial | `layout="editorial"` | `FileSet view="rail"` — names and one line each |

The split layout gives the text column a little more than half from 900 px up, with a title
size that fits about 40 characters on two lines at 1440 px; below 900 px text and output stack.

The stack layout reads as a pipeline from top to bottom: the `source` slot (usually a
`CodeBlock` with the configuration), the `command` pill, then the output — each over the full
width of the container. Side by side the three do not fit inside `--max`: the source is cut off
Expand Down Expand Up @@ -272,4 +275,5 @@ Grundlage ist das Claude-Design-Projekt „CASOON Pages Template“. Bewusst ge
- Footer mit echtem CASOON-Logo (hell/dunkel) statt Farbquadrat; alle `#`-Links durch echte
Ziele ersetzt.
- Tabs ohne JavaScript (Radio-Buttons); „Last updated“ in der Doku entfällt vorerst.
- Auf schmalen Bildschirmen rückt die Navigation in eine zweite Zeile.
- Auf schmalen Bildschirmen rückt die Navigation in eine zweite, einzeilige Zeile, die seitlich
scrollt, wenn sie nicht passt; der Theme-Umschalter bleibt neben dem Namen.
4 changes: 2 additions & 2 deletions site/vendor/pages-theme/SOURCE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@casoon/pages-theme 0.8.0
source: gh-pages-template@a03f9ef
@casoon/pages-theme 0.8.2
source: gh-pages-template@d535677
synced: 2026-10-26

Vendored copy. Do not edit here: change the theme in gh-pages-template,
Expand Down
153 changes: 92 additions & 61 deletions site/vendor/pages-theme/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,46 @@ const nav = [
];
---

<header class="header" data-website={websiteHost ? '' : undefined}>
<header class="header" data-wide={websiteHost || config.demo ? '' : undefined}>
<div class="inner">
<a class="home" href={url()}>
<span class="name">{config.name}</span>
{config.version && <span class="version">v{config.version}</span>}
</a>
{
websiteHost && (
<a class="website" href={config.website}>
{websiteHost}
</a>
)
}
<nav aria-label={s.mainNav}>
<ul>
{
nav.map((item) => (
<li>
<a href={item.href} aria-current={path.startsWith(item.href) ? 'page' : undefined}>
{item.label}
</a>
</li>
))
}
</ul>
<span class="sep" aria-hidden="true"></span>
{config.repo && <a href={`https://github.com/${config.repo}`}>GitHub</a>}
<button class="theme" type="button" data-theme-toggle aria-label={s.darkTheme} aria-pressed="false" hidden>
<!-- Shows the theme a click switches to: moon while light, sun while dark. -->
<svg class="icon-moon" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z" />
</svg>
<svg class="icon-sun" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<circle cx="12" cy="12" r="4" />
<path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.3 5.3l1.4 1.4M17.3 17.3l1.4 1.4M5.3 18.7l1.4-1.4M17.3 6.7l1.4-1.4" />
</svg>
</button>
</nav>
<div class="links">
{
websiteHost && (
<a class="website" href={config.website}>
{websiteHost}
</a>
)
}
<nav aria-label={s.mainNav}>
<ul>
{
nav.map((item) => (
<li>
<a href={item.href} aria-current={path.startsWith(item.href) ? 'page' : undefined}>
{item.label}
</a>
</li>
))
}
</ul>
<span class="sep" aria-hidden="true"></span>
{config.repo && <a href={`https://github.com/${config.repo}`}>GitHub</a>}
</nav>
</div>
<button class="theme" type="button" data-theme-toggle aria-label={s.darkTheme} aria-pressed="false" hidden>
<!-- Shows the theme a click switches to: moon while light, sun while dark. -->
<svg class="icon-moon" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z" />
</svg>
<svg class="icon-sun" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<circle cx="12" cy="12" r="4" />
<path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.3 5.3l1.4 1.4M17.3 17.3l1.4 1.4M5.3 18.7l1.4-1.4M17.3 6.7l1.4-1.4" />
</svg>
</button>
</div>
</header>

Expand Down Expand Up @@ -102,11 +104,19 @@ const nav = [
border-radius: 999px;
color: var(--text);
font-size: 13.5px;
white-space: nowrap;
}
.website:hover {
border-color: var(--accent);
color: var(--heading);
}
.links {
display: flex;
flex: 1;
align-items: center;
gap: 20px;
min-width: 0;
}
nav {
display: flex;
align-items: center;
Expand All @@ -126,6 +136,7 @@ const nav = [
border-radius: 8px;
color: var(--text);
font-size: 14.5px;
white-space: nowrap;
}
nav a:hover {
background: var(--bg-deep);
Expand All @@ -147,7 +158,8 @@ const nav = [
justify-content: center;
width: 32px;
height: 32px;
margin-left: 4px;
/* Close to the GitHub link, as if it were the last nav entry: 20px gap - 14px. */
margin-left: -14px;
border: 1px solid var(--border);
border-radius: 9px;
background: none;
Expand All @@ -172,56 +184,75 @@ const nav = [
:global([data-theme='dark']) .icon-moon {
display: none;
}
/* Narrow screens: navigation moves to a second row. */
/* Narrow screens: name and theme toggle on the first row, the links on a second row that
stays one line and scrolls sideways when it does not fit — no wrapped labels, nothing cut
off. A header with a website pill or a demo entry needs the second row earlier. */
@media (max-width: 640px) {
:global(:root) {
--header-h: 100px;
--header-h: 92px;
}
.inner {
flex-wrap: wrap;
gap: 4px 8px;
height: auto;
min-height: var(--header-h);
padding: 10px 16px;
align-content: center;
gap: 2px 8px;
height: var(--header-h);
padding: 0 16px;
}
.links {
flex: 0 0 calc(100% + 32px);
order: 3;
gap: 8px;
margin: 0 -16px;
/* Room for the focus outline, which the scroll container would clip. */
padding: 3px 8px;
overflow-x: auto;
scrollbar-width: none;
}
.theme {
margin-left: auto;
}
nav {
width: 100%;
margin-left: -8px;
margin-left: 0;
}
.sep {
display: none;
}
nav a {
padding: 7px 8px;
}
.theme {
margin-left: auto;
}
}
/* With the website pill one row needs more room, so the second row starts earlier. */
@media (max-width: 900px) {
:global(:root:has(.header[data-website])) {
--header-h: 100px;
:global(:root:has(.header[data-wide])) {
--header-h: 92px;
}
[data-website] .inner {
[data-wide] .inner {
flex-wrap: wrap;
gap: 4px 8px;
height: auto;
min-height: var(--header-h);
padding: 10px 16px;
align-content: center;
gap: 2px 8px;
height: var(--header-h);
padding: 0 16px;
}
[data-wide] .links {
flex: 0 0 calc(100% + 32px);
order: 3;
gap: 8px;
margin: 0 -16px;
/* Room for the focus outline, which the scroll container would clip. */
padding: 3px 8px;
overflow-x: auto;
scrollbar-width: none;
}
[data-website] nav {
width: 100%;
margin-left: -8px;
[data-wide] .theme {
margin-left: auto;
}
[data-wide] nav {
margin-left: 0;
}
[data-website] .sep {
[data-wide] .sep {
display: none;
}
[data-website] nav a {
[data-wide] nav a {
padding: 7px 8px;
}
[data-website] .theme {
margin-left: auto;
}
}
</style>
21 changes: 18 additions & 3 deletions site/vendor/pages-theme/components/Hero.astro
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,22 @@ const hasSource = Astro.slots.has('source');
min-width: 0;
}

/* Text gets a little more than half and a slightly smaller title, so a title of about 40
characters fits on two lines at desktop width; in two equal halves it took three. */
.is-split .inner {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
gap: 56px;
gap: 44px;
align-items: center;
}
@media (min-width: 900px) {
.is-split .inner {
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
gap: 48px;
}
.is-split h1 {
font-size: clamp(36px, 3.4vw, 48px);
}
}

.is-stack .head {
text-align: center;
Expand Down Expand Up @@ -215,10 +225,15 @@ const hasSource = Astro.slots.has('source');
gap: 32px;
margin-bottom: 44px;
}
/* Lead and actions share the row about evenly; the actions keep the install box's width, so
the badges go below it instead of squeezing the lead into a narrow column. */
.is-editorial .lead {
flex: 1 1 300px;
flex: 1 1 380px;
margin: 0;
}
.is-editorial .actions {
flex: 0 1 470px;
}

/* Dark brand ground. Child components follow through the tokens. */
.invert {
Expand Down
34 changes: 29 additions & 5 deletions site/vendor/pages-theme/components/Install.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ interface Props {
const s = t(config.lang);
const { commands, label = s.installLabel } = Astro.props;
const uid = `install-${commands.map((c) => c.label.replace(/\W/g, '')).join('-')}`;

/** Splits a command into the units a line may break between: words, and inside a word the path
segments after each "/" ("https://" is one). "./", "../", "~/" and a leading "/" stay with
what follows. Spaces are kept as separate parts. */
const units = (command: string) =>
command
.split(/( +)/)
.filter(Boolean)
.map((word) =>
word.startsWith(' ') ? word : word.split(/(?<=\/)(?!\/)(?<!^(?:\.{1,2}|~)?\/)/)
);
---

<div class="install">
Expand All @@ -37,8 +48,14 @@ const uid = `install-${commands.map((c) => c.label.replace(/\W/g, '')).join('-')
<span class="prompt" aria-hidden="true">
$
</span>
{/* Long commands scroll horizontally; tabindex keeps the region keyboard-reachable. */}
<code id={`${uid}-cmd-${i}`} tabindex="0">{c.command}</code>
{/* Long commands wrap instead of being cut off, so all of it stays visible and selectable.
Each unit is an inline-block, so a line breaks only at spaces and after a "/", never at a
hyphen; a unit wider than the box still breaks inside as a last resort. */}
<code id={`${uid}-cmd-${i}`}>
{units(c.command).map((part) =>
typeof part === 'string' ? part : part.map((unit) => <span class="unit">{unit}</span>),
)}
</code>
<button class="copy" type="button" data-copy={`${uid}-cmd-${i}`} data-copied={s.copied} hidden>
{s.copy}
</button>
Expand Down Expand Up @@ -82,7 +99,7 @@ const uid = `install-${commands.map((c) => c.label.replace(/\W/g, '')).join('-')
}
.panel {
display: none;
align-items: center;
align-items: baseline;
gap: 12px;
padding: 14px 16px;
}
Expand All @@ -103,12 +120,19 @@ const uid = `install-${commands.map((c) => c.label.replace(/\W/g, '')).join('-')
font-family: var(--font-mono);
font-size: 13px;
}
/* Breaks between units (see above); a unit longer than the line breaks anywhere. */
code {
flex: 1;
overflow: auto;
min-width: 0;
color: var(--heading);
font-size: 13.5px;
white-space: nowrap;
line-height: 1.6;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.unit {
display: inline-block;
max-width: 100%;
}
.copy {
flex-shrink: 0;
Expand Down
2 changes: 1 addition & 1 deletion site/vendor/pages-theme/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@casoon/pages-theme",
"version": "0.8.0",
"version": "0.8.2",
"private": true,
"description": "Shared Astro theme for the GitHub Pages sites of CASOON open-source projects",
"type": "module",
Expand Down
Loading