@nu-appdev/northwestern-starlight-theme 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -2
- package/index.ts +71 -2
- package/package.json +1 -1
- package/src/components/Hero.astro +7 -5
- package/src/favicon.png +0 -0
- package/src/styles/navigation.css +9 -1
- package/src/virtual.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
## [1.
|
|
10
|
+
## [1.1.0] - 2026-03-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Automatic favicon — the theme ships Northwestern's official favicon and applies it without touching `public/`. Consumers can still override it with their own `favicon` in Starlight config.
|
|
15
|
+
- `homepage.imageWidth` option to control hero image size. Defaults to `500px`, useful for wide lockup images that need more space.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `showTitle: false` now works in the centered hero layout (previously only worked in split layout).
|
|
20
|
+
- Search result titles and headings no longer appear white-on-white in light mode. The `.header a` selector was too broad and bled into Pagefind's search modal.
|
|
21
|
+
- Search input focus ring now uses the Northwestern purple treatment instead of the browser's default blue outline.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Release workflow uses npm trusted publishing (OIDC) instead of long-lived tokens.
|
|
26
|
+
|
|
27
|
+
## [1.0.0] - 2026-03-25
|
|
11
28
|
|
|
12
29
|
- Initial public release
|
|
13
30
|
- Northwestern Purple color palette mapped to Starlight's accent system
|
|
@@ -17,5 +34,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
17
34
|
- OpenAPI plugin compatibility with method badge preservation
|
|
18
35
|
- Reduced motion support for transitions
|
|
19
36
|
|
|
20
|
-
[Unreleased]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.
|
|
37
|
+
[Unreleased]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.1.0...HEAD
|
|
38
|
+
[1.1.0]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.0.0...v1.1.0
|
|
21
39
|
[1.0.0]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/releases/tag/v1.0.0
|
package/index.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
1
5
|
import type { StarlightPlugin } from "@astrojs/starlight/types";
|
|
2
6
|
|
|
3
7
|
export interface NorthwesternHomepageConfig {
|
|
@@ -17,6 +21,15 @@ export interface NorthwesternHomepageConfig {
|
|
|
17
21
|
* @default true
|
|
18
22
|
*/
|
|
19
23
|
showTitle?: boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Maximum width of the hero image in the centered layout, in pixels.
|
|
27
|
+
*
|
|
28
|
+
* Use a larger value for wide lockup images (e.g., `"750px"`, `"1000px"`).
|
|
29
|
+
*
|
|
30
|
+
* @default "500px"
|
|
31
|
+
*/
|
|
32
|
+
imageWidth?: string;
|
|
20
33
|
}
|
|
21
34
|
|
|
22
35
|
export interface NorthwesternThemeConfig {
|
|
@@ -53,12 +66,27 @@ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
|
53
66
|
|
|
54
67
|
export default function northwesternTheme(config: NorthwesternThemeConfig = {}): StarlightPlugin {
|
|
55
68
|
const { homepage = {}, mermaid = true } = config;
|
|
56
|
-
const themeConfig = {
|
|
69
|
+
const themeConfig = {
|
|
70
|
+
homepage: {
|
|
71
|
+
layout: homepage.layout ?? "centered",
|
|
72
|
+
showTitle: homepage.showTitle ?? true,
|
|
73
|
+
imageWidth: homepage.imageWidth ?? "500px",
|
|
74
|
+
},
|
|
75
|
+
};
|
|
57
76
|
|
|
58
77
|
return {
|
|
59
78
|
name: "northwestern-starlight-theme",
|
|
60
79
|
hooks: {
|
|
61
80
|
async "config:setup"({ config: starlightConfig, updateConfig, addIntegration, logger }) {
|
|
81
|
+
// Apply default favicon if consumer hasn't set one
|
|
82
|
+
const consumerSetFavicon =
|
|
83
|
+
starlightConfig.favicon &&
|
|
84
|
+
(starlightConfig.favicon as unknown as { href: string }).href !== "/favicon.svg";
|
|
85
|
+
|
|
86
|
+
// Read favicon bytes once for the Vite plugin to serve
|
|
87
|
+
const faviconPath = join(dirname(fileURLToPath(import.meta.url)), "src", "favicon.png");
|
|
88
|
+
const faviconBytes = consumerSetFavicon ? null : readFileSync(faviconPath);
|
|
89
|
+
|
|
62
90
|
addIntegration({
|
|
63
91
|
name: "northwestern-theme-config",
|
|
64
92
|
hooks: {
|
|
@@ -77,14 +105,54 @@ export default function northwesternTheme(config: NorthwesternThemeConfig = {}):
|
|
|
77
105
|
}
|
|
78
106
|
},
|
|
79
107
|
},
|
|
108
|
+
// Serve the bundled favicon during dev — no file touches public/
|
|
109
|
+
...(faviconBytes
|
|
110
|
+
? [
|
|
111
|
+
{
|
|
112
|
+
name: "northwestern-theme-favicon",
|
|
113
|
+
configureServer(server: {
|
|
114
|
+
middlewares: {
|
|
115
|
+
use(
|
|
116
|
+
fn: (
|
|
117
|
+
req: IncomingMessage,
|
|
118
|
+
res: ServerResponse,
|
|
119
|
+
next: () => void,
|
|
120
|
+
) => void,
|
|
121
|
+
): void;
|
|
122
|
+
};
|
|
123
|
+
}) {
|
|
124
|
+
server.middlewares.use((req, res, next) => {
|
|
125
|
+
if (req.url === "/favicon.png") {
|
|
126
|
+
res.setHeader("Content-Type", "image/png");
|
|
127
|
+
res.setHeader(
|
|
128
|
+
"Cache-Control",
|
|
129
|
+
"public, max-age=31536000, immutable",
|
|
130
|
+
);
|
|
131
|
+
res.end(faviconBytes);
|
|
132
|
+
} else {
|
|
133
|
+
next();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
]
|
|
139
|
+
: []),
|
|
80
140
|
],
|
|
81
141
|
},
|
|
82
142
|
});
|
|
83
143
|
},
|
|
144
|
+
// Copy favicon into build output so nothing touches public/
|
|
145
|
+
"astro:build:done": ({ dir }) => {
|
|
146
|
+
if (faviconBytes) {
|
|
147
|
+
const dest = join(fileURLToPath(dir), "favicon.png");
|
|
148
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
149
|
+
copyFileSync(faviconPath, dest);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
84
152
|
},
|
|
85
153
|
});
|
|
86
154
|
// Detect mermaid availability
|
|
87
|
-
let mermaidEnabled = mermaid
|
|
155
|
+
let mermaidEnabled = mermaid;
|
|
88
156
|
|
|
89
157
|
if (mermaidEnabled) {
|
|
90
158
|
const hasMermaid = await canResolve("astro-mermaid");
|
|
@@ -102,6 +170,7 @@ export default function northwesternTheme(config: NorthwesternThemeConfig = {}):
|
|
|
102
170
|
}
|
|
103
171
|
|
|
104
172
|
updateConfig({
|
|
173
|
+
...(consumerSetFavicon ? {} : { favicon: "/favicon.png" }),
|
|
105
174
|
components: {
|
|
106
175
|
...(starlightConfig.components ?? {}),
|
|
107
176
|
Hero:
|
package/package.json
CHANGED
|
@@ -7,11 +7,12 @@ const PAGE_TITLE_ID = "_top";
|
|
|
7
7
|
const { data } = Astro.locals.starlightRoute.entry;
|
|
8
8
|
const { title = data.title, tagline, image, actions = [] } = data.hero || {};
|
|
9
9
|
|
|
10
|
+
const imageWidthPx = parseInt(themeConfig.homepage.imageWidth, 10) || 500;
|
|
11
|
+
|
|
10
12
|
const imageAttrs = {
|
|
11
13
|
loading: "eager" as const,
|
|
12
14
|
decoding: "async" as const,
|
|
13
|
-
width:
|
|
14
|
-
height: 400,
|
|
15
|
+
width: imageWidthPx,
|
|
15
16
|
alt: image?.alt || "",
|
|
16
17
|
};
|
|
17
18
|
|
|
@@ -32,9 +33,10 @@ if (image) {
|
|
|
32
33
|
const hasImage = Boolean(darkImage || lightImage || rawHtml);
|
|
33
34
|
const isSplit = hasImage && themeConfig.homepage.layout === "split";
|
|
34
35
|
const showTitle = themeConfig.homepage.showTitle;
|
|
36
|
+
const imageWidth = themeConfig.homepage.imageWidth;
|
|
35
37
|
---
|
|
36
38
|
|
|
37
|
-
<div class:list={["hero", { "hero--split": isSplit }]}>
|
|
39
|
+
<div class:list={["hero", { "hero--split": isSplit }]} style={`--hero-image-width: ${imageWidth};`}>
|
|
38
40
|
{
|
|
39
41
|
isSplit ? (
|
|
40
42
|
<>
|
|
@@ -81,7 +83,7 @@ const showTitle = themeConfig.homepage.showTitle;
|
|
|
81
83
|
</div>
|
|
82
84
|
)}
|
|
83
85
|
<div class="sl-flex copy">
|
|
84
|
-
<h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />
|
|
86
|
+
{showTitle && <h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />}
|
|
85
87
|
{tagline && <div class="tagline" set:html={tagline} />}
|
|
86
88
|
</div>
|
|
87
89
|
{actions.length > 0 && (
|
|
@@ -163,7 +165,7 @@ const showTitle = themeConfig.homepage.showTitle;
|
|
|
163
165
|
.hero-image-centered .hero-image,
|
|
164
166
|
.hero-image-centered .hero-html {
|
|
165
167
|
object-fit: contain;
|
|
166
|
-
width: min(90%, 500px);
|
|
168
|
+
width: min(90%, var(--hero-image-width, 500px));
|
|
167
169
|
height: auto;
|
|
168
170
|
}
|
|
169
171
|
|
package/src/favicon.png
ADDED
|
Binary file
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
@layer northwestern {
|
|
9
9
|
.site-title,
|
|
10
|
-
.header a,
|
|
10
|
+
.header > a,
|
|
11
|
+
.header > nav a,
|
|
11
12
|
.social-icons a,
|
|
12
13
|
starlight-theme-select,
|
|
13
14
|
starlight-theme-select label,
|
|
@@ -58,6 +59,13 @@
|
|
|
58
59
|
line-height: 1 !important;
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/* stylelint-disable-next-line selector-id-pattern -- Starlight's own ID */
|
|
63
|
+
#starlight__search input:focus {
|
|
64
|
+
--pagefind-ui-border: var(--nu-focus-border) !important;
|
|
65
|
+
outline: none !important;
|
|
66
|
+
box-shadow: 0 0 0 0.25rem var(--nu-focus-shadow-color) !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
site-search button[data-open-modal] > svg {
|
|
62
70
|
flex-shrink: 0;
|
|
63
71
|
align-self: center;
|