mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 14:39:30 -07:00
FEAT: OCTOBER UPDATE
This commit is contained in:
66
src/utils/favorites.ts
Normal file
66
src/utils/favorites.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
const STORAGE_KEY = 'savedComponents';
|
||||
|
||||
const read = (): string[] => {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
const parsed = raw ? JSON.parse(raw) : [];
|
||||
return Array.isArray(parsed) ? parsed.filter(x => typeof x === 'string') : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const write = (list: string[]) => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
|
||||
|
||||
try {
|
||||
window.dispatchEvent(new CustomEvent('favorites:updated', { detail: list }));
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
export const getSavedComponents = () => read();
|
||||
|
||||
export const isComponentSaved = (key: string) => read().includes(key);
|
||||
|
||||
export const addSavedComponent = (key: string) => {
|
||||
const list = read();
|
||||
if (!list.includes(key)) {
|
||||
const next = [...list, key];
|
||||
write(next);
|
||||
return next;
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
export const removeSavedComponent = (key: string) => {
|
||||
const list = read();
|
||||
const next = list.filter(item => item !== key);
|
||||
write(next);
|
||||
return next;
|
||||
};
|
||||
|
||||
export const toggleSavedComponent = (key: string) => {
|
||||
const list = read();
|
||||
if (list.includes(key)) {
|
||||
const next = list.filter(item => item !== key);
|
||||
write(next);
|
||||
return { saved: false, list: next };
|
||||
}
|
||||
const next = [...list, key];
|
||||
write(next);
|
||||
return { saved: true, list: next };
|
||||
};
|
||||
|
||||
export default {
|
||||
getSavedComponents,
|
||||
isComponentSaved,
|
||||
addSavedComponent,
|
||||
removeSavedComponent,
|
||||
toggleSavedComponent
|
||||
};
|
||||
30
src/utils/fuzzy.ts
Normal file
30
src/utils/fuzzy.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export const levenshtein = (a: string, b: string): number => {
|
||||
const m = a.length,
|
||||
n = b.length;
|
||||
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
||||
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
||||
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
||||
for (let i = 1; i <= m; i++) {
|
||||
for (let j = 1; j <= n; j++) {
|
||||
dp[i][j] =
|
||||
a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : Math.min(dp[i - 1][j - 1] + 1, dp[i][j - 1] + 1, dp[i - 1][j] + 1);
|
||||
}
|
||||
}
|
||||
return dp[m][n];
|
||||
};
|
||||
|
||||
export const fuzzyMatch = (candidate?: string, query?: string): boolean => {
|
||||
const lowerCandidate = (candidate || '').toLowerCase();
|
||||
const lowerQuery = (query || '').toLowerCase();
|
||||
if (!lowerQuery) return true;
|
||||
if (lowerCandidate.includes(lowerQuery)) return true;
|
||||
const candidateWords = lowerCandidate.split(/\s+/).filter(Boolean);
|
||||
const queryWords = lowerQuery.split(/\s+/).filter(Boolean);
|
||||
return queryWords.every(qw =>
|
||||
candidateWords.some(cw => {
|
||||
const distance = levenshtein(cw, qw);
|
||||
const threshold = Math.max(1, Math.floor(qw.length / 3));
|
||||
return distance <= threshold;
|
||||
})
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user