@fifthbell/brokaw 0.1.39
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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/carousels.d.ts +1 -0
- package/dist/carousels.js +65 -0
- package/dist/components/live-program/LiveProgram.d.ts +8 -0
- package/dist/components/live-program/LiveProgram.js +526 -0
- package/dist/components/live-program/assets.d.ts +14 -0
- package/dist/components/live-program/assets.js +14 -0
- package/dist/components/live-program/components/Marquee.d.ts +16 -0
- package/dist/components/live-program/components/Marquee.js +88 -0
- package/dist/components/live-program/components/MarqueeCurtain.d.ts +5 -0
- package/dist/components/live-program/components/MarqueeCurtain.js +30 -0
- package/dist/components/live-program/components/WorldClocks.d.ts +19 -0
- package/dist/components/live-program/components/WorldClocks.js +101 -0
- package/dist/components/live-program/components/slides/ArticleSlide.d.ts +14 -0
- package/dist/components/live-program/components/slides/ArticleSlide.js +22 -0
- package/dist/components/live-program/components/slides/CallsignSlide.d.ts +6 -0
- package/dist/components/live-program/components/slides/CallsignSlide.js +49 -0
- package/dist/components/live-program/components/slides/slideStyles.d.ts +1 -0
- package/dist/components/live-program/components/slides/slideStyles.js +64 -0
- package/dist/components/live-program/events.d.ts +34 -0
- package/dist/components/live-program/events.js +167 -0
- package/dist/components/live-program/hooks/useSSE.d.ts +11 -0
- package/dist/components/live-program/hooks/useSSE.js +67 -0
- package/dist/components/live-program/i18n.d.ts +4 -0
- package/dist/components/live-program/i18n.js +290 -0
- package/dist/components/live-program/segments/ArticlesSegment.d.ts +6 -0
- package/dist/components/live-program/segments/ArticlesSegment.js +160 -0
- package/dist/components/live-program/segments/EarthquakeSegment.d.ts +16 -0
- package/dist/components/live-program/segments/EarthquakeSegment.js +130 -0
- package/dist/components/live-program/segments/MarketsSegment.d.ts +12 -0
- package/dist/components/live-program/segments/MarketsSegment.js +87 -0
- package/dist/components/live-program/segments/WeatherSegment.d.ts +15 -0
- package/dist/components/live-program/segments/WeatherSegment.js +184 -0
- package/dist/components/live-program/segments/index.d.ts +6 -0
- package/dist/components/live-program/segments/index.js +6 -0
- package/dist/components/live-program/segments/types.d.ts +23 -0
- package/dist/components/live-program/segments/types.js +1 -0
- package/dist/components/live-program/segments/usePlaylistEngine.d.ts +9 -0
- package/dist/components/live-program/segments/usePlaylistEngine.js +108 -0
- package/dist/components/live-program/utils/broadcastTime.d.ts +12 -0
- package/dist/components/live-program/utils/broadcastTime.js +33 -0
- package/dist/homepage-distributor.d.ts +55 -0
- package/dist/homepage-distributor.js +68 -0
- package/dist/instagram-image-template.d.ts +8 -0
- package/dist/instagram-image-template.js +200 -0
- package/dist/outlet-config.d.ts +23 -0
- package/dist/outlet-config.js +23 -0
- package/dist/renderer.browser.d.ts +2 -0
- package/dist/renderer.browser.js +128 -0
- package/dist/renderer.core.d.ts +9 -0
- package/dist/renderer.core.js +353 -0
- package/dist/renderer.d.ts +3 -0
- package/dist/renderer.js +3 -0
- package/dist/renderer.node.d.ts +2 -0
- package/dist/renderer.node.js +71 -0
- package/dist/types/canonical-article.d.ts +247 -0
- package/dist/types/canonical-article.js +235 -0
- package/dist/utils/sofascore.d.ts +3 -0
- package/dist/utils/sofascore.js +31 -0
- package/package.json +78 -0
- package/src/partial-deps.json +52 -0
- package/src/styles/compiled.css +2 -0
- package/src/templates/layouts/404.hbs +5 -0
- package/src/templates/layouts/article-page.hbs +5 -0
- package/src/templates/layouts/category-page.hbs +5 -0
- package/src/templates/layouts/homepage.hbs +5 -0
- package/src/templates/layouts/link-in-bio.hbs +228 -0
- package/src/templates/layouts/live-story.hbs +5 -0
- package/src/templates/layouts/search-page.hbs +5 -0
- package/src/templates/partials/blocks/audio.hbs +12 -0
- package/src/templates/partials/blocks/data-table.hbs +23 -0
- package/src/templates/partials/blocks/divider.hbs +1 -0
- package/src/templates/partials/blocks/heading.hbs +9 -0
- package/src/templates/partials/blocks/image.hbs +6 -0
- package/src/templates/partials/blocks/info-box.hbs +8 -0
- package/src/templates/partials/blocks/instagram.hbs +28 -0
- package/src/templates/partials/blocks/key-points.hbs +8 -0
- package/src/templates/partials/blocks/list.hbs +13 -0
- package/src/templates/partials/blocks/live-update.hbs +24 -0
- package/src/templates/partials/blocks/pull-quote.hbs +6 -0
- package/src/templates/partials/blocks/rich-text.hbs +1 -0
- package/src/templates/partials/blocks/tiktok.hbs +15 -0
- package/src/templates/partials/blocks/x.hbs +74 -0
- package/src/templates/partials/blocks/youtube.hbs +12 -0
- package/src/templates/partials/components/article-main.hbs +159 -0
- package/src/templates/partials/components/breaking-news/live-updates-column.hbs +29 -0
- package/src/templates/partials/components/breaking-news.hbs +56 -0
- package/src/templates/partials/components/category/header.hbs +5 -0
- package/src/templates/partials/components/category/main-grid.hbs +55 -0
- package/src/templates/partials/components/category/main.hbs +7 -0
- package/src/templates/partials/components/category/more-grid.hbs +26 -0
- package/src/templates/partials/components/editorial-hero.hbs +73 -0
- package/src/templates/partials/components/headline.hbs +15 -0
- package/src/templates/partials/components/hero-editorial.hbs +1 -0
- package/src/templates/partials/components/hero.hbs +1 -0
- package/src/templates/partials/components/home/landing.hbs +111 -0
- package/src/templates/partials/components/home/main.hbs +63 -0
- package/src/templates/partials/components/home/more-stories.hbs +23 -0
- package/src/templates/partials/components/home/must-read.hbs +77 -0
- package/src/templates/partials/components/live-story/main.hbs +229 -0
- package/src/templates/partials/components/not-found/main.hbs +28 -0
- package/src/templates/partials/components/search/main.hbs +420 -0
- package/src/templates/partials/components/snack.hbs +92 -0
- package/src/templates/partials/components/spotlight-hero.hbs +59 -0
- package/src/templates/partials/components/trending.hbs +14 -0
- package/src/templates/partials/components/ui/accordion.hbs +30 -0
- package/src/templates/partials/components/ui/breadcrumb.hbs +16 -0
- package/src/templates/partials/components/ui/icon-button.hbs +19 -0
- package/src/templates/partials/components/ui/loading-spinner.hbs +27 -0
- package/src/templates/partials/components/ui/pagination.hbs +56 -0
- package/src/templates/partials/components/ui/scroll-area.hbs +12 -0
- package/src/templates/partials/components/ui/status-badge.hbs +21 -0
- package/src/templates/partials/footers/footer-full.hbs +79 -0
- package/src/templates/partials/footers/footer-minimal.hbs +5 -0
- package/src/templates/partials/headers/header-main.hbs +397 -0
- package/src/templates/partials/headers/header-minimal.hbs +16 -0
- package/src/templates/partials/nav/nav-categories.hbs +5 -0
- package/src/templates/partials/shell/doc-end.hbs +282 -0
- package/src/templates/partials/shell/doc-start-404.hbs +28 -0
- package/src/templates/partials/shell/doc-start-standard.hbs +68 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<div class='inline-flex items-center justify-center gap-2 {{#if className}}{{className}}{{/if}}' role='status' aria-live='polite'>
|
|
2
|
+
{{#if (eq size "sm")}}
|
|
3
|
+
<svg viewBox='0 0 24 24' class='h-4 w-4 text-[#b21100] dark:text-[#ff2e1a]' fill='none' aria-hidden='true'>
|
|
4
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2' opacity='0.15'/>
|
|
5
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-dasharray='16 40' fill='none'>
|
|
6
|
+
<animateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='0.75s' repeatCount='indefinite'/>
|
|
7
|
+
</circle>
|
|
8
|
+
</svg>
|
|
9
|
+
{{else}}
|
|
10
|
+
{{#if (eq size "lg")}}
|
|
11
|
+
<svg viewBox='0 0 24 24' class='h-12 w-12 text-[#b21100] dark:text-[#ff2e1a]' fill='none' aria-hidden='true'>
|
|
12
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2' opacity='0.15'/>
|
|
13
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-dasharray='20 36' fill='none'>
|
|
14
|
+
<animateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='0.75s' repeatCount='indefinite'/>
|
|
15
|
+
</circle>
|
|
16
|
+
</svg>
|
|
17
|
+
{{else}}
|
|
18
|
+
<svg viewBox='0 0 24 24' class='h-8 w-8 text-[#b21100] dark:text-[#ff2e1a]' fill='none' aria-hidden='true'>
|
|
19
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2' opacity='0.15'/>
|
|
20
|
+
<circle cx='12' cy='12' r='9' stroke='currentColor' stroke-width='2.25' stroke-linecap='round' stroke-dasharray='18 38' fill='none'>
|
|
21
|
+
<animateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='0.75s' repeatCount='indefinite'/>
|
|
22
|
+
</circle>
|
|
23
|
+
</svg>
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{/if}}
|
|
26
|
+
<span class='sr-only'>{{coalesce label "Loading"}}</span>
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<nav aria-label='Pagination' class='flex items-center justify-center gap-6 {{#if className}}{{className}}{{/if}}'>
|
|
2
|
+
{{#if prev.url}}
|
|
3
|
+
<a
|
|
4
|
+
href='{{prev.url}}'
|
|
5
|
+
class='inline-flex items-center gap-1 text-sm font-medium text-slate-500 dark:text-slate-400 transition-colors hover:text-[#b21100] dark:hover:text-[#ff2e1a]'
|
|
6
|
+
aria-label='Previous page'
|
|
7
|
+
>
|
|
8
|
+
<svg viewBox='0 0 20 20' fill='currentColor' class='h-4 w-4' aria-hidden='true'><path fill-rule='evenodd' d='M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z' clip-rule='evenodd'/></svg>
|
|
9
|
+
{{coalesce prev.label "Prev"}}
|
|
10
|
+
</a>
|
|
11
|
+
{{else}}
|
|
12
|
+
<span class='inline-flex items-center gap-1 text-sm font-medium text-slate-300 dark:text-slate-700' aria-disabled='true'>
|
|
13
|
+
<svg viewBox='0 0 20 20' fill='currentColor' class='h-4 w-4' aria-hidden='true'><path fill-rule='evenodd' d='M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z' clip-rule='evenodd'/></svg>
|
|
14
|
+
{{coalesce prev.label "Prev"}}
|
|
15
|
+
</span>
|
|
16
|
+
{{/if}}
|
|
17
|
+
|
|
18
|
+
<ol class='flex items-center gap-0.5'>
|
|
19
|
+
{{#each pages}}
|
|
20
|
+
<li>
|
|
21
|
+
{{#if ellipsis}}
|
|
22
|
+
<span class='inline-flex h-9 w-9 items-center justify-center text-sm text-slate-400 dark:text-slate-500'>…</span>
|
|
23
|
+
{{else}}
|
|
24
|
+
{{#if current}}
|
|
25
|
+
<span aria-current='page' class='inline-flex h-9 w-9 items-center justify-center text-sm font-bold text-[#b21100] dark:text-[#ff2e1a] border-b-2 border-[#b21100] dark:border-[#ff2e1a]'>
|
|
26
|
+
{{label}}
|
|
27
|
+
</span>
|
|
28
|
+
{{else}}
|
|
29
|
+
<a
|
|
30
|
+
href='{{url}}'
|
|
31
|
+
class='inline-flex h-9 w-9 items-center justify-center text-sm font-medium text-slate-600 dark:text-slate-300 transition-colors hover:text-[#b21100] dark:hover:text-[#ff2e1a]'
|
|
32
|
+
>
|
|
33
|
+
{{label}}
|
|
34
|
+
</a>
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{/if}}
|
|
37
|
+
</li>
|
|
38
|
+
{{/each}}
|
|
39
|
+
</ol>
|
|
40
|
+
|
|
41
|
+
{{#if next.url}}
|
|
42
|
+
<a
|
|
43
|
+
href='{{next.url}}'
|
|
44
|
+
class='inline-flex items-center gap-1 text-sm font-medium text-slate-500 dark:text-slate-400 transition-colors hover:text-[#b21100] dark:hover:text-[#ff2e1a]'
|
|
45
|
+
aria-label='Next page'
|
|
46
|
+
>
|
|
47
|
+
{{coalesce next.label "Next"}}
|
|
48
|
+
<svg viewBox='0 0 20 20' fill='currentColor' class='h-4 w-4' aria-hidden='true'><path fill-rule='evenodd' d='M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 1 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z' clip-rule='evenodd'/></svg>
|
|
49
|
+
</a>
|
|
50
|
+
{{else}}
|
|
51
|
+
<span class='inline-flex items-center gap-1 text-sm font-medium text-slate-300 dark:text-slate-700' aria-disabled='true'>
|
|
52
|
+
{{coalesce next.label "Next"}}
|
|
53
|
+
<svg viewBox='0 0 20 20' fill='currentColor' class='h-4 w-4' aria-hidden='true'><path fill-rule='evenodd' d='M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 1 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z' clip-rule='evenodd'/></svg>
|
|
54
|
+
</span>
|
|
55
|
+
{{/if}}
|
|
56
|
+
</nav>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class='{{#if (eq orientation "both")}}overflow-auto{{else}}{{#if (eq orientation "horizontal")}}overflow-x-auto overflow-y-hidden{{else}}overflow-y-auto overflow-x-hidden{{/if}}{{/if}} [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-slate-300 [&::-webkit-scrollbar-thumb:hover]:bg-slate-400 dark:[&::-webkit-scrollbar-thumb]:bg-slate-600 dark:[&::-webkit-scrollbar-thumb:hover]:bg-slate-500 {{#if className}}{{className}}{{/if}}'
|
|
3
|
+
{{#if maxHeight}}style='max-height: {{maxHeight}};'{{/if}}
|
|
4
|
+
>
|
|
5
|
+
{{#if content}}
|
|
6
|
+
{{{content}}}
|
|
7
|
+
{{else}}
|
|
8
|
+
{{#if @partial-block}}
|
|
9
|
+
{{> @partial-block}}
|
|
10
|
+
{{/if}}
|
|
11
|
+
{{/if}}
|
|
12
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<span class='inline-flex items-baseline gap-3 {{#if className}}{{className}}{{/if}}'>
|
|
2
|
+
<span class='inline-flex items-center gap-1.5 border-l-2 pl-2 pr-3 py-0.5 text-xs font-semibold uppercase tracking-wider leading-5
|
|
3
|
+
{{#if (eq variant "live")}}border-emerald-500 bg-emerald-50 text-emerald-700 dark:bg-emerald-950/30 dark:text-emerald-300
|
|
4
|
+
{{else}}{{#if (eq variant "offline")}}border-slate-400 bg-slate-100 text-slate-600 dark:bg-slate-800/60 dark:text-slate-400
|
|
5
|
+
{{else}}{{#if (eq variant "warning")}}border-amber-500 bg-amber-50 text-amber-700 dark:bg-amber-950/30 dark:text-amber-400
|
|
6
|
+
{{else}}{{#if (eq variant "info")}}border-sky-500 bg-sky-50 text-sky-700 dark:bg-sky-950/30 dark:text-sky-400
|
|
7
|
+
{{else}}border-slate-400 bg-slate-100 text-slate-600 dark:bg-slate-800/60 dark:text-slate-400
|
|
8
|
+
{{/if}}{{/if}}{{/if}}{{/if}}'>
|
|
9
|
+
<span class='h-1.5 w-1.5 rounded-full flex-shrink-0
|
|
10
|
+
{{#if (eq variant "live")}}bg-emerald-500 animate-pulse
|
|
11
|
+
{{else}}{{#if (eq variant "offline")}}bg-slate-400
|
|
12
|
+
{{else}}{{#if (eq variant "warning")}}bg-amber-500
|
|
13
|
+
{{else}}{{#if (eq variant "info")}}bg-sky-500
|
|
14
|
+
{{else}}bg-slate-500
|
|
15
|
+
{{/if}}{{/if}}{{/if}}{{/if}}'></span>
|
|
16
|
+
<span>{{label}}</span>
|
|
17
|
+
</span>
|
|
18
|
+
{{#if description}}
|
|
19
|
+
<span class='text-xs leading-5 text-slate-500 dark:text-slate-400'>{{description}}</span>
|
|
20
|
+
{{/if}}
|
|
21
|
+
</span>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<footer
|
|
2
|
+
class='sticky top-[100vh] bg-slate-50 dark:bg-slate-900 border-t border-slate-200 dark:border-slate-800 mt-8 transition-colors'
|
|
3
|
+
style='view-transition-name: site-footer;'
|
|
4
|
+
>
|
|
5
|
+
<div class='container mx-auto px-4 py-6'>
|
|
6
|
+
<div class='flex flex-col md:grid md:grid-cols-3 items-center gap-4'>
|
|
7
|
+
<div class='flex items-center justify-center md:justify-start gap-3'>
|
|
8
|
+
<a
|
|
9
|
+
href='https://bsky.app/profile/fifthbell.com'
|
|
10
|
+
target='_blank'
|
|
11
|
+
rel='noopener noreferrer'
|
|
12
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#0085ff] dark:hover:text-[#0085ff] transition-colors'
|
|
13
|
+
aria-label='Follow us on Bluesky'
|
|
14
|
+
>
|
|
15
|
+
<svg class='w-5 h-5' viewBox='0 0 600 530' fill='currentColor'>
|
|
16
|
+
<path
|
|
17
|
+
d='M135.72 44.03c66.496 49.921 138.02 151.14 164.28 205.46 26.262-54.316 97.782-155.54 164.28-205.46 47.98-36.021 125.72-63.892 125.72 24.795 0 17.712-10.155 148.79-16.111 170.07-20.703 73.984-96.144 92.854-163.25 81.433 117.3 19.964 147.14 86.092 82.697 152.22-122.39 125.59-175.91-31.511-189.63-71.766-2.514-7.3797-3.6904-10.832-3.7077-7.8964-.0174-2.9357-1.1937.51669-3.7077 7.8964-13.714 40.255-67.233 197.36-189.63 71.766-64.444-66.128-34.605-132.26 82.697-152.22-67.108 11.421-142.55-7.4491-163.25-81.433-5.9562-21.282-16.111-152.36-16.111-170.07 0-88.687 77.742-60.816 125.72-24.795z'
|
|
18
|
+
></path>
|
|
19
|
+
</svg>
|
|
20
|
+
</a>
|
|
21
|
+
<a
|
|
22
|
+
href='https://x.com/thisisfifthbell'
|
|
23
|
+
target='_blank'
|
|
24
|
+
rel='noopener noreferrer'
|
|
25
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#000000] dark:hover:text-[#ffffff] transition-colors'
|
|
26
|
+
aria-label='Follow us on X (Twitter)'
|
|
27
|
+
>
|
|
28
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor'>
|
|
29
|
+
<path
|
|
30
|
+
d='M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'
|
|
31
|
+
></path>
|
|
32
|
+
</svg>
|
|
33
|
+
</a>
|
|
34
|
+
<a
|
|
35
|
+
href='https://instagram.com/thisisfifthbell'
|
|
36
|
+
target='_blank'
|
|
37
|
+
rel='noopener noreferrer'
|
|
38
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#E4405F] dark:hover:text-[#E4405F] transition-colors'
|
|
39
|
+
aria-label='Follow us on Instagram'
|
|
40
|
+
>
|
|
41
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor'>
|
|
42
|
+
<path
|
|
43
|
+
d='M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z'
|
|
44
|
+
></path>
|
|
45
|
+
</svg>
|
|
46
|
+
</a>
|
|
47
|
+
<a
|
|
48
|
+
href='https://www.youtube.com/@thisisfifthbell'
|
|
49
|
+
target='_blank'
|
|
50
|
+
rel='noopener noreferrer'
|
|
51
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#FF0000] dark:hover:text-[#FF0000] transition-colors'
|
|
52
|
+
aria-label='Subscribe on YouTube'
|
|
53
|
+
>
|
|
54
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor'>
|
|
55
|
+
<path
|
|
56
|
+
d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'
|
|
57
|
+
></path>
|
|
58
|
+
</svg>
|
|
59
|
+
</a>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class='flex items-center justify-center md:space-x-3'>
|
|
63
|
+
<div class='bg-slate-600 dark:bg-slate-700 text-slate-50 dark:text-slate-300 p-2 transition-colors'>
|
|
64
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>
|
|
65
|
+
<path d='M10.268 21a2 2 0 0 0 3.464 0'></path>
|
|
66
|
+
<path d='M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326'></path>
|
|
67
|
+
<path d='M4 2C2.8 3.7 2 5.7 2 8'></path>
|
|
68
|
+
<path d='M22 8a10 10 0 0 0-2-6'></path>
|
|
69
|
+
</svg>
|
|
70
|
+
</div>
|
|
71
|
+
<span class='hidden md:inline text-slate-600 dark:text-slate-400 transition-colors'>fifth<span class='font-semibold'>bell</span></span>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class='flex items-center justify-center md:justify-end text-sm text-slate-600 dark:text-slate-400 transition-colors'>
|
|
75
|
+
<span>© 2026 fifth<b>bell</b>. All rights reserved.</span>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</footer>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<footer class='sticky top-[100vh] bg-slate-50 dark:bg-slate-900 border-t border-slate-200 dark:border-slate-800 mt-8 transition-colors' style='view-transition-name: site-footer;'>
|
|
2
|
+
<div class='container mx-auto px-4 py-6 text-center text-sm text-slate-600 dark:text-slate-400'>
|
|
3
|
+
<span>© 2026 fifth<b>bell</b>. All rights reserved.</span>
|
|
4
|
+
</div>
|
|
5
|
+
</footer>
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
<header
|
|
2
|
+
class='border-b border-slate-200 dark:border-slate-700 relative z-[60] bg-white dark:bg-slate-900 transition-colors'
|
|
3
|
+
style='view-transition-name: site-header;'
|
|
4
|
+
>
|
|
5
|
+
<div class='container mx-auto px-4'>
|
|
6
|
+
<nav class='flex items-center justify-between h-16'>
|
|
7
|
+
<div class='flex items-center space-x-8'>
|
|
8
|
+
<div class='relative'>
|
|
9
|
+
<button
|
|
10
|
+
id='menu-button'
|
|
11
|
+
class='flex items-center space-x-2 p-2 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-black dark:text-white'
|
|
12
|
+
aria-label='Menu'
|
|
13
|
+
aria-expanded='false'
|
|
14
|
+
type='button'
|
|
15
|
+
>
|
|
16
|
+
<svg class='w-4 h-4' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'>
|
|
17
|
+
<line x1='3' y1='6' x2='21' y2='6'></line>
|
|
18
|
+
<line x1='3' y1='12' x2='21' y2='12'></line>
|
|
19
|
+
<line x1='3' y1='18' x2='21' y2='18'></line>
|
|
20
|
+
</svg>
|
|
21
|
+
</button>
|
|
22
|
+
|
|
23
|
+
<div
|
|
24
|
+
id='dropdown-menu'
|
|
25
|
+
class='fixed top-16 left-0 right-0 bottom-0 bg-white/98 dark:bg-slate-900/98 backdrop-blur-md shadow-lg z-50 pointer-events-none border-t border-slate-200 dark:border-slate-700 overflow-hidden transition-colors'
|
|
26
|
+
style='opacity: 0; transform: translateX(-100%); transition: transform 600ms ease-out, opacity 300ms ease-out 300ms;'
|
|
27
|
+
>
|
|
28
|
+
<div class='container mx-auto px-4 py-4 md:py-8 h-full overflow-y-auto overscroll-contain'>
|
|
29
|
+
<div class='grid grid-cols-1 lg:grid-cols-5 gap-6 lg:gap-8'>
|
|
30
|
+
<div class='lg:col-span-1'>
|
|
31
|
+
<h3
|
|
32
|
+
class='text-xs font-bold text-slate-400 dark:text-slate-600 uppercase tracking-wider mb-4 border-b border-slate-200 dark:border-slate-800 pb-2'
|
|
33
|
+
>SECTIONS</h3>
|
|
34
|
+
<div id='sections-links' class='space-y-3'>
|
|
35
|
+
<a
|
|
36
|
+
href='{{logoLink}}'
|
|
37
|
+
class='block text-lg font-bold text-black dark:text-white hover:text-[#b21100] dark:hover:text-[#ff2e1a] transition-colors'
|
|
38
|
+
>TOP STORIES</a>
|
|
39
|
+
<div id='category-links-container' class='space-y-3'>
|
|
40
|
+
<p class='text-sm text-slate-400 dark:text-slate-500'>Loading sections...</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class='mt-8 pt-6 border-t border-slate-200 dark:border-slate-800'>
|
|
45
|
+
<h3 class='text-xs font-bold text-slate-400 dark:text-slate-600 uppercase tracking-wider mb-4'>FOLLOW US</h3>
|
|
46
|
+
<div class='flex items-center gap-3'>
|
|
47
|
+
<a
|
|
48
|
+
href='https://bsky.app/profile/fifthbell.com'
|
|
49
|
+
target='_blank'
|
|
50
|
+
rel='noopener noreferrer'
|
|
51
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#0085ff] dark:hover:text-[#0085ff] transition-colors'
|
|
52
|
+
aria-label='Follow us on Bluesky'
|
|
53
|
+
>
|
|
54
|
+
<svg class='w-5 h-5' viewBox='0 0 600 530' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
|
55
|
+
<path
|
|
56
|
+
d='M135.72 44.03c66.496 49.921 138.02 151.14 164.28 205.46 26.262-54.316 97.782-155.54 164.28-205.46 47.98-36.021 125.72-63.892 125.72 24.795 0 17.712-10.155 148.79-16.111 170.07-20.703 73.984-96.144 92.854-163.25 81.433 117.3 19.964 147.14 86.092 82.697 152.22-122.39 125.59-175.91-31.511-189.63-71.766-2.514-7.3797-3.6904-10.832-3.7077-7.8964-.0174-2.9357-1.1937.51669-3.7077 7.8964-13.714 40.255-67.233 197.36-189.63 71.766-64.444-66.128-34.605-132.26 82.697-152.22-67.108 11.421-142.55-7.4491-163.25-81.433-5.9562-21.282-16.111-152.36-16.111-170.07 0-88.687 77.742-60.816 125.72-24.795z'
|
|
57
|
+
></path>
|
|
58
|
+
</svg>
|
|
59
|
+
</a>
|
|
60
|
+
<a
|
|
61
|
+
href='https://x.com/thisisfifthbell'
|
|
62
|
+
target='_blank'
|
|
63
|
+
rel='noopener noreferrer'
|
|
64
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#000000] dark:hover:text-[#ffffff] transition-colors'
|
|
65
|
+
aria-label='Follow us on X (Twitter)'
|
|
66
|
+
>
|
|
67
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
|
68
|
+
<path
|
|
69
|
+
d='M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'
|
|
70
|
+
></path>
|
|
71
|
+
</svg>
|
|
72
|
+
</a>
|
|
73
|
+
<a
|
|
74
|
+
href='https://instagram.com/thisisfifthbell'
|
|
75
|
+
target='_blank'
|
|
76
|
+
rel='noopener noreferrer'
|
|
77
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#E4405F] dark:hover:text-[#E4405F] transition-colors'
|
|
78
|
+
aria-label='Follow us on Instagram'
|
|
79
|
+
>
|
|
80
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
|
81
|
+
<path
|
|
82
|
+
d='M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z'
|
|
83
|
+
></path>
|
|
84
|
+
</svg>
|
|
85
|
+
</a>
|
|
86
|
+
<a
|
|
87
|
+
href='https://www.youtube.com/@thisisfifthbell'
|
|
88
|
+
target='_blank'
|
|
89
|
+
rel='noopener noreferrer'
|
|
90
|
+
class='text-slate-600 dark:text-slate-400 hover:text-[#FF0000] dark:hover:text-[#FF0000] transition-colors'
|
|
91
|
+
aria-label='Subscribe on YouTube'
|
|
92
|
+
>
|
|
93
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
|
94
|
+
<path
|
|
95
|
+
d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'
|
|
96
|
+
></path>
|
|
97
|
+
</svg>
|
|
98
|
+
</a>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class='mt-8 pt-6 border-t border-slate-200 dark:border-slate-800'>
|
|
103
|
+
<h3 class='text-xs font-bold text-slate-400 dark:text-slate-600 uppercase tracking-wider mb-4'>THEME</h3>
|
|
104
|
+
<div class='flex items-center gap-2'>
|
|
105
|
+
<button
|
|
106
|
+
id='theme-light'
|
|
107
|
+
class='theme-btn flex items-center justify-center p-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300'
|
|
108
|
+
aria-label='Light mode'
|
|
109
|
+
data-theme='light'
|
|
110
|
+
type='button'
|
|
111
|
+
>
|
|
112
|
+
<svg
|
|
113
|
+
class='w-5 h-5'
|
|
114
|
+
viewBox='0 0 24 24'
|
|
115
|
+
fill='none'
|
|
116
|
+
stroke='currentColor'
|
|
117
|
+
stroke-width='2'
|
|
118
|
+
stroke-linecap='round'
|
|
119
|
+
stroke-linejoin='round'
|
|
120
|
+
>
|
|
121
|
+
<circle cx='12' cy='12' r='4'></circle>
|
|
122
|
+
<path d='M12 2v2'></path>
|
|
123
|
+
<path d='M12 20v2'></path>
|
|
124
|
+
<path d='m4.93 4.93 1.41 1.41'></path>
|
|
125
|
+
<path d='m17.66 17.66 1.41 1.41'></path>
|
|
126
|
+
<path d='M2 12h2'></path>
|
|
127
|
+
<path d='M20 12h2'></path>
|
|
128
|
+
<path d='m6.34 17.66-1.41 1.41'></path>
|
|
129
|
+
<path d='m19.07 4.93-1.41 1.41'></path>
|
|
130
|
+
</svg>
|
|
131
|
+
</button>
|
|
132
|
+
<button
|
|
133
|
+
id='theme-dark'
|
|
134
|
+
class='theme-btn flex items-center justify-center p-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300'
|
|
135
|
+
aria-label='Dark mode'
|
|
136
|
+
data-theme='dark'
|
|
137
|
+
type='button'
|
|
138
|
+
>
|
|
139
|
+
<svg
|
|
140
|
+
class='w-5 h-5'
|
|
141
|
+
viewBox='0 0 24 24'
|
|
142
|
+
fill='none'
|
|
143
|
+
stroke='currentColor'
|
|
144
|
+
stroke-width='2'
|
|
145
|
+
stroke-linecap='round'
|
|
146
|
+
stroke-linejoin='round'
|
|
147
|
+
>
|
|
148
|
+
<path d='M12 3a6 6 0 1 0 9 9 9 9 0 1 1-9-9z'></path>
|
|
149
|
+
</svg>
|
|
150
|
+
</button>
|
|
151
|
+
<button
|
|
152
|
+
id='theme-system'
|
|
153
|
+
class='theme-btn flex items-center justify-center p-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300'
|
|
154
|
+
aria-label='System theme'
|
|
155
|
+
data-theme='system'
|
|
156
|
+
type='button'
|
|
157
|
+
>
|
|
158
|
+
<svg
|
|
159
|
+
class='w-5 h-5'
|
|
160
|
+
viewBox='0 0 24 24'
|
|
161
|
+
fill='none'
|
|
162
|
+
stroke='currentColor'
|
|
163
|
+
stroke-width='2'
|
|
164
|
+
stroke-linecap='round'
|
|
165
|
+
stroke-linejoin='round'
|
|
166
|
+
>
|
|
167
|
+
<rect x='2' y='3' width='20' height='14' rx='2' ry='2'></rect>
|
|
168
|
+
<line x1='8' y1='21' x2='16' y2='21'></line>
|
|
169
|
+
<line x1='12' y1='17' x2='12' y2='21'></line>
|
|
170
|
+
</svg>
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<div class='mt-8 pt-6 border-t border-slate-200 dark:border-slate-800'>
|
|
176
|
+
<h3 class='text-xs font-bold text-slate-400 dark:text-slate-600 uppercase tracking-wider mb-4'>LANGUAGE</h3>
|
|
177
|
+
<div class='flex items-center gap-2'>
|
|
178
|
+
<button
|
|
179
|
+
class='lang-btn flex items-center justify-center px-3 py-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300 font-medium text-sm'
|
|
180
|
+
aria-label='English'
|
|
181
|
+
data-lang='en'
|
|
182
|
+
type='button'
|
|
183
|
+
>
|
|
184
|
+
EN
|
|
185
|
+
</button>
|
|
186
|
+
<button
|
|
187
|
+
class='lang-btn flex items-center justify-center px-3 py-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300 font-medium text-sm'
|
|
188
|
+
aria-label='Español'
|
|
189
|
+
data-lang='es'
|
|
190
|
+
type='button'
|
|
191
|
+
>
|
|
192
|
+
ES
|
|
193
|
+
</button>
|
|
194
|
+
<button
|
|
195
|
+
class='lang-btn flex items-center justify-center px-3 py-2 rounded hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-300 font-medium text-sm'
|
|
196
|
+
aria-label='Italiano'
|
|
197
|
+
data-lang='it'
|
|
198
|
+
type='button'
|
|
199
|
+
>
|
|
200
|
+
IT
|
|
201
|
+
</button>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div id='mini-featured' class='lg:col-span-4 hidden lg:block'>
|
|
207
|
+
<div class='flex flex-col items-center justify-center py-20'>
|
|
208
|
+
<div class='animate-spin rounded-full h-12 w-12 border-b-2 border-slate-300 dark:border-slate-600'></div>
|
|
209
|
+
<p class='text-slate-400 dark:text-slate-500 mt-4'>Loading stories...</p>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class='absolute left-1/2 transform -translate-x-1/2 bg-[#b21100] text-white p-3'>
|
|
219
|
+
<a href='{{logoLink}}' aria-label='fifthbell - Home'>
|
|
220
|
+
<svg class='w-7 h-7' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>
|
|
221
|
+
<path d='M10.268 21a2 2 0 0 0 3.464 0'></path>
|
|
222
|
+
<path d='M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326'></path>
|
|
223
|
+
<path d='M4 2C2.8 3.7 2 5.7 2 8'></path>
|
|
224
|
+
<path d='M22 8a10 10 0 0 0-2-6'></path>
|
|
225
|
+
</svg>
|
|
226
|
+
</a>
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
<div class='flex items-center space-x-4'>
|
|
230
|
+
<a
|
|
231
|
+
href='{{#if (eq language "en")}}/search{{else}}/{{language}}/search{{/if}}'
|
|
232
|
+
class='flex items-center justify-center p-2 border border-slate-300 dark:border-slate-700 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-slate-700 dark:text-slate-200'
|
|
233
|
+
aria-label='Search'
|
|
234
|
+
>
|
|
235
|
+
<svg class='w-4 h-4' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'>
|
|
236
|
+
<circle cx='11' cy='11' r='8'></circle>
|
|
237
|
+
<line x1='21' y1='21' x2='16.65' y2='16.65'></line>
|
|
238
|
+
</svg>
|
|
239
|
+
</a>
|
|
240
|
+
<form
|
|
241
|
+
class='hidden md:flex items-center'
|
|
242
|
+
role='search'
|
|
243
|
+
action='{{#if (eq language "en")}}/search{{else}}/{{language}}/search{{/if}}'
|
|
244
|
+
method='get'
|
|
245
|
+
>
|
|
246
|
+
<label for='header-search-input' class='sr-only'>Search</label>
|
|
247
|
+
<input
|
|
248
|
+
id='header-search-input'
|
|
249
|
+
name='q'
|
|
250
|
+
type='search'
|
|
251
|
+
autocomplete='off'
|
|
252
|
+
spellcheck='false'
|
|
253
|
+
placeholder='Search'
|
|
254
|
+
class='w-44 lg:w-56 px-3 py-2 border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-900 text-sm text-slate-900 dark:text-slate-100 placeholder:text-slate-400 dark:placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-[#b21100]/40'
|
|
255
|
+
/>
|
|
256
|
+
</form>
|
|
257
|
+
<a
|
|
258
|
+
href='https://www.youtube.com/watch?v=3Zq7RR-9Asc'
|
|
259
|
+
target='_blank'
|
|
260
|
+
rel='noopener noreferrer'
|
|
261
|
+
class='hidden md:flex items-center space-x-2 bg-[#b21100] hover:bg-[#8f0d00] text-white px-4 py-2 rounded font-bold transition-colors uppercase tracking-wide text-sm'
|
|
262
|
+
>
|
|
263
|
+
<svg class='w-5 h-5' viewBox='0 0 24 24' fill='currentColor'>
|
|
264
|
+
<path d='M8 5v14l11-7z'></path>
|
|
265
|
+
</svg>
|
|
266
|
+
<span>Watch Live</span>
|
|
267
|
+
</a>
|
|
268
|
+
</div>
|
|
269
|
+
</nav>
|
|
270
|
+
</div>
|
|
271
|
+
</header>
|
|
272
|
+
|
|
273
|
+
<script>
|
|
274
|
+
(function () { const menuButton = document.getElementById('menu-button'); const dropdownMenu = document.getElementById('dropdown-menu'); const sectionsLinks =
|
|
275
|
+
document.getElementById('sections-links'); const categoryLinksContainer = document.getElementById('category-links-container'); const miniFeatured =
|
|
276
|
+
document.getElementById('mini-featured'); if (!menuButton || !dropdownMenu) return; let isOpen = false; let contentLoaded = false; let currentCategoryKey =
|
|
277
|
+
'__home__'; let activeCategorySlug = ''; let requestVersion = 0; const cache = new Map(); function getCurrentLang() { const p = window.location.pathname ||
|
|
278
|
+
'/'; if (p.startsWith('/es')) return 'es'; if (p.startsWith('/it')) return 'it'; return 'en'; } function buildLocalePath(slug) { const lang =
|
|
279
|
+
getCurrentLang(); if (!slug) return lang === 'en' ? '/' : `/${lang}`; const normalized = String(slug).startsWith('/') ? String(slug) : `/${slug}`; if
|
|
280
|
+
(normalized.startsWith('/es/') || normalized.startsWith('/it/')) return normalized; if (lang === 'en') return normalized; return `/${lang}${normalized}`; }
|
|
281
|
+
function normalizePathInput(value) { if (typeof value !== 'string') return ''; const trimmed = value.trim(); if (!trimmed) return ''; try { if
|
|
282
|
+
(/^https?:\/\//i.test(trimmed)) { const parsed = new URL(trimmed); const normalizedAbsolute = `/${(parsed.pathname || '').replace(/^\/+/,
|
|
283
|
+
'')}`.replace(/\/{2,}/g, '/'); if (normalizedAbsolute !== '/' && normalizedAbsolute.endsWith('/')) { return normalizedAbsolute.slice(0, -1); } return
|
|
284
|
+
normalizedAbsolute || '/'; } } catch { /* Fall back to raw string normalization below */ } const withoutQueryOrHash = trimmed.split('#')[0].split('?')[0]; const
|
|
285
|
+
normalized = `/${withoutQueryOrHash.replace(/^\/+/, '')}`.replace(/\/{2,}/g, '/'); if (normalized !== '/' && normalized.endsWith('/')) { return
|
|
286
|
+
normalized.slice(0, -1); } return normalized; } function cleanPathSegment(value) { if (typeof value !== 'string') return ''; return
|
|
287
|
+
value.trim().replace(/^\/+|\/+$/g, ''); } function getArticleLeafPath(article) { const explicitUrl = normalizePathInput(article?.url); if (explicitUrl &&
|
|
288
|
+
explicitUrl !== '/') { return buildLocalePath(explicitUrl); } const canonicalUrl = normalizePathInput(article?.canonicalUrl); if (canonicalUrl && canonicalUrl
|
|
289
|
+
!== '/') { return buildLocalePath(canonicalUrl); } const slugRaw = typeof article?.slug === 'string' ? article.slug : ''; const normalizedSlugPath =
|
|
290
|
+
normalizePathInput(slugRaw); const slugSegments = normalizedSlugPath.split('/').filter(Boolean); if (slugSegments.length > 1) { return
|
|
291
|
+
buildLocalePath(normalizedSlugPath); } const slugSegment = cleanPathSegment(slugRaw); const primaryCategorySlug =
|
|
292
|
+
cleanPathSegment(article?.categories?.[0]?.slug) || cleanPathSegment(article?.category?.slug); if (slugSegment && primaryCategorySlug) { return
|
|
293
|
+
buildLocalePath(`/${primaryCategorySlug}/${slugSegment}`); } if (slugSegment) { return buildLocalePath(`/${slugSegment}`); } return buildLocalePath('/'); }
|
|
294
|
+
function getCdnUrl(categorySlug) { const lang = getCurrentLang(); const file = categorySlug ? `${categorySlug}-current-${lang}.json` :
|
|
295
|
+
`homepage-current-${lang}.json`; return `https://cdn.fifthbell.com/content/${file}?v=${Date.now()}-${Math.random().toString(36).slice(2)}`; } function
|
|
296
|
+
getArticlesFromPayload(payload) { if (!payload || typeof payload !== 'object') return []; return payload.docs || payload.articles || []; } function
|
|
297
|
+
showCategoryLinksLoading() { if (!categoryLinksContainer) return; categoryLinksContainer.innerHTML = `<p class='text-sm text-slate-400
|
|
298
|
+
dark:text-slate-500'>Loading sections...</p>`; } function showCategoryLinksError() { if (!categoryLinksContainer) return; categoryLinksContainer.innerHTML =
|
|
299
|
+
`<p class='text-sm text-red-500'>Failed to load sections</p>`; } function setActiveCategoryLink(categorySlug) { if (!sectionsLinks) return; activeCategorySlug
|
|
300
|
+
= categorySlug || ''; const links = sectionsLinks.querySelectorAll('.category-link'); links.forEach((link) => { const isActive =
|
|
301
|
+
(link.getAttribute('data-category-slug') || '') === activeCategorySlug; if (isActive) { link.classList.add('text-[#b21100]', 'dark:text-[#ff2e1a]');
|
|
302
|
+
link.classList.remove('text-black', 'dark:text-white'); link.setAttribute('aria-current', 'page'); } else { link.classList.remove('text-[#b21100]',
|
|
303
|
+
'dark:text-[#ff2e1a]'); link.classList.add('text-black', 'dark:text-white'); link.setAttribute('aria-current', 'false'); } }); } function
|
|
304
|
+
renderCategories(categories) { if (!categoryLinksContainer) return; if (!Array.isArray(categories) || categories.length === 0) {
|
|
305
|
+
categoryLinksContainer.innerHTML = `<p class='text-sm text-slate-400 dark:text-slate-500'>No sections available</p>`; return; }
|
|
306
|
+
categoryLinksContainer.innerHTML = categories .map( (category) => `<a href="${buildLocalePath(category.slug)}" class="category-link block text-lg font-bold
|
|
307
|
+
text-black dark:text-white hover:text-[#b21100] dark:hover:text-[#ff2e1a] transition-colors" data-category-slug="${category.slug}"
|
|
308
|
+
aria-current="false">${String(category.name || '').toUpperCase()}</a>` ) .join(''); setActiveCategoryLink(activeCategorySlug); } function
|
|
309
|
+
showMiniFeaturedLoading() { if (!miniFeatured) return; miniFeatured.innerHTML = ` <div class='flex flex-col items-center justify-center py-20'> <div
|
|
310
|
+
class='animate-spin rounded-full h-12 w-12 border-b-2 border-slate-300 dark:border-slate-600'></div> <p class='text-slate-400 dark:text-slate-500
|
|
311
|
+
mt-4'>Loading stories...</p> </div> `; } function renderMiniFeatured(articles, categoryName) { if (!miniFeatured) return; if (!Array.isArray(articles) ||
|
|
312
|
+
articles.length === 0) { miniFeatured.innerHTML = `<h3 class='text-xs font-bold text-slate-400 uppercase tracking-wider mb-6 border-b border-slate-200
|
|
313
|
+
dark:border-slate-800 pb-2'>${(categoryName || 'Featured Stories').toUpperCase()}</h3>` + `<p class='text-slate-400 dark:text-slate-500'>No stories
|
|
314
|
+
available</p>`; return; } const top = (articles || []).slice(0, 2); const grid = (articles || []).slice(2, 11); const topHtml = top .map( (article) => ` <div>
|
|
315
|
+
<div class='relative mb-5'> <img src='${article?.featuredImage?.url || ''}' alt='${article?.featuredImage?.alt || article?.title || ''}' class='w-full h-50
|
|
316
|
+
object-cover rounded' /> </div> <div class='flex items-center text-slate-500 dark:text-slate-400 text-sm mb-3'> <span class='uppercase font-bold
|
|
317
|
+
tracking-wider'>${article?.categories?.[0]?.name || categoryName || 'GENERAL'}</span> <span class='mx-2'>•</span> <span>5 min</span> </div> <h2 class='text-xl
|
|
318
|
+
font-bold text-slate-900 dark:text-slate-100 leading-tight'> <a href='${getArticleLeafPath(article)}' class='hover:text-[#b21100] dark:hover:text-[#ff2e1a]
|
|
319
|
+
transition-colors'>${article?.title || ''}</a> </h2> </div> ` ) .join(''); const rows = []; for (let i = 0; i < grid.length; i += 3) { const row =
|
|
320
|
+
grid.slice(i, i + 3); if (!row.length) continue; rows.push(` <div class='grid grid-cols-3 gap-6 ${i > 0 ? 'pt-6 border-t border-slate-200 dark:border-slate-800' : ''}'> ${row .map( (article, idx) => ` <div class='${idx === 0 ? 'pr-4 border-r border-slate-200 dark:border-slate-800' : idx === 1 ?
|
|
321
|
+
'px-4 border-r border-slate-200 dark:border-slate-800' : 'pl-4'}'> <div class='flex items-center text-slate-500 dark:text-slate-400 text-sm mb-3'> <span
|
|
322
|
+
class='uppercase font-bold'>${article?.categories?.[0]?.name || categoryName || 'GENERAL'}</span> </div> <h3 class='font-medium text-base leading-tight
|
|
323
|
+
text-slate-900 dark:text-slate-100'> <a href='${getArticleLeafPath(article)}' class='hover:text-[#b21100] dark:hover:text-[#ff2e1a]
|
|
324
|
+
transition-colors'>${article?.title || ''}</a> </h3> </div> ` ) .join('')} </div> `); } miniFeatured.innerHTML = ` <h3 class='text-xs font-bold text-slate-400
|
|
325
|
+
dark:text-slate-600 uppercase tracking-wider mb-6 border-b border-slate-200 dark:border-slate-800 pb-2'> ${(categoryName || 'Featured Stories').toUpperCase()}
|
|
326
|
+
</h3> <div class='grid grid-cols-2 gap-8 mb-10'>${topHtml}</div> <div class='space-y-6'>${rows.join('')}</div> `; } function getCategoryName(payload,
|
|
327
|
+
categorySlug) { if (!categorySlug) return 'Featured Stories'; const fromPrimaryCategory = payload?.category?.name; if (fromPrimaryCategory) return
|
|
328
|
+
fromPrimaryCategory; const fromCategoriesArray = (payload?.categories || []).find((category) => category?.slug === categorySlug)?.name; if
|
|
329
|
+
(fromCategoriesArray) return fromCategoriesArray; return String(categorySlug).replace(/-/g, ' '); } async function fetchPayload(categorySlug) { const response
|
|
330
|
+
= await fetch(getCdnUrl(categorySlug), { headers: { 'Content-Type': 'application/json' } }); if (!response.ok) throw new Error(`Failed to fetch ${categorySlug
|
|
331
|
+
|| 'homepage'} data`); return response.json(); } async function loadCategoryContent(categorySlug) { const key = categorySlug || '__home__'; if (key ===
|
|
332
|
+
currentCategoryKey && cache.has(key)) return; currentCategoryKey = key; if (cache.has(key)) { const cached = cache.get(key);
|
|
333
|
+
renderMiniFeatured(cached.articles, cached.categoryName); return; } const requestId = ++requestVersion; showMiniFeaturedLoading(); try { const payload = await
|
|
334
|
+
fetchPayload(categorySlug); if (requestId !== requestVersion || key !== currentCategoryKey) return; const articles = getArticlesFromPayload(payload); const
|
|
335
|
+
categoryName = getCategoryName(payload, categorySlug); const data = { articles, categoryName }; cache.set(key, data); renderMiniFeatured(articles,
|
|
336
|
+
categoryName); } catch (error) { if (requestId !== requestVersion || key !== currentCategoryKey) return; if (miniFeatured) { miniFeatured.innerHTML = `<h3
|
|
337
|
+
class='text-xs font-bold text-slate-400 uppercase tracking-wider mb-6 border-b border-slate-200 dark:border-slate-800 pb-2'>ERROR</h3>` + `<p
|
|
338
|
+
class='text-red-500'>Failed to load stories</p>`; } } } function shouldPreviewOnClick(event) { if (!(miniFeatured instanceof HTMLElement)) return false; if
|
|
339
|
+
(!window.matchMedia('(min-width: 1024px)').matches) return false; if (event.button !== 0) return false; if (event.metaKey || event.ctrlKey || event.shiftKey
|
|
340
|
+
|| event.altKey) return false; return true; } function attachSectionHandlers() { if (!sectionsLinks) return; const topStories =
|
|
341
|
+
sectionsLinks.querySelector('a[href="{{logoLink}}"]'); if (topStories) { topStories.classList.add('category-link');
|
|
342
|
+
topStories.setAttribute('data-category-slug', ''); } const links = sectionsLinks.querySelectorAll('.category-link'); links.forEach((link) => { const
|
|
343
|
+
selectCategory = () => { const slug = link.getAttribute('data-category-slug') || ''; setActiveCategoryLink(slug); loadCategoryContent(slug); };
|
|
344
|
+
link.addEventListener('mouseenter', selectCategory); link.addEventListener('focus', selectCategory); link.addEventListener('click', (event) => { if
|
|
345
|
+
(!shouldPreviewOnClick(event)) return; event.preventDefault(); selectCategory(); }); }); } async function initializeMenuContent() { if (contentLoaded) return;
|
|
346
|
+
showCategoryLinksLoading(); showMiniFeaturedLoading(); try { const payload = await fetchPayload(''); const categories = (payload.categories || []).filter((c) => c && c.slug && (c.featured ?? true)); renderCategories(categories); attachSectionHandlers(); const homeArticles = getArticlesFromPayload(payload); const
|
|
347
|
+
homeData = { articles: homeArticles, categoryName: 'Featured Stories' }; cache.set('__home__', homeData); currentCategoryKey = '__home__';
|
|
348
|
+
setActiveCategoryLink(''); renderMiniFeatured(homeArticles, homeData.categoryName); contentLoaded = true; } catch { showCategoryLinksError(); if
|
|
349
|
+
(miniFeatured) { miniFeatured.innerHTML = `<h3 class='text-xs font-bold text-slate-400 uppercase tracking-wider mb-6 border-b border-slate-200
|
|
350
|
+
dark:border-slate-800 pb-2'>ERROR</h3>` + `<p class='text-red-500'>Failed to load stories</p>`; } } } function toggleMenu() { isOpen = !isOpen;
|
|
351
|
+
menuButton.setAttribute('aria-expanded', String(isOpen)); dropdownMenu.style.pointerEvents = isOpen ? 'auto' : 'none'; dropdownMenu.style.transform = isOpen ?
|
|
352
|
+
'translateX(0)' : 'translateX(-100%)'; dropdownMenu.style.opacity = isOpen ? '1' : '0'; document.body.style.overflow = isOpen ? 'hidden' : ''; if (isOpen) {
|
|
353
|
+
initializeMenuContent(); } } menuButton.addEventListener('click', (event) => { event.stopPropagation(); toggleMenu(); }); document.addEventListener('click',
|
|
354
|
+
(event) => { if (!isOpen) return; const target = event.target; if (target instanceof Node && dropdownMenu.contains(target)) return; if (target === menuButton)
|
|
355
|
+
return; toggleMenu(); }); })();
|
|
356
|
+
</script>
|
|
357
|
+
|
|
358
|
+
<script>
|
|
359
|
+
(function () { const THEME_KEY = 'fifthbell_theme'; const themeButtons = document.querySelectorAll('.theme-btn'); if (!themeButtons.length) return; function
|
|
360
|
+
getSystemTheme() { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } function applyTheme(theme) { const actualTheme =
|
|
361
|
+
theme === 'system' ? getSystemTheme() : theme; if (actualTheme === 'dark') { document.documentElement.classList.add('dark'); } else {
|
|
362
|
+
document.documentElement.classList.remove('dark'); } } function updateActiveButton(theme) { themeButtons.forEach((button) => { const buttonTheme =
|
|
363
|
+
button.getAttribute('data-theme'); if (buttonTheme === theme) { button.classList.add('!bg-[#b21100]', '!text-white');
|
|
364
|
+
button.classList.remove('text-slate-700', 'dark:text-slate-300'); button.setAttribute('aria-pressed', 'true'); } else {
|
|
365
|
+
button.classList.remove('!bg-[#b21100]', '!text-white'); button.classList.add('text-slate-700', 'dark:text-slate-300'); button.setAttribute('aria-pressed',
|
|
366
|
+
'false'); } }); } function setTheme(theme) { localStorage.setItem(THEME_KEY, theme); applyTheme(theme); updateActiveButton(theme); } function initTheme() {
|
|
367
|
+
const savedTheme = localStorage.getItem(THEME_KEY) || 'system'; applyTheme(savedTheme); updateActiveButton(savedTheme); } themeButtons.forEach((button) => {
|
|
368
|
+
button.addEventListener('click', () => { const theme = button.getAttribute('data-theme'); if (theme) setTheme(theme); }); });
|
|
369
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { if ((localStorage.getItem(THEME_KEY) || 'system') === 'system') {
|
|
370
|
+
applyTheme('system'); } }); initTheme(); })();
|
|
371
|
+
</script>
|
|
372
|
+
|
|
373
|
+
<script>
|
|
374
|
+
(function () { const langButtons = document.querySelectorAll('.lang-btn'); if (!langButtons.length) return; function getCurrentLanguageFromPath() { const path
|
|
375
|
+
= window.location.pathname || '/'; if (path.startsWith('/es')) return 'es'; if (path.startsWith('/it')) return 'it'; return 'en'; } function
|
|
376
|
+
updateActiveButton(lang) { langButtons.forEach((button) => { const buttonLang = button.getAttribute('data-lang'); if (buttonLang === lang) {
|
|
377
|
+
button.classList.add('!bg-[#b21100]', '!text-white'); button.classList.remove('text-slate-700', 'dark:text-slate-300'); button.setAttribute('aria-pressed',
|
|
378
|
+
'true'); } else { button.classList.remove('!bg-[#b21100]', '!text-white'); button.classList.add('text-slate-700', 'dark:text-slate-300');
|
|
379
|
+
button.setAttribute('aria-pressed', 'false'); } }); } function getTargetPathForLanguage(targetLang) { const currentPath = window.location.pathname || '/';
|
|
380
|
+
const currentLang = getCurrentLanguageFromPath(); if (currentLang === targetLang) return null; let basePath = currentPath; if (currentLang === 'es' &&
|
|
381
|
+
currentPath.startsWith('/es')) { basePath = currentPath.substring(3) || '/'; } else if (currentLang === 'it' && currentPath.startsWith('/it')) { basePath =
|
|
382
|
+
currentPath.substring(3) || '/'; } const segments = basePath.split('/').filter(Boolean); let categorySlugs = new Set(['politics', 'world', 'business',
|
|
383
|
+
'sports', 'technology', 'weather', 'crime', 'new-york']); try { const cached = localStorage.getItem('fifthbell_categories'); if (cached) { const parsed =
|
|
384
|
+
JSON.parse(cached); const categories = parsed?.data; if (Array.isArray(categories)) { categorySlugs = new Set(categories.map((item) => item.slug)); } } }
|
|
385
|
+
catch { /* ignore invalid local cache */ } const isHomepage = segments.length === 0; const isCategoryPage = segments.length === 1 &&
|
|
386
|
+
categorySlugs.has(segments[0]); const isSearchPage = segments.length >= 1 && segments[0] === 'search'; if (!isHomepage && !isCategoryPage &&
|
|
387
|
+
!isSearchPage) { return targetLang === 'en' ? '/' : `/${targetLang}`; } if (isSearchPage) { const currentSearch = window.location.search || ''; return
|
|
388
|
+
targetLang === 'en' ? `/search${currentSearch}` : `/${targetLang}/search${currentSearch}`; } if (targetLang === 'en') return
|
|
389
|
+
basePath === '/' ? '/' : basePath; return basePath === '/' ? `/${targetLang}` : `/${targetLang}${basePath}`; } function closeMenuIfOpen() { const menuButton =
|
|
390
|
+
document.getElementById('menu-button'); const dropdownMenu = document.getElementById('dropdown-menu'); if (!(menuButton instanceof HTMLElement) ||
|
|
391
|
+
!(dropdownMenu instanceof HTMLElement)) return; const isExpanded = menuButton.getAttribute('aria-expanded') === 'true'; if (!isExpanded) return;
|
|
392
|
+
menuButton.setAttribute('aria-expanded', 'false'); dropdownMenu.style.pointerEvents = 'none'; dropdownMenu.style.transform = 'translateX(-100%)';
|
|
393
|
+
dropdownMenu.style.opacity = '0'; document.body.style.overflow = ''; } langButtons.forEach((button) => { button.addEventListener('click', () => { const
|
|
394
|
+
targetLang = button.getAttribute('data-lang'); if (!targetLang) return; updateActiveButton(targetLang); closeMenuIfOpen(); const
|
|
395
|
+
targetPath = getTargetPathForLanguage(targetLang); if (targetPath) window.location.href = targetPath; }); });
|
|
396
|
+
updateActiveButton(getCurrentLanguageFromPath()); })();
|
|
397
|
+
</script>
|