11---
2- import { Code } from ' astro-expressive-code/components' ;
32import Contributors from ' @/components/Contributors.astro' ;
43import Icon from ' @/components/ui/Icon.astro' ;
54import LinkButton from ' @/components/ui/LinkButton.astro' ;
65import type { GitHubContributor } from ' @/lib/github' ;
6+ import { Code } from ' astro:components' ;
77
88interface Props {
99 badge? : string ;
@@ -39,6 +39,136 @@ def run_model(messages, config):
3939 model=config.model,
4040 messages=messages,
4141 ) ` ;
42+
43+ const heroCodeScopes = {
44+ keyword: [
45+ ' keyword.control' ,
46+ ' keyword.operator' ,
47+ ' storage.type' ,
48+ ' storage.modifier' ,
49+ ' keyword.other.unit.python' ,
50+ ],
51+ decorator: [
52+ ' entity.name.function.decorator' ,
53+ ' entity.name.function.decorator.python' ,
54+ ' meta.annotation' ,
55+ ' meta.annotation punctuation' ,
56+ ],
57+ functionName: [
58+ ' entity.name.function' ,
59+ ' meta.function.python entity.name.function.python' ,
60+ ' meta.function-call.generic.python' ,
61+ ],
62+ callable: [
63+ ' support.function' ,
64+ ' support.function.builtin' ,
65+ ' support.type.property-name' ,
66+ ' meta.function-call.python' ,
67+ ],
68+ parameter: [
69+ ' variable.parameter' ,
70+ ' variable.parameter.function.python' ,
71+ ' meta.function-call.arguments.python' ,
72+ ],
73+ string: [
74+ ' string' ,
75+ ' string.quoted' ,
76+ ' comment.block.documentation' ,
77+ ' punctuation.definition.string' ,
78+ ],
79+ punctuation: [
80+ ' punctuation' ,
81+ ' meta.brace' ,
82+ ' meta.delimiter' ,
83+ ' entity.name.type' ,
84+ ],
85+ };
86+
87+ function createHeroCodeTheme(name , type , palette ) {
88+ return {
89+ name ,
90+ type ,
91+ colors: {
92+ ' editor.background' : palette .background ,
93+ ' editor.foreground' : palette .foreground ,
94+ },
95+ tokenColors: [
96+ {
97+ settings: {
98+ foreground: palette .foreground ,
99+ },
100+ },
101+ {
102+ scope: heroCodeScopes .keyword ,
103+ settings: {
104+ foreground: palette .keyword ,
105+ fontStyle: ' italic' ,
106+ },
107+ },
108+ {
109+ scope: heroCodeScopes .decorator ,
110+ settings: {
111+ foreground: palette .decorator ,
112+ },
113+ },
114+ {
115+ scope: heroCodeScopes .functionName ,
116+ settings: {
117+ foreground: palette .functionName ,
118+ },
119+ },
120+ {
121+ scope: heroCodeScopes .callable ,
122+ settings: {
123+ foreground: palette .callable ,
124+ },
125+ },
126+ {
127+ scope: heroCodeScopes .parameter ,
128+ settings: {
129+ foreground: palette .parameter ,
130+ },
131+ },
132+ {
133+ scope: heroCodeScopes .string ,
134+ settings: {
135+ foreground: palette .string ,
136+ },
137+ },
138+ {
139+ scope: heroCodeScopes .punctuation ,
140+ settings: {
141+ foreground: palette .punctuation ,
142+ },
143+ },
144+ ],
145+ };
146+ }
147+
148+ const heroCodeThemes = {
149+ light: createHeroCodeTheme (' bub-hero-light' , ' light' , {
150+ background: ' #F6F7F9' ,
151+ foreground: ' #403F53' ,
152+ keyword: ' #8844AE' ,
153+ decorator: ' #3B61B0' ,
154+ functionName: ' #3B61B0' ,
155+ callable: ' #096E72' ,
156+ parameter: ' #096E72' ,
157+ string: ' #984E4D' ,
158+ punctuation: ' #111111' ,
159+ }),
160+ dark: createHeroCodeTheme (' bub-hero-dark' , ' dark' , {
161+ background: ' #252525' ,
162+ foreground: ' #D6DEEB' ,
163+ keyword: ' #C792EA' ,
164+ decorator: ' #C5E478' ,
165+ functionName: ' #82AAFF' ,
166+ callable: ' #B2CCD6' ,
167+ parameter: ' #7FDBCA' ,
168+ string: ' #ECC48D' ,
169+ punctuation: ' #D9F5DD' ,
170+ }),
171+ };
42172---
43173
44174<section class =" pb-20 pt-14 md:pb-28 md:pt-20" aria-label =" Hero" >
@@ -81,20 +211,42 @@ def run_model(messages, config):
81211
82212 <!-- Right: code editor -->
83213 <div class =" hero-terminal min-w-0 overflow-hidden border border-border shadow-[var(--site-shadow-elevated)]" role =" img" aria-label =" Example Python code showing Bub hook implementations" >
84- <Code code ={ exampleCode } lang =" python" frame =" code" title =" hooks.py" />
214+ <div class =" expressive-code" >
215+ <figure class =" frame has-title not-content" >
216+ <figcaption class =" header" >
217+ <span class =" title" >hooks.py</span >
218+ </figcaption >
219+ <Code
220+ code ={ exampleCode }
221+ lang =" python"
222+ themes ={ {
223+ light: heroCodeThemes .light ,
224+ dark: heroCodeThemes .dark ,
225+ }}
226+ defaultColor =" light"
227+ />
228+ </figure >
229+ </div >
85230 </div >
86231 </div >
87232 </div >
88233</section >
89234
90235<style >
236+ .hero-terminal {
237+ background: var(--card);
238+ }
239+
240+ @media (min-width: 64rem) {
241+ .hero-terminal {
242+ margin-top: 4.75rem;
243+ }
244+ }
245+
91246 .hero-terminal :global(.expressive-code) {
92247 margin: 0;
93248 border: none;
94249 border-radius: 0;
95- /* Decouple frame colors from Starlight --sl-* variables;
96- use the site's own design tokens so the editor matches
97- the landing page in both light and dark mode. */
98250 --ec-brdWd: 0px;
99251 --ec-codeBg: var(--card);
100252 --ec-frm-edTabBarBg: var(--secondary);
@@ -106,18 +258,87 @@ def run_model(messages, config):
106258 --ec-frm-edActTabIndTopCol: transparent;
107259 --ec-frm-edActTabIndBtmCol: transparent;
108260 }
261+
109262 .hero-terminal :global(.expressive-code .frame) {
263+ margin: 0;
110264 border: none;
111265 border-radius: 0;
112266 box-shadow: none;
113267 }
114- .hero-terminal :global(.expressive-code .copy) {
115- display: none;
268+
269+ .hero-terminal :global(.expressive-code .header) {
270+ position: relative;
271+ display: flex;
272+ align-items: flex-end;
273+ background:
274+ linear-gradient(to top, var(--border) 1px, transparent 1px),
275+ linear-gradient(var(--secondary), var(--secondary));
276+ background-repeat: no-repeat;
277+ padding: 0;
278+ }
279+
280+ .hero-terminal :global(.expressive-code .header::before) {
281+ content: '';
282+ position: absolute;
283+ inset: 0;
284+ border: 1px solid var(--border);
285+ border-bottom: none;
286+ border-radius: inherit;
287+ pointer-events: none;
116288 }
117- .hero-terminal :global(.expressive-code pre) {
289+
290+ .hero-terminal :global(.expressive-code .title) {
291+ position: relative;
292+ display: block;
293+ color: var(--muted-foreground);
294+ background: var(--card);
295+ background-clip: padding-box;
296+ padding: 5px 15px;
297+ border: none;
298+ border-radius: 0;
299+ font-family: 'JetBrains Mono Variable', ui-monospace, monospace;
300+ font-size: 0.78rem;
301+ line-height: 1.9;
302+ letter-spacing: 0.02em;
303+ }
304+
305+ .hero-terminal :global(.expressive-code pre.astro-code) {
306+ margin: 0;
307+ padding: 0;
308+ border: none;
309+ border-radius: 0;
310+ box-shadow: none;
311+ background: var(--card) !important;
118312 font-family: 'JetBrains Mono Variable', ui-monospace, monospace;
119313 font-size: 0.78rem;
120314 line-height: 1.7;
121315 overflow-x: auto;
316+ display: flex;
317+ white-space: pre-wrap;
318+ }
319+
320+ .hero-terminal :global(.expressive-code pre.astro-code code) {
321+ display: grid;
322+ min-width: 100%;
323+ padding: 0.75rem 1.2rem;
324+ }
325+
326+ .hero-terminal :global(.expressive-code pre.astro-code .line) {
327+ display: block;
328+ min-height: 1.7em;
329+ }
330+
331+ :global(.dark) .hero-terminal :global(.expressive-code pre.astro-code),
332+ :global([data-theme='dark']) .hero-terminal :global(.expressive-code pre.astro-code) {
333+ color: var(--shiki-dark) !important;
334+ }
335+
336+ :global(.dark) .hero-terminal :global(.expressive-code pre.astro-code span[style*='--shiki-dark']),
337+ :global([data-theme='dark']) .hero-terminal :global(.expressive-code pre.astro-code span[style*='--shiki-dark']) {
338+ color: var(--shiki-dark) !important;
339+ background-color: transparent !important;
340+ font-style: var(--shiki-dark-font-style) !important;
341+ font-weight: var(--shiki-dark-font-weight) !important;
342+ text-decoration: var(--shiki-dark-text-decoration) !important;
122343 }
123344</style >
0 commit comments