@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.
- package/README.md +65 -0
- package/dist/components/layout/ThemeToggle.svelte +50 -0
- package/dist/components/layout/ThemeToggle.svelte.d.ts +4 -0
- package/dist/components/layout/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/components/layout/WolfToggle.svelte +19 -0
- package/dist/components/layout/WolfToggle.svelte.d.ts +4 -0
- package/dist/components/layout/WolfToggle.svelte.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +5 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/index.js +4 -0
- package/dist/components/layout/main/DynamicLinks.svelte +63 -0
- package/dist/components/layout/main/DynamicLinks.svelte.d.ts +7 -0
- package/dist/components/layout/main/DynamicLinks.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/ScrollToTop.svelte +36 -0
- package/dist/components/layout/main/ScrollToTop.svelte.d.ts +4 -0
- package/dist/components/layout/main/ScrollToTop.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/BlueskyPostCard.svelte +261 -0
- package/dist/components/layout/main/card/BlueskyPostCard.svelte.d.ts +9 -0
- package/dist/components/layout/main/card/BlueskyPostCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/KibunStatusCard.svelte +48 -0
- package/dist/components/layout/main/card/KibunStatusCard.svelte.d.ts +8 -0
- package/dist/components/layout/main/card/KibunStatusCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/LinkCard.svelte +63 -0
- package/dist/components/layout/main/card/LinkCard.svelte.d.ts +17 -0
- package/dist/components/layout/main/card/LinkCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/MusicStatusCard.svelte +101 -0
- package/dist/components/layout/main/card/MusicStatusCard.svelte.d.ts +8 -0
- package/dist/components/layout/main/card/MusicStatusCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/PostCard.svelte +46 -0
- package/dist/components/layout/main/card/PostCard.svelte.d.ts +8 -0
- package/dist/components/layout/main/card/PostCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/ProfileCard.svelte +70 -0
- package/dist/components/layout/main/card/ProfileCard.svelte.d.ts +8 -0
- package/dist/components/layout/main/card/ProfileCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/TangledRepoCard.svelte +80 -0
- package/dist/components/layout/main/card/TangledRepoCard.svelte.d.ts +11 -0
- package/dist/components/layout/main/card/TangledRepoCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/main/card/index.d.ts +8 -0
- package/dist/components/layout/main/card/index.d.ts.map +1 -0
- package/dist/components/layout/main/card/index.js +7 -0
- package/dist/components/layout/main/index.d.ts +4 -0
- package/dist/components/layout/main/index.d.ts.map +1 -0
- package/dist/components/layout/main/index.js +3 -0
- package/dist/components/seo/MetaTags.svelte +39 -0
- package/dist/components/seo/MetaTags.svelte.d.ts +9 -0
- package/dist/components/seo/MetaTags.svelte.d.ts.map +1 -0
- package/dist/components/seo/index.d.ts +2 -0
- package/dist/components/seo/index.d.ts.map +1 -0
- package/dist/components/seo/index.js +1 -0
- package/dist/components/ui/BlogPostCard.svelte +44 -0
- package/dist/components/ui/BlogPostCard.svelte.d.ts +9 -0
- package/dist/components/ui/BlogPostCard.svelte.d.ts.map +1 -0
- package/dist/components/ui/Card.svelte +144 -0
- package/dist/components/ui/Card.svelte.d.ts +27 -0
- package/dist/components/ui/Card.svelte.d.ts.map +1 -0
- package/dist/components/ui/DocumentCard.svelte +42 -0
- package/dist/components/ui/DocumentCard.svelte.d.ts +9 -0
- package/dist/components/ui/DocumentCard.svelte.d.ts.map +1 -0
- package/dist/components/ui/Dropdown.svelte +36 -0
- package/dist/components/ui/Dropdown.svelte.d.ts +15 -0
- package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -0
- package/dist/components/ui/InternalCard.svelte +41 -0
- package/dist/components/ui/InternalCard.svelte.d.ts +14 -0
- package/dist/components/ui/InternalCard.svelte.d.ts.map +1 -0
- package/dist/components/ui/Pagination.svelte +74 -0
- package/dist/components/ui/Pagination.svelte.d.ts +11 -0
- package/dist/components/ui/Pagination.svelte.d.ts.map +1 -0
- package/dist/components/ui/PostsGroupedView.svelte +40 -0
- package/dist/components/ui/PostsGroupedView.svelte.d.ts +10 -0
- package/dist/components/ui/PostsGroupedView.svelte.d.ts.map +1 -0
- package/dist/components/ui/SearchBar.svelte +26 -0
- package/dist/components/ui/SearchBar.svelte.d.ts +9 -0
- package/dist/components/ui/SearchBar.svelte.d.ts.map +1 -0
- package/dist/components/ui/Tabs.svelte +25 -0
- package/dist/components/ui/Tabs.svelte.d.ts +13 -0
- package/dist/components/ui/Tabs.svelte.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +11 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +10 -0
- package/dist/config/themes.config.d.ts +23 -0
- package/dist/config/themes.config.d.ts.map +1 -0
- package/dist/config/themes.config.js +116 -0
- package/dist/helper/badges.d.ts +9 -0
- package/dist/helper/badges.d.ts.map +1 -0
- package/dist/helper/badges.js +28 -0
- package/dist/helper/posts.d.ts +14 -0
- package/dist/helper/posts.d.ts.map +1 -0
- package/dist/helper/posts.js +47 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/stores/colorTheme.d.ts +12 -0
- package/dist/stores/colorTheme.d.ts.map +1 -0
- package/dist/stores/colorTheme.js +36 -0
- package/dist/stores/dropdownState.d.ts +2 -0
- package/dist/stores/dropdownState.d.ts.map +1 -0
- package/dist/stores/dropdownState.js +2 -0
- package/dist/stores/happyMac.d.ts +11 -0
- package/dist/stores/happyMac.d.ts.map +1 -0
- package/dist/stores/happyMac.js +19 -0
- package/dist/stores/index.d.ts +6 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +4 -0
- package/dist/stores/wolfMode.d.ts +7 -0
- package/dist/stores/wolfMode.d.ts.map +1 -0
- package/dist/stores/wolfMode.js +130 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/formatNumber.d.ts +3 -0
- package/dist/utils/formatNumber.d.ts.map +1 -0
- package/dist/utils/formatNumber.js +26 -0
- package/dist/utils/locale.d.ts +4 -0
- package/dist/utils/locale.d.ts.map +1 -0
- package/dist/utils/locale.js +32 -0
- package/package.json +45 -0
- package/src/lib/components/layout/ThemeToggle.svelte +50 -0
- package/src/lib/components/layout/WolfToggle.svelte +19 -0
- package/src/lib/components/layout/index.ts +4 -0
- package/src/lib/components/layout/main/DynamicLinks.svelte +63 -0
- package/src/lib/components/layout/main/ScrollToTop.svelte +36 -0
- package/src/lib/components/layout/main/card/BlueskyPostCard.svelte +261 -0
- package/src/lib/components/layout/main/card/KibunStatusCard.svelte +48 -0
- package/src/lib/components/layout/main/card/LinkCard.svelte +63 -0
- package/src/lib/components/layout/main/card/MusicStatusCard.svelte +101 -0
- package/src/lib/components/layout/main/card/PostCard.svelte +46 -0
- package/src/lib/components/layout/main/card/ProfileCard.svelte +70 -0
- package/src/lib/components/layout/main/card/TangledRepoCard.svelte +80 -0
- package/src/lib/components/layout/main/card/index.ts +7 -0
- package/src/lib/components/layout/main/index.ts +3 -0
- package/src/lib/components/seo/MetaTags.svelte +39 -0
- package/src/lib/components/seo/index.ts +1 -0
- package/src/lib/components/ui/BlogPostCard.svelte +44 -0
- package/src/lib/components/ui/Card.svelte +144 -0
- package/src/lib/components/ui/DocumentCard.svelte +42 -0
- package/src/lib/components/ui/Dropdown.svelte +36 -0
- package/src/lib/components/ui/InternalCard.svelte +41 -0
- package/src/lib/components/ui/Pagination.svelte +74 -0
- package/src/lib/components/ui/PostsGroupedView.svelte +40 -0
- package/src/lib/components/ui/SearchBar.svelte +26 -0
- package/src/lib/components/ui/Tabs.svelte +25 -0
- package/src/lib/components/ui/index.ts +10 -0
- package/src/lib/config/themes.config.ts +130 -0
- package/src/lib/helper/badges.ts +44 -0
- package/src/lib/helper/posts.ts +63 -0
- package/src/lib/index.ts +32 -0
- package/src/lib/stores/colorTheme.ts +44 -0
- package/src/lib/stores/dropdownState.ts +3 -0
- package/src/lib/stores/happyMac.ts +28 -0
- package/src/lib/stores/index.ts +5 -0
- package/src/lib/stores/wolfMode.ts +127 -0
- package/src/lib/types/index.ts +19 -0
- package/src/lib/utils/formatNumber.ts +27 -0
- package/src/lib/utils/locale.ts +29 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { writable } from 'svelte/store';
|
|
2
|
+
|
|
3
|
+
const browser = typeof window !== 'undefined';
|
|
4
|
+
|
|
5
|
+
const wolfSounds = [
|
|
6
|
+
'awoo', 'awooo', 'howl', 'ahroo', 'owww', 'yip', 'yap', 'arf', 'ruff', 'woof',
|
|
7
|
+
'grr', 'grrr', 'growl', 'snarl', 'whine', 'whimper', 'bark', 'yowl', 'yelp', 'huff'
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
let originalTexts = new Map<Node, string>();
|
|
11
|
+
let wordCounter = 0;
|
|
12
|
+
let wordToSoundMap = new Map<string, string>();
|
|
13
|
+
|
|
14
|
+
function createWolfModeStore() {
|
|
15
|
+
const { subscribe, set, update } = writable(false);
|
|
16
|
+
return {
|
|
17
|
+
subscribe,
|
|
18
|
+
toggle: () => {
|
|
19
|
+
update((value) => {
|
|
20
|
+
const newValue = !value;
|
|
21
|
+
if (browser) {
|
|
22
|
+
if (newValue) enableWolfMode();
|
|
23
|
+
else disableWolfMode();
|
|
24
|
+
}
|
|
25
|
+
return newValue;
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
enable: () => { set(true); if (browser) enableWolfMode(); },
|
|
29
|
+
disable: () => { set(false); if (browser) disableWolfMode(); }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getWolfSoundByPosition(position: number): string {
|
|
34
|
+
return wolfSounds[position % wolfSounds.length];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getWolfSoundForWord(word: string, position: number): string {
|
|
38
|
+
const normalizedWord = word.toLowerCase();
|
|
39
|
+
if (wordToSoundMap.has(normalizedWord)) return wordToSoundMap.get(normalizedWord)!;
|
|
40
|
+
const wolfSound = getWolfSoundByPosition(position);
|
|
41
|
+
wordToSoundMap.set(normalizedWord, wolfSound);
|
|
42
|
+
return wolfSound;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isNumberAbbreviation(text: string): boolean {
|
|
46
|
+
return /^\d+\.?\d*[a-zA-Z]+$/.test(text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function hasAlphabeticalCharacters(text: string): boolean {
|
|
50
|
+
return /[a-zA-Z]/.test(text);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function shouldTransform(word: string): boolean {
|
|
54
|
+
if (!hasAlphabeticalCharacters(word)) return false;
|
|
55
|
+
if (isNumberAbbreviation(word)) return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function splitWordAndPunctuation(token: string): { prefix: string; word: string; suffix: string } {
|
|
60
|
+
const match = token.match(/^([^a-zA-Z0-9]*)([a-zA-Z0-9]+)([^a-zA-Z0-9]*)$/);
|
|
61
|
+
if (match) return { prefix: match[1], word: match[2], suffix: match[3] };
|
|
62
|
+
return { prefix: '', word: token, suffix: '' };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function convertToWolfSpeak(text: string, startPosition: number): string {
|
|
66
|
+
const words = text.split(/(\s+)/);
|
|
67
|
+
let currentPosition = startPosition;
|
|
68
|
+
return words.map((token) => {
|
|
69
|
+
if (token.trim().length === 0) return token;
|
|
70
|
+
const { prefix, word, suffix } = splitWordAndPunctuation(token);
|
|
71
|
+
if (!shouldTransform(word)) return token;
|
|
72
|
+
const wolfSound = getWolfSoundForWord(word, currentPosition);
|
|
73
|
+
currentPosition++;
|
|
74
|
+
let transformedWord = wolfSound;
|
|
75
|
+
if (word === word.toUpperCase() && word.length > 1) transformedWord = wolfSound.toUpperCase();
|
|
76
|
+
else if (word[0] === word[0].toUpperCase()) transformedWord = wolfSound.charAt(0).toUpperCase() + wolfSound.slice(1);
|
|
77
|
+
return prefix + transformedWord + suffix;
|
|
78
|
+
}).join('');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function shouldSkipElement(element: Element): boolean {
|
|
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')) return true;
|
|
85
|
+
}
|
|
86
|
+
if (element.closest('header button')) return true;
|
|
87
|
+
if (element.tagName === 'NAV' || element.closest('nav')) return true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function walkTextNodes(node: Node, callback: (textNode: Text) => void) {
|
|
92
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
93
|
+
callback(node as Text);
|
|
94
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
95
|
+
const element = node as Element;
|
|
96
|
+
if (element.tagName === 'SCRIPT' || element.tagName === 'STYLE' || shouldSkipElement(element)) return;
|
|
97
|
+
for (const child of Array.from(node.childNodes)) walkTextNodes(child, callback);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function enableWolfMode() {
|
|
102
|
+
originalTexts.clear();
|
|
103
|
+
wordToSoundMap.clear();
|
|
104
|
+
wordCounter = 0;
|
|
105
|
+
walkTextNodes(document.body, (textNode) => {
|
|
106
|
+
const originalText = textNode.textContent || '';
|
|
107
|
+
if (originalText.trim().length > 0) {
|
|
108
|
+
originalTexts.set(textNode, originalText);
|
|
109
|
+
textNode.textContent = convertToWolfSpeak(originalText, wordCounter);
|
|
110
|
+
wordCounter += originalText.split(/\s+/).filter((w) => {
|
|
111
|
+
const { word } = splitWordAndPunctuation(w);
|
|
112
|
+
return shouldTransform(word);
|
|
113
|
+
}).length;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function disableWolfMode() {
|
|
119
|
+
originalTexts.forEach((originalText, textNode) => {
|
|
120
|
+
if (textNode.parentNode) textNode.textContent = originalText;
|
|
121
|
+
});
|
|
122
|
+
originalTexts.clear();
|
|
123
|
+
wordToSoundMap.clear();
|
|
124
|
+
wordCounter = 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
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
|
+
/**
|
|
12
|
+
* A nav item used by Header and NavLinks.
|
|
13
|
+
* The `iconPath` is a Lucide icon component name (e.g. 'Home', 'Archive').
|
|
14
|
+
*/
|
|
15
|
+
export interface NavItem {
|
|
16
|
+
href: string;
|
|
17
|
+
label: string;
|
|
18
|
+
iconPath: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function getLocale(locale?: string): string {
|
|
2
|
+
return locale || (typeof navigator !== 'undefined' && navigator.language) || 'en-GB';
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function formatCompactNumber(num?: number, locale?: string): string {
|
|
6
|
+
if (num === undefined || num === null) 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
|
+
|
|
25
|
+
export function formatNumber(num: number, locale?: string): string {
|
|
26
|
+
return new Intl.NumberFormat(getLocale(locale)).format(num);
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function getUserLocale(): string {
|
|
2
|
+
if (typeof navigator !== 'undefined') return navigator.language || 'en-GB';
|
|
3
|
+
return 'en-GB';
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function formatLocalizedDate(dateString: string, locale?: string): string {
|
|
7
|
+
const date = new Date(dateString);
|
|
8
|
+
const userLocale = locale || getUserLocale();
|
|
9
|
+
return date.toLocaleDateString(userLocale, { month: 'short', day: 'numeric', year: 'numeric' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function formatRelativeTime(dateString: string): string {
|
|
13
|
+
const date = new Date(dateString);
|
|
14
|
+
const now = new Date();
|
|
15
|
+
const diffMs = now.getTime() - date.getTime();
|
|
16
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
17
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
18
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
19
|
+
if (diffMins < 1) return 'just now';
|
|
20
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
21
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
22
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
23
|
+
const userLocale = getUserLocale();
|
|
24
|
+
return date.toLocaleDateString(userLocale, {
|
|
25
|
+
day: 'numeric',
|
|
26
|
+
month: 'short',
|
|
27
|
+
year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined
|
|
28
|
+
});
|
|
29
|
+
}
|