@ewanc26/ui 0.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.
Files changed (154) hide show
  1. package/README.md +65 -0
  2. package/dist/components/layout/ThemeToggle.svelte +50 -0
  3. package/dist/components/layout/ThemeToggle.svelte.d.ts +4 -0
  4. package/dist/components/layout/ThemeToggle.svelte.d.ts.map +1 -0
  5. package/dist/components/layout/WolfToggle.svelte +19 -0
  6. package/dist/components/layout/WolfToggle.svelte.d.ts +4 -0
  7. package/dist/components/layout/WolfToggle.svelte.d.ts.map +1 -0
  8. package/dist/components/layout/index.d.ts +5 -0
  9. package/dist/components/layout/index.d.ts.map +1 -0
  10. package/dist/components/layout/index.js +4 -0
  11. package/dist/components/layout/main/DynamicLinks.svelte +63 -0
  12. package/dist/components/layout/main/DynamicLinks.svelte.d.ts +7 -0
  13. package/dist/components/layout/main/DynamicLinks.svelte.d.ts.map +1 -0
  14. package/dist/components/layout/main/ScrollToTop.svelte +36 -0
  15. package/dist/components/layout/main/ScrollToTop.svelte.d.ts +4 -0
  16. package/dist/components/layout/main/ScrollToTop.svelte.d.ts.map +1 -0
  17. package/dist/components/layout/main/card/BlueskyPostCard.svelte +261 -0
  18. package/dist/components/layout/main/card/BlueskyPostCard.svelte.d.ts +9 -0
  19. package/dist/components/layout/main/card/BlueskyPostCard.svelte.d.ts.map +1 -0
  20. package/dist/components/layout/main/card/KibunStatusCard.svelte +48 -0
  21. package/dist/components/layout/main/card/KibunStatusCard.svelte.d.ts +8 -0
  22. package/dist/components/layout/main/card/KibunStatusCard.svelte.d.ts.map +1 -0
  23. package/dist/components/layout/main/card/LinkCard.svelte +63 -0
  24. package/dist/components/layout/main/card/LinkCard.svelte.d.ts +17 -0
  25. package/dist/components/layout/main/card/LinkCard.svelte.d.ts.map +1 -0
  26. package/dist/components/layout/main/card/MusicStatusCard.svelte +101 -0
  27. package/dist/components/layout/main/card/MusicStatusCard.svelte.d.ts +8 -0
  28. package/dist/components/layout/main/card/MusicStatusCard.svelte.d.ts.map +1 -0
  29. package/dist/components/layout/main/card/PostCard.svelte +46 -0
  30. package/dist/components/layout/main/card/PostCard.svelte.d.ts +8 -0
  31. package/dist/components/layout/main/card/PostCard.svelte.d.ts.map +1 -0
  32. package/dist/components/layout/main/card/ProfileCard.svelte +70 -0
  33. package/dist/components/layout/main/card/ProfileCard.svelte.d.ts +8 -0
  34. package/dist/components/layout/main/card/ProfileCard.svelte.d.ts.map +1 -0
  35. package/dist/components/layout/main/card/TangledRepoCard.svelte +80 -0
  36. package/dist/components/layout/main/card/TangledRepoCard.svelte.d.ts +11 -0
  37. package/dist/components/layout/main/card/TangledRepoCard.svelte.d.ts.map +1 -0
  38. package/dist/components/layout/main/card/index.d.ts +8 -0
  39. package/dist/components/layout/main/card/index.d.ts.map +1 -0
  40. package/dist/components/layout/main/card/index.js +7 -0
  41. package/dist/components/layout/main/index.d.ts +4 -0
  42. package/dist/components/layout/main/index.d.ts.map +1 -0
  43. package/dist/components/layout/main/index.js +3 -0
  44. package/dist/components/seo/MetaTags.svelte +39 -0
  45. package/dist/components/seo/MetaTags.svelte.d.ts +9 -0
  46. package/dist/components/seo/MetaTags.svelte.d.ts.map +1 -0
  47. package/dist/components/seo/index.d.ts +2 -0
  48. package/dist/components/seo/index.d.ts.map +1 -0
  49. package/dist/components/seo/index.js +1 -0
  50. package/dist/components/ui/BlogPostCard.svelte +44 -0
  51. package/dist/components/ui/BlogPostCard.svelte.d.ts +9 -0
  52. package/dist/components/ui/BlogPostCard.svelte.d.ts.map +1 -0
  53. package/dist/components/ui/Card.svelte +144 -0
  54. package/dist/components/ui/Card.svelte.d.ts +27 -0
  55. package/dist/components/ui/Card.svelte.d.ts.map +1 -0
  56. package/dist/components/ui/DocumentCard.svelte +42 -0
  57. package/dist/components/ui/DocumentCard.svelte.d.ts +9 -0
  58. package/dist/components/ui/DocumentCard.svelte.d.ts.map +1 -0
  59. package/dist/components/ui/Dropdown.svelte +36 -0
  60. package/dist/components/ui/Dropdown.svelte.d.ts +15 -0
  61. package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -0
  62. package/dist/components/ui/InternalCard.svelte +41 -0
  63. package/dist/components/ui/InternalCard.svelte.d.ts +14 -0
  64. package/dist/components/ui/InternalCard.svelte.d.ts.map +1 -0
  65. package/dist/components/ui/Pagination.svelte +74 -0
  66. package/dist/components/ui/Pagination.svelte.d.ts +11 -0
  67. package/dist/components/ui/Pagination.svelte.d.ts.map +1 -0
  68. package/dist/components/ui/PostsGroupedView.svelte +40 -0
  69. package/dist/components/ui/PostsGroupedView.svelte.d.ts +10 -0
  70. package/dist/components/ui/PostsGroupedView.svelte.d.ts.map +1 -0
  71. package/dist/components/ui/SearchBar.svelte +26 -0
  72. package/dist/components/ui/SearchBar.svelte.d.ts +9 -0
  73. package/dist/components/ui/SearchBar.svelte.d.ts.map +1 -0
  74. package/dist/components/ui/Tabs.svelte +25 -0
  75. package/dist/components/ui/Tabs.svelte.d.ts +13 -0
  76. package/dist/components/ui/Tabs.svelte.d.ts.map +1 -0
  77. package/dist/components/ui/index.d.ts +11 -0
  78. package/dist/components/ui/index.d.ts.map +1 -0
  79. package/dist/components/ui/index.js +10 -0
  80. package/dist/config/themes.config.d.ts +23 -0
  81. package/dist/config/themes.config.d.ts.map +1 -0
  82. package/dist/config/themes.config.js +116 -0
  83. package/dist/helper/badges.d.ts +9 -0
  84. package/dist/helper/badges.d.ts.map +1 -0
  85. package/dist/helper/badges.js +28 -0
  86. package/dist/helper/posts.d.ts +14 -0
  87. package/dist/helper/posts.d.ts.map +1 -0
  88. package/dist/helper/posts.js +47 -0
  89. package/dist/index.d.ts +16 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +18 -0
  92. package/dist/stores/colorTheme.d.ts +12 -0
  93. package/dist/stores/colorTheme.d.ts.map +1 -0
  94. package/dist/stores/colorTheme.js +36 -0
  95. package/dist/stores/dropdownState.d.ts +2 -0
  96. package/dist/stores/dropdownState.d.ts.map +1 -0
  97. package/dist/stores/dropdownState.js +2 -0
  98. package/dist/stores/happyMac.d.ts +11 -0
  99. package/dist/stores/happyMac.d.ts.map +1 -0
  100. package/dist/stores/happyMac.js +19 -0
  101. package/dist/stores/index.d.ts +6 -0
  102. package/dist/stores/index.d.ts.map +1 -0
  103. package/dist/stores/index.js +4 -0
  104. package/dist/stores/wolfMode.d.ts +7 -0
  105. package/dist/stores/wolfMode.d.ts.map +1 -0
  106. package/dist/stores/wolfMode.js +130 -0
  107. package/dist/types/index.d.ts +19 -0
  108. package/dist/types/index.d.ts.map +1 -0
  109. package/dist/types/index.js +1 -0
  110. package/dist/utils/formatNumber.d.ts +3 -0
  111. package/dist/utils/formatNumber.d.ts.map +1 -0
  112. package/dist/utils/formatNumber.js +26 -0
  113. package/dist/utils/locale.d.ts +4 -0
  114. package/dist/utils/locale.d.ts.map +1 -0
  115. package/dist/utils/locale.js +32 -0
  116. package/package.json +45 -0
  117. package/src/lib/components/layout/ThemeToggle.svelte +50 -0
  118. package/src/lib/components/layout/WolfToggle.svelte +19 -0
  119. package/src/lib/components/layout/index.ts +4 -0
  120. package/src/lib/components/layout/main/DynamicLinks.svelte +63 -0
  121. package/src/lib/components/layout/main/ScrollToTop.svelte +36 -0
  122. package/src/lib/components/layout/main/card/BlueskyPostCard.svelte +261 -0
  123. package/src/lib/components/layout/main/card/KibunStatusCard.svelte +48 -0
  124. package/src/lib/components/layout/main/card/LinkCard.svelte +63 -0
  125. package/src/lib/components/layout/main/card/MusicStatusCard.svelte +101 -0
  126. package/src/lib/components/layout/main/card/PostCard.svelte +46 -0
  127. package/src/lib/components/layout/main/card/ProfileCard.svelte +70 -0
  128. package/src/lib/components/layout/main/card/TangledRepoCard.svelte +80 -0
  129. package/src/lib/components/layout/main/card/index.ts +7 -0
  130. package/src/lib/components/layout/main/index.ts +3 -0
  131. package/src/lib/components/seo/MetaTags.svelte +39 -0
  132. package/src/lib/components/seo/index.ts +1 -0
  133. package/src/lib/components/ui/BlogPostCard.svelte +44 -0
  134. package/src/lib/components/ui/Card.svelte +144 -0
  135. package/src/lib/components/ui/DocumentCard.svelte +42 -0
  136. package/src/lib/components/ui/Dropdown.svelte +36 -0
  137. package/src/lib/components/ui/InternalCard.svelte +41 -0
  138. package/src/lib/components/ui/Pagination.svelte +74 -0
  139. package/src/lib/components/ui/PostsGroupedView.svelte +40 -0
  140. package/src/lib/components/ui/SearchBar.svelte +26 -0
  141. package/src/lib/components/ui/Tabs.svelte +25 -0
  142. package/src/lib/components/ui/index.ts +10 -0
  143. package/src/lib/config/themes.config.ts +130 -0
  144. package/src/lib/helper/badges.ts +44 -0
  145. package/src/lib/helper/posts.ts +63 -0
  146. package/src/lib/index.ts +32 -0
  147. package/src/lib/stores/colorTheme.ts +44 -0
  148. package/src/lib/stores/dropdownState.ts +3 -0
  149. package/src/lib/stores/happyMac.ts +28 -0
  150. package/src/lib/stores/index.ts +5 -0
  151. package/src/lib/stores/wolfMode.ts +127 -0
  152. package/src/lib/types/index.ts +19 -0
  153. package/src/lib/utils/formatNumber.ts +27 -0
  154. package/src/lib/utils/locale.ts +29 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Central theme configuration
3
+ * Add new themes here and they'll automatically appear in the dropdown and type system
4
+ */
5
+ export const THEMES = [
6
+ // Neutral themes
7
+ {
8
+ value: 'sage',
9
+ label: 'Sage',
10
+ description: 'Calm green-blue',
11
+ color: 'oklch(77.77% 0.182 127.42)',
12
+ category: 'neutral'
13
+ },
14
+ {
15
+ value: 'monochrome',
16
+ label: 'Monochrome',
17
+ description: 'Pure greyscale',
18
+ color: 'oklch(78% 0 0)',
19
+ category: 'neutral'
20
+ },
21
+ {
22
+ value: 'slate',
23
+ label: 'Slate',
24
+ description: 'Blue-grey',
25
+ color: 'oklch(78.5% 0.095 230)',
26
+ category: 'neutral'
27
+ },
28
+ // Warm themes
29
+ {
30
+ value: 'ruby',
31
+ label: 'Ruby',
32
+ description: 'Bold red',
33
+ color: 'oklch(81.5% 0.228 10)',
34
+ category: 'warm'
35
+ },
36
+ {
37
+ value: 'coral',
38
+ label: 'Coral',
39
+ description: 'Orange-pink',
40
+ color: 'oklch(81.8% 0.212 20)',
41
+ category: 'warm'
42
+ },
43
+ {
44
+ value: 'sunset',
45
+ label: 'Sunset',
46
+ description: 'Warm orange',
47
+ color: 'oklch(80.5% 0.208 45)',
48
+ category: 'warm'
49
+ },
50
+ {
51
+ value: 'amber',
52
+ label: 'Amber',
53
+ description: 'Bright yellow',
54
+ color: 'oklch(82.8% 0.195 85)',
55
+ category: 'warm'
56
+ },
57
+ // Cool themes
58
+ {
59
+ value: 'forest',
60
+ label: 'Forest',
61
+ description: 'Natural green',
62
+ color: 'oklch(79.5% 0.195 145)',
63
+ category: 'cool'
64
+ },
65
+ {
66
+ value: 'teal',
67
+ label: 'Teal',
68
+ description: 'Blue-green',
69
+ color: 'oklch(79% 0.205 195)',
70
+ category: 'cool'
71
+ },
72
+ {
73
+ value: 'ocean',
74
+ label: 'Ocean',
75
+ description: 'Deep blue',
76
+ color: 'oklch(78.2% 0.188 240)',
77
+ category: 'cool'
78
+ },
79
+ // Vibrant themes
80
+ {
81
+ value: 'lavender',
82
+ label: 'Lavender',
83
+ description: 'Soft purple',
84
+ color: 'oklch(82% 0.215 295)',
85
+ category: 'vibrant'
86
+ },
87
+ {
88
+ value: 'rose',
89
+ label: 'Rose',
90
+ description: 'Pink-red',
91
+ color: 'oklch(83.5% 0.230 350)',
92
+ category: 'vibrant'
93
+ }
94
+ ];
95
+ export const DEFAULT_THEME = 'slate';
96
+ export const CATEGORY_LABELS = {
97
+ neutral: 'Neutral',
98
+ warm: 'Warm',
99
+ cool: 'Cool',
100
+ vibrant: 'Vibrant'
101
+ };
102
+ export const getThemesByCategory = () => {
103
+ const grouped = {
104
+ neutral: [],
105
+ warm: [],
106
+ cool: [],
107
+ vibrant: []
108
+ };
109
+ THEMES.forEach((theme) => {
110
+ grouped[theme.category].push(theme);
111
+ });
112
+ return grouped;
113
+ };
114
+ export const getTheme = (value) => {
115
+ return THEMES.find((theme) => theme.value === value);
116
+ };
@@ -0,0 +1,9 @@
1
+ import type { BlogPost } from '@ewanc26/atproto';
2
+ export interface PostBadge {
3
+ text: string;
4
+ color: 'mint' | 'sage' | 'jade' | 'ink';
5
+ variant: 'soft' | 'solid';
6
+ }
7
+ export declare function getPostBadges(post: BlogPost): PostBadge[];
8
+ export declare function getBadgeClasses(badge: PostBadge): string;
9
+ //# sourceMappingURL=badges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badges.d.ts","sourceRoot":"","sources":["../../src/lib/helper/badges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,CAOzD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CA0BxD"}
@@ -0,0 +1,28 @@
1
+ export function getPostBadges(post) {
2
+ const badges = [];
3
+ badges.push({ text: 'Standard.site', color: 'jade', variant: 'solid' });
4
+ if (post.publicationName) {
5
+ badges.push({ text: post.publicationName, color: 'jade', variant: 'soft' });
6
+ }
7
+ return badges;
8
+ }
9
+ export function getBadgeClasses(badge) {
10
+ const baseStyle = badge.variant === 'soft'
11
+ ? 'px-2 py-0.5 text-xs font-medium rounded'
12
+ : 'px-2 py-0.5 text-xs font-semibold uppercase rounded';
13
+ const colorClasses = {
14
+ mint: badge.variant === 'soft'
15
+ ? 'bg-secondary-100 text-secondary-800 dark:bg-secondary-900 dark:text-secondary-200'
16
+ : 'bg-secondary-500 text-white dark:bg-secondary-600',
17
+ sage: badge.variant === 'soft'
18
+ ? 'bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-200'
19
+ : 'bg-primary-500 text-white dark:bg-primary-600',
20
+ jade: badge.variant === 'soft'
21
+ ? 'bg-accent-100 text-accent-800 dark:bg-accent-900 dark:text-accent-200'
22
+ : 'bg-accent-500 text-white dark:bg-accent-600',
23
+ ink: badge.variant === 'soft'
24
+ ? 'bg-ink-100 text-ink-800 dark:bg-ink-800 dark:text-ink-100'
25
+ : 'bg-ink-700 text-white dark:bg-ink-300 dark:text-ink-900'
26
+ };
27
+ return `${baseStyle} ${colorClasses[badge.color]}`;
28
+ }
@@ -0,0 +1,14 @@
1
+ import type { BlogPost } from '@ewanc26/atproto';
2
+ export interface MonthData {
3
+ monthName: string;
4
+ posts: BlogPost[];
5
+ }
6
+ export type GroupedPosts = Map<number, Map<number, MonthData>>;
7
+ export declare function filterPosts(posts: BlogPost[], query: string): BlogPost[];
8
+ export declare function groupPostsByDate(posts: BlogPost[], locale?: string): GroupedPosts;
9
+ export declare function getSortedMonths(yearGroup: Map<number, MonthData>): [number, MonthData][];
10
+ export declare function getSortedYears(groupedPosts: GroupedPosts): number[];
11
+ export declare function getAllTags(items: Array<{
12
+ tags?: string[];
13
+ }>): string[];
14
+ //# sourceMappingURL=posts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posts.d.ts","sourceRoot":"","sources":["../../src/lib/helper/posts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,MAAM,WAAW,SAAS;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/D,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAWxE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAyBjF;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAExF;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,EAAE,CAEnE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAItE"}
@@ -0,0 +1,47 @@
1
+ import { getUserLocale } from '../utils/locale.js';
2
+ export function filterPosts(posts, query) {
3
+ if (!query.trim())
4
+ return posts;
5
+ const lowerQuery = query.toLowerCase();
6
+ return posts.filter((post) => {
7
+ const titleMatch = post.title.toLowerCase().includes(lowerQuery);
8
+ const descMatch = post.description?.toLowerCase().includes(lowerQuery);
9
+ const platformMatch = post.platform.toLowerCase().includes(lowerQuery);
10
+ const pubMatch = post.publicationName?.toLowerCase().includes(lowerQuery);
11
+ const tagsMatch = post.tags?.some((tag) => tag.toLowerCase().includes(lowerQuery));
12
+ return titleMatch || descMatch || platformMatch || pubMatch || tagsMatch;
13
+ });
14
+ }
15
+ export function groupPostsByDate(posts, locale) {
16
+ const userLocale = locale || getUserLocale();
17
+ const grouped = new Map();
18
+ posts.forEach((post) => {
19
+ const date = new Date(post.createdAt);
20
+ const year = date.getFullYear();
21
+ const month = date.getMonth();
22
+ const monthName = date.toLocaleString(userLocale, { month: 'long' });
23
+ if (!grouped.has(year))
24
+ grouped.set(year, new Map());
25
+ const yearGroup = grouped.get(year);
26
+ if (!yearGroup.has(month))
27
+ yearGroup.set(month, { monthName, posts: [] });
28
+ yearGroup.get(month).posts.push(post);
29
+ });
30
+ grouped.forEach((yearGroup) => {
31
+ yearGroup.forEach((monthData) => {
32
+ monthData.posts.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
33
+ });
34
+ });
35
+ return grouped;
36
+ }
37
+ export function getSortedMonths(yearGroup) {
38
+ return Array.from(yearGroup.entries()).sort((a, b) => b[0] - a[0]);
39
+ }
40
+ export function getSortedYears(groupedPosts) {
41
+ return Array.from(groupedPosts.keys()).sort((a, b) => b - a);
42
+ }
43
+ export function getAllTags(items) {
44
+ const tagsSet = new Set();
45
+ items.forEach((item) => item.tags?.forEach((tag) => tagsSet.add(tag.toLowerCase())));
46
+ return Array.from(tagsSet).sort();
47
+ }
@@ -0,0 +1,16 @@
1
+ export { wolfMode, colorThemeDropdownOpen, happyMacStore, colorTheme } from './stores/index.js';
2
+ export type { ColorTheme } from './stores/index.js';
3
+ export { THEMES, DEFAULT_THEME, CATEGORY_LABELS, getThemesByCategory, getTheme } from './config/themes.config.js';
4
+ export type { ThemeDefinition } from './config/themes.config.js';
5
+ export type { SiteMetadata, NavItem } from './types/index.js';
6
+ export { filterPosts, groupPostsByDate, getSortedMonths, getSortedYears, getAllTags } from './helper/posts.js';
7
+ export type { MonthData, GroupedPosts } from './helper/posts.js';
8
+ export { getPostBadges, getBadgeClasses } from './helper/badges.js';
9
+ export type { PostBadge } from './helper/badges.js';
10
+ export { default as ThemeToggle } from './components/layout/ThemeToggle.svelte';
11
+ export { default as WolfToggle } from './components/layout/WolfToggle.svelte';
12
+ export { DynamicLinks, ScrollToTop, TangledRepos } from './components/layout/main/index.js';
13
+ export { LinkCard, ProfileCard, PostCard, BlueskyPostCard, TangledRepoCard, MusicStatusCard, KibunStatusCard } from './components/layout/main/card/index.js';
14
+ export { MetaTags } from './components/seo/index.js';
15
+ export { Card, InternalCard, Dropdown, Pagination, SearchBar, Tabs, PostsGroupedView, DocumentCard, BlogPostCard } from './components/ui/index.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChG,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAClH,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/G,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACpE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAG9E,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAG5F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAG7J,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // ─── Stores ───────────────────────────────────────────────────────────────────
2
+ export { wolfMode, colorThemeDropdownOpen, happyMacStore, colorTheme } from './stores/index.js';
3
+ // ─── Config ───────────────────────────────────────────────────────────────────
4
+ export { THEMES, DEFAULT_THEME, CATEGORY_LABELS, getThemesByCategory, getTheme } from './config/themes.config.js';
5
+ // ─── Helper ───────────────────────────────────────────────────────────────────
6
+ export { filterPosts, groupPostsByDate, getSortedMonths, getSortedYears, getAllTags } from './helper/posts.js';
7
+ export { getPostBadges, getBadgeClasses } from './helper/badges.js';
8
+ // ─── Layout toggles ───────────────────────────────────────────────────────────
9
+ export { default as ThemeToggle } from './components/layout/ThemeToggle.svelte';
10
+ export { default as WolfToggle } from './components/layout/WolfToggle.svelte';
11
+ // ─── Layout main ──────────────────────────────────────────────────────────────
12
+ export { DynamicLinks, ScrollToTop, TangledRepos } from './components/layout/main/index.js';
13
+ // ─── Cards ────────────────────────────────────────────────────────────────────
14
+ export { LinkCard, ProfileCard, PostCard, BlueskyPostCard, TangledRepoCard, MusicStatusCard, KibunStatusCard } from './components/layout/main/card/index.js';
15
+ // ─── SEO ──────────────────────────────────────────────────────────────────────
16
+ export { MetaTags } from './components/seo/index.js';
17
+ // ─── UI primitives ────────────────────────────────────────────────────────────
18
+ export { Card, InternalCard, Dropdown, Pagination, SearchBar, Tabs, PostsGroupedView, DocumentCard, BlogPostCard } from './components/ui/index.js';
@@ -0,0 +1,12 @@
1
+ import { type ColorTheme } from '../config/themes.config.js';
2
+ interface ColorThemeState {
3
+ current: ColorTheme;
4
+ mounted: boolean;
5
+ }
6
+ export declare const colorTheme: {
7
+ subscribe: (this: void, run: import("svelte/store").Subscriber<ColorThemeState>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
8
+ init: () => void;
9
+ setTheme: (theme: ColorTheme) => void;
10
+ };
11
+ export type { ColorTheme };
12
+ //# sourceMappingURL=colorTheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colorTheme.d.ts","sourceRoot":"","sources":["../../src/lib/stores/colorTheme.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAI5E,UAAU,eAAe;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CACjB;AAkCD,eAAO,MAAM,UAAU;;;sBAdH,UAAU;CAcmB,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { writable } from 'svelte/store';
2
+ import { DEFAULT_THEME } from '../config/themes.config.js';
3
+ const browser = typeof window !== 'undefined';
4
+ const STORAGE_KEY = 'color-theme';
5
+ function createColorThemeStore() {
6
+ const { subscribe, set, update } = writable({
7
+ current: DEFAULT_THEME,
8
+ mounted: false
9
+ });
10
+ return {
11
+ subscribe,
12
+ init: () => {
13
+ if (!browser)
14
+ return;
15
+ const stored = localStorage.getItem(STORAGE_KEY);
16
+ const theme = stored || DEFAULT_THEME;
17
+ update((state) => ({ ...state, current: theme, mounted: true }));
18
+ const currentTheme = document.documentElement.getAttribute('data-color-theme');
19
+ if (currentTheme !== theme)
20
+ applyTheme(theme);
21
+ },
22
+ setTheme: (theme) => {
23
+ if (!browser)
24
+ return;
25
+ localStorage.setItem(STORAGE_KEY, theme);
26
+ update((state) => ({ ...state, current: theme }));
27
+ applyTheme(theme);
28
+ }
29
+ };
30
+ }
31
+ function applyTheme(theme) {
32
+ if (!browser)
33
+ return;
34
+ document.documentElement.setAttribute('data-color-theme', theme);
35
+ }
36
+ export const colorTheme = createColorThemeStore();
@@ -0,0 +1,2 @@
1
+ export declare const colorThemeDropdownOpen: import("svelte/store").Writable<boolean>;
2
+ //# sourceMappingURL=dropdownState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdownState.d.ts","sourceRoot":"","sources":["../../src/lib/stores/dropdownState.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB,0CAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { writable } from 'svelte/store';
2
+ export const colorThemeDropdownOpen = writable(false);
@@ -0,0 +1,11 @@
1
+ interface HappyMacState {
2
+ clickCount: number;
3
+ isTriggered: boolean;
4
+ }
5
+ export declare const happyMacStore: {
6
+ subscribe: (this: void, run: import("svelte/store").Subscriber<HappyMacState>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
7
+ incrementClick: () => void;
8
+ reset: () => void;
9
+ };
10
+ export {};
11
+ //# sourceMappingURL=happyMac.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"happyMac.d.ts","sourceRoot":"","sources":["../../src/lib/stores/happyMac.ts"],"names":[],"mappings":"AAEA,UAAU,aAAa;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACrB;AAsBD,eAAO,MAAM,aAAa;;;;CAAwB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { writable } from 'svelte/store';
2
+ function createHappyMacStore() {
3
+ const { subscribe, set, update } = writable({
4
+ clickCount: 0,
5
+ isTriggered: false
6
+ });
7
+ return {
8
+ subscribe,
9
+ incrementClick: () => update((state) => {
10
+ const newCount = state.clickCount + 1;
11
+ if (newCount === 24) {
12
+ return { clickCount: newCount, isTriggered: true };
13
+ }
14
+ return { ...state, clickCount: newCount };
15
+ }),
16
+ reset: () => set({ clickCount: 0, isTriggered: false })
17
+ };
18
+ }
19
+ export const happyMacStore = createHappyMacStore();
@@ -0,0 +1,6 @@
1
+ export { wolfMode } from './wolfMode.js';
2
+ export { colorThemeDropdownOpen } from './dropdownState.js';
3
+ export { happyMacStore } from './happyMac.js';
4
+ export { colorTheme } from './colorTheme.js';
5
+ export type { ColorTheme } from './colorTheme.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { wolfMode } from './wolfMode.js';
2
+ export { colorThemeDropdownOpen } from './dropdownState.js';
3
+ export { happyMacStore } from './happyMac.js';
4
+ export { colorTheme } from './colorTheme.js';
@@ -0,0 +1,7 @@
1
+ export declare const wolfMode: {
2
+ subscribe: (this: void, run: import("svelte/store").Subscriber<boolean>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
3
+ toggle: () => void;
4
+ enable: () => void;
5
+ disable: () => void;
6
+ };
7
+ //# sourceMappingURL=wolfMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wolfMode.d.ts","sourceRoot":"","sources":["../../src/lib/stores/wolfMode.ts"],"names":[],"mappings":"AA8HA,eAAO,MAAM,QAAQ;;;;;CAAwB,CAAC"}
@@ -0,0 +1,130 @@
1
+ import { writable } from 'svelte/store';
2
+ const browser = typeof window !== 'undefined';
3
+ const wolfSounds = [
4
+ 'awoo', 'awooo', 'howl', 'ahroo', 'owww', 'yip', 'yap', 'arf', 'ruff', 'woof',
5
+ 'grr', 'grrr', 'growl', 'snarl', 'whine', 'whimper', 'bark', 'yowl', 'yelp', 'huff'
6
+ ];
7
+ let originalTexts = new Map();
8
+ let wordCounter = 0;
9
+ let wordToSoundMap = new Map();
10
+ function createWolfModeStore() {
11
+ const { subscribe, set, update } = writable(false);
12
+ return {
13
+ subscribe,
14
+ toggle: () => {
15
+ update((value) => {
16
+ const newValue = !value;
17
+ if (browser) {
18
+ if (newValue)
19
+ enableWolfMode();
20
+ else
21
+ disableWolfMode();
22
+ }
23
+ return newValue;
24
+ });
25
+ },
26
+ enable: () => { set(true); if (browser)
27
+ enableWolfMode(); },
28
+ disable: () => { set(false); if (browser)
29
+ disableWolfMode(); }
30
+ };
31
+ }
32
+ function getWolfSoundByPosition(position) {
33
+ return wolfSounds[position % wolfSounds.length];
34
+ }
35
+ function getWolfSoundForWord(word, position) {
36
+ const normalizedWord = word.toLowerCase();
37
+ if (wordToSoundMap.has(normalizedWord))
38
+ return wordToSoundMap.get(normalizedWord);
39
+ const wolfSound = getWolfSoundByPosition(position);
40
+ wordToSoundMap.set(normalizedWord, wolfSound);
41
+ return wolfSound;
42
+ }
43
+ function isNumberAbbreviation(text) {
44
+ return /^\d+\.?\d*[a-zA-Z]+$/.test(text);
45
+ }
46
+ function hasAlphabeticalCharacters(text) {
47
+ return /[a-zA-Z]/.test(text);
48
+ }
49
+ function shouldTransform(word) {
50
+ if (!hasAlphabeticalCharacters(word))
51
+ return false;
52
+ if (isNumberAbbreviation(word))
53
+ return false;
54
+ return true;
55
+ }
56
+ function splitWordAndPunctuation(token) {
57
+ const match = token.match(/^([^a-zA-Z0-9]*)([a-zA-Z0-9]+)([^a-zA-Z0-9]*)$/);
58
+ if (match)
59
+ return { prefix: match[1], word: match[2], suffix: match[3] };
60
+ return { prefix: '', word: token, suffix: '' };
61
+ }
62
+ function convertToWolfSpeak(text, startPosition) {
63
+ const words = text.split(/(\s+)/);
64
+ let currentPosition = startPosition;
65
+ return words.map((token) => {
66
+ if (token.trim().length === 0)
67
+ return token;
68
+ const { prefix, word, suffix } = splitWordAndPunctuation(token);
69
+ if (!shouldTransform(word))
70
+ return token;
71
+ const wolfSound = getWolfSoundForWord(word, currentPosition);
72
+ currentPosition++;
73
+ let transformedWord = wolfSound;
74
+ if (word === word.toUpperCase() && word.length > 1)
75
+ transformedWord = wolfSound.toUpperCase();
76
+ else if (word[0] === word[0].toUpperCase())
77
+ transformedWord = wolfSound.charAt(0).toUpperCase() + wolfSound.slice(1);
78
+ return prefix + transformedWord + suffix;
79
+ }).join('');
80
+ }
81
+ function shouldSkipElement(element) {
82
+ if (element.hasAttribute('aria-label')) {
83
+ const label = element.getAttribute('aria-label') || '';
84
+ if (label.includes('wolf mode') || label.includes('theme') || label.includes('mode'))
85
+ return true;
86
+ }
87
+ if (element.closest('header button'))
88
+ return true;
89
+ if (element.tagName === 'NAV' || element.closest('nav'))
90
+ return true;
91
+ return false;
92
+ }
93
+ function walkTextNodes(node, callback) {
94
+ if (node.nodeType === Node.TEXT_NODE) {
95
+ callback(node);
96
+ }
97
+ else if (node.nodeType === Node.ELEMENT_NODE) {
98
+ const element = node;
99
+ if (element.tagName === 'SCRIPT' || element.tagName === 'STYLE' || shouldSkipElement(element))
100
+ return;
101
+ for (const child of Array.from(node.childNodes))
102
+ walkTextNodes(child, callback);
103
+ }
104
+ }
105
+ function enableWolfMode() {
106
+ originalTexts.clear();
107
+ wordToSoundMap.clear();
108
+ wordCounter = 0;
109
+ walkTextNodes(document.body, (textNode) => {
110
+ const originalText = textNode.textContent || '';
111
+ if (originalText.trim().length > 0) {
112
+ originalTexts.set(textNode, originalText);
113
+ textNode.textContent = convertToWolfSpeak(originalText, wordCounter);
114
+ wordCounter += originalText.split(/\s+/).filter((w) => {
115
+ const { word } = splitWordAndPunctuation(w);
116
+ return shouldTransform(word);
117
+ }).length;
118
+ }
119
+ });
120
+ }
121
+ function disableWolfMode() {
122
+ originalTexts.forEach((originalText, textNode) => {
123
+ if (textNode.parentNode)
124
+ textNode.textContent = originalText;
125
+ });
126
+ originalTexts.clear();
127
+ wordToSoundMap.clear();
128
+ wordCounter = 0;
129
+ }
130
+ export const wolfMode = createWolfModeStore();
@@ -0,0 +1,19 @@
1
+ export interface SiteMetadata {
2
+ title: string;
3
+ description: string;
4
+ keywords: string;
5
+ url: string;
6
+ image: string;
7
+ imageWidth?: number;
8
+ imageHeight?: number;
9
+ }
10
+ /**
11
+ * A nav item used by Header and NavLinks.
12
+ * The `iconPath` is a Lucide icon component name (e.g. 'Home', 'Archive').
13
+ */
14
+ export interface NavItem {
15
+ href: string;
16
+ label: string;
17
+ iconPath: string;
18
+ }
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function formatCompactNumber(num?: number, locale?: string): string;
2
+ export declare function formatNumber(num: number, locale?: string): string;
3
+ //# sourceMappingURL=formatNumber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatNumber.d.ts","sourceRoot":"","sources":["../../src/lib/utils/formatNumber.ts"],"names":[],"mappings":"AAIA,wBAAgB,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAkBzE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,26 @@
1
+ function getLocale(locale) {
2
+ return locale || (typeof navigator !== 'undefined' && navigator.language) || 'en-GB';
3
+ }
4
+ export function formatCompactNumber(num, locale) {
5
+ if (num === undefined || num === null)
6
+ return '0';
7
+ const effectiveLocale = getLocale(locale);
8
+ if (num >= 1000) {
9
+ const divisor = num >= 1000000000 ? 1000000000 : num >= 1000000 ? 1000000 : 1000;
10
+ const roundedDown = Math.floor((num / divisor) * 10) / 10;
11
+ const adjustedNum = roundedDown * divisor;
12
+ return new Intl.NumberFormat(effectiveLocale, {
13
+ notation: 'compact',
14
+ compactDisplay: 'short',
15
+ maximumFractionDigits: 1
16
+ }).format(adjustedNum);
17
+ }
18
+ return new Intl.NumberFormat(effectiveLocale, {
19
+ notation: 'compact',
20
+ compactDisplay: 'short',
21
+ maximumFractionDigits: 1
22
+ }).format(num);
23
+ }
24
+ export function formatNumber(num, locale) {
25
+ return new Intl.NumberFormat(getLocale(locale)).format(num);
26
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getUserLocale(): string;
2
+ export declare function formatLocalizedDate(dateString: string, locale?: string): string;
3
+ export declare function formatRelativeTime(dateString: string): string;
4
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/lib/utils/locale.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,IAAI,MAAM,CAGtC;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/E;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAiB7D"}
@@ -0,0 +1,32 @@
1
+ export function getUserLocale() {
2
+ if (typeof navigator !== 'undefined')
3
+ return navigator.language || 'en-GB';
4
+ return 'en-GB';
5
+ }
6
+ export function formatLocalizedDate(dateString, locale) {
7
+ const date = new Date(dateString);
8
+ const userLocale = locale || getUserLocale();
9
+ return date.toLocaleDateString(userLocale, { month: 'short', day: 'numeric', year: 'numeric' });
10
+ }
11
+ export function formatRelativeTime(dateString) {
12
+ const date = new Date(dateString);
13
+ const now = new Date();
14
+ const diffMs = now.getTime() - date.getTime();
15
+ const diffMins = Math.floor(diffMs / 60000);
16
+ const diffHours = Math.floor(diffMins / 60);
17
+ const diffDays = Math.floor(diffHours / 24);
18
+ if (diffMins < 1)
19
+ return 'just now';
20
+ if (diffMins < 60)
21
+ return `${diffMins}m ago`;
22
+ if (diffHours < 24)
23
+ return `${diffHours}h ago`;
24
+ if (diffDays < 7)
25
+ return `${diffDays}d ago`;
26
+ const userLocale = getUserLocale();
27
+ return date.toLocaleDateString(userLocale, {
28
+ day: 'numeric',
29
+ month: 'short',
30
+ year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined
31
+ });
32
+ }