Skip to content

Commit 8e72a3e

Browse files
committed
Updates image paths
1 parent bcb7597 commit 8e72a3e

4 files changed

Lines changed: 12 additions & 152 deletions

File tree

.github/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ If you're new to GitHub or open source, take a look at [git-in.to](https://git-i
136136
<p align="center">
137137
<i>© <a href="https://aliciasykes.com">Alicia Sykes</a> 2025</i><br>
138138
<i>Licensed under <a href="https://gist.github.com/Lissy93/143d2ee01ccc5c052a17">MIT</a></i><br>
139-
<a href="https://github.com/lissy93"><img src="https://i.ibb.co/4KtpYxb/octocat-clean-mini.png" /></a><br>
139+
<a href="https://github.com/lissy93"><img src="https://cdn.as93.net/84m3gc?w=56" /></a><br>
140140
<sup>Thanks for visiting :)</sup>
141141
</p>
142142

src/lib/components/global/GlobalSearch.svelte

Lines changed: 4 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import { frequentlyUsedTools, toolUsage } from '$lib/stores/toolUsage';
1111
import { tooltip } from '$lib/actions/tooltip';
1212
import { formatShortcut } from '$lib/utils/keyboard';
13+
import { searchPages } from '$lib/utils/search';
1314
1415
interface Props {
1516
embedded?: boolean; // Whether this is embedded in a page vs popup modal
@@ -37,34 +38,6 @@
3738
let selectedIndex = $state(0);
3839
let searchInput: HTMLInputElement | undefined = $state();
3940
40-
// Levenshtein distance for fuzzy matching
41-
42-
/**
43-
* Calculate the Levenshtein distance between two strings (aka similarity score)
44-
* Ok, chill before you scream "import a library"...
45-
* It's not as bad as it looks.... Basically, we're just creating a 2D array
46-
* and filling it in based on character comparisons. The array size is small
47-
* (query length x label length) so performance is not a big deal here.
48-
* It's just a rudimentary fuzzy search to catch typos and close matches.
49-
* @param a (string 1)
50-
* @param b (string 2)
51-
*/
52-
function levenshtein(a: string, b: string): number {
53-
const matrix: number[][] = [];
54-
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
55-
for (let j = 0; j <= a.length; j++) matrix[0]![j] = j;
56-
for (let i = 1; i <= b.length; i++) {
57-
for (let j = 1; j <= a.length; j++) {
58-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
59-
matrix[i]![j] = matrix[i - 1]![j - 1]!;
60-
} else {
61-
matrix[i]![j] = Math.min(matrix[i - 1]![j - 1]! + 1, matrix[i]![j - 1]! + 1, matrix[i - 1]![j]! + 1);
62-
}
63-
}
64-
}
65-
return matrix[b.length]![a.length]!;
66-
}
67-
6841
// Get smart suggestions when no results
6942
function getSuggested(): NavItem[] {
7043
const fromStores = [...$frequentlyUsedTools, ...$bookmarks]
@@ -80,126 +53,13 @@
8053
function search(q: string): NavItem[] {
8154
if (!q.trim()) return [];
8255
83-
const normalizedQuery = q.toLowerCase().trim();
84-
const tokens = normalizedQuery.split(/\s+/);
8556
const bookmarkedHrefs = new Set($bookmarks.map((b) => b.href));
8657
const frequentHrefs = new Set($frequentlyUsedTools.map((t) => t.href));
8758
88-
const results = ALL_PAGES.map((page) => {
89-
let score = 0;
90-
const label = page.label.toLowerCase();
91-
const searchText = `${label} ${page.description || ''} ${page.keywords?.join(' ') || ''}`.toLowerCase();
92-
93-
// Exact label match (highest priority)
94-
if (label === normalizedQuery) score += 1000;
95-
96-
// Label starts with query
97-
if (label.startsWith(normalizedQuery)) score += 500;
98-
99-
// Label contains query
100-
if (label.includes(normalizedQuery)) score += 200;
101-
102-
// All tokens found
103-
if (tokens.every((token) => searchText.includes(token))) score += 100;
104-
105-
// Keywords match
106-
if (page.keywords) {
107-
tokens.forEach((token) => {
108-
if (page.keywords!.some((kw) => kw.toLowerCase().includes(token))) score += 50;
109-
});
110-
}
111-
112-
// Description match
113-
if (page.description && tokens.some((token) => page.description!.toLowerCase().includes(token))) {
114-
score += 25;
115-
}
116-
117-
// Boost for bookmarked/frequent
118-
if (bookmarkedHrefs.has(page.href)) score += 15;
119-
if (frequentHrefs.has(page.href)) score += 10;
120-
121-
return { ...page, score };
122-
})
123-
.filter((page) => page.score > 10)
124-
.sort((a, b) => b.score - a.score);
125-
126-
// If few/no results and query is reasonable length, do fuzzy search
127-
if (results.length < 3 && normalizedQuery.length >= 2 && normalizedQuery.length <= 20) {
128-
const fuzzyResults = ALL_PAGES.map((page) => {
129-
let score = results.find((r) => r.href === page.href)?.score || 0;
130-
const label = page.label.toLowerCase();
131-
const words = label.split(/\s+/);
132-
let hasMeaningfulMatch = false;
133-
134-
// Acronym match (e.g., "dc" matches "DNS Check")
135-
const acronym = words.map((w) => w[0]).join('');
136-
if (acronym === normalizedQuery) {
137-
score += 300;
138-
hasMeaningfulMatch = true;
139-
}
140-
if (acronym.startsWith(normalizedQuery)) {
141-
score += 150;
142-
hasMeaningfulMatch = true;
143-
}
59+
const results = searchPages(q, ALL_PAGES, bookmarkedHrefs, frequentHrefs, 8);
14460
145-
// Fuzzy string match with Levenshtein distance
146-
tokens.forEach((token) => {
147-
if (token.length < 2) return; // Skip single chars
148-
149-
const distance = levenshtein(token, label);
150-
const similarity = 1 - distance / Math.max(token.length, label.length);
151-
if (similarity > 0.65) {
152-
score += Math.floor(similarity * 100);
153-
hasMeaningfulMatch = true;
154-
}
155-
156-
// Check against individual words
157-
words.forEach((word) => {
158-
if (word.length < 2) return;
159-
const wordDist = levenshtein(token, word);
160-
const wordSim = 1 - wordDist / Math.max(token.length, word.length);
161-
if (wordSim > 0.7) {
162-
score += Math.floor(wordSim * 80);
163-
hasMeaningfulMatch = true;
164-
}
165-
});
166-
167-
// Check keywords with fuzzy match
168-
page.keywords?.forEach((keyword) => {
169-
const kwDist = levenshtein(token, keyword.toLowerCase());
170-
const kwSim = 1 - kwDist / Math.max(token.length, keyword.length);
171-
if (kwSim > 0.75) {
172-
score += Math.floor(kwSim * 60);
173-
hasMeaningfulMatch = true;
174-
}
175-
});
176-
});
177-
178-
// Partial word boundary match (only if token is significant portion of word)
179-
tokens.forEach((token) => {
180-
if (token.length >= 3) {
181-
words.forEach((word) => {
182-
if (word.includes(token) && token.length / word.length > 0.6) {
183-
score += 40;
184-
hasMeaningfulMatch = true;
185-
}
186-
});
187-
}
188-
});
189-
190-
// Boost for bookmarked/frequent (but don't count as meaningful match)
191-
if (bookmarkedHrefs.has(page.href)) score += 15;
192-
if (frequentHrefs.has(page.href)) score += 10;
193-
194-
return { ...page, score, hasMeaningfulMatch };
195-
})
196-
.filter((page) => page.score > 100 && page.hasMeaningfulMatch) // Must have meaningful match
197-
.sort((a, b) => b.score - a.score);
198-
199-
return fuzzyResults.slice(0, 8);
200-
}
201-
202-
return results.slice(0, 8);
61+
// If no results, show suggestions
62+
return results.length > 0 ? results : getSuggested().slice(0, 8);
20363
}
20464
20565
// Using a separate internal function to avoid reactivity warnings

src/lib/components/page-specific/about/AuthorSection.svelte

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,43 @@
1111
{
1212
name: 'domain-locker',
1313
title: 'Domain Locker',
14-
icon: 'https://storage.googleapis.com/as93-screenshots/project-logos/domain-locker.png',
14+
icon: 'https://cdn.as93.net/logo/domain-locker/w128',
1515
description: 'Domain name portfolio app for monitoring your domains',
1616
color: '#9571ff',
1717
},
1818
{
1919
name: 'web-check',
2020
title: 'Web Check',
2121
description: 'The ultimate all-in-one OSINT tool for analyzing any website',
22-
icon: 'https://raw.githubusercontent.com/Lissy93/web-check/master/public/android-chrome-192x192.png',
22+
icon: 'https://cdn.as93.net/logo/web-check/w128',
2323
color: '#9fef00',
2424
},
2525
{
2626
name: 'permissionator',
2727
title: 'Permissionator',
2828
description: 'A Linux chmod calculator, for generating safe file permissions',
29-
icon: 'https://github.com/Lissy93/permissionator/blob/main/public/logo.png?raw=true',
29+
icon: 'https://cdn.as93.net/logo/permissionator/w128',
3030
color: '#05df72',
3131
},
3232
{
3333
name: 'personal-security-checklist',
3434
title: 'Digital Defense',
3535
description: 'The ultimate security checklist, for protecting your data online',
36-
icon: 'https://storage.googleapis.com/as93-screenshots/project-logos/digital-defense.png',
36+
icon: 'https://pixelflare.cc/alicia/logo/digital-defense/w128',
3737
color: '#a78bfa',
3838
},
3939
{
4040
name: 'awesome-privacy',
4141
title: 'Awesome Privacy',
42-
icon: 'https://storage.googleapis.com/as93-screenshots/project-logos/awesome-privacy.png',
42+
icon: 'https://pixelflare.cc/alicia/logo/awesome-privacy/w128',
4343
description: 'A curated list of services which respects your privacy',
4444
color: '#fc60a8',
4545
},
4646
{
4747
name: 'dashy',
4848
title: 'Dashy',
4949
description: 'A self-hostable personal server dashboard',
50-
icon: 'https://i.ibb.co/yhbt6CY/dashy.png',
50+
icon: 'https://cdn.as93.net/logo/dashy/w128',
5151
color: '#00efe3',
5252
},
5353
];

src/lib/constants/site.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const author = {
3737
url: 'https://aliciasykes.com',
3838
portfolio: 'https://as93.net',
3939
sponsor: 'https://github.com/sponsors/lissy93',
40-
avatar: 'https://i.ibb.co/Q7XTgybB/DSC-0444-2.jpg',
40+
avatar: 'https://pixelflare.cc/alicia/profile-pictures/dsc_04442',
4141
};
4242

4343
export default { site, license, author };

0 commit comments

Comments
 (0)