setSearch(v)} />
onChange(e.target.value)}
+ {...inputProps}
+ />
+ );
+}
diff --git a/website/src/repl/components/usedebounce.jsx b/website/src/repl/components/usedebounce.jsx
new file mode 100644
index 00000000..a0fb1ea7
--- /dev/null
+++ b/website/src/repl/components/usedebounce.jsx
@@ -0,0 +1,30 @@
+import { useMemo } from 'react';
+import { useEffect } from 'react';
+import { useRef } from 'react';
+
+function debounce(fn, wait) {
+ let timer;
+ return function (...args) {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ timer = setTimeout(() => fn(...args), wait);
+ };
+}
+
+export function useDebounce(callback) {
+ const ref = useRef;
+ useEffect(() => {
+ ref.current = callback;
+ }, [callback]);
+
+ const debouncedCallback = useMemo(() => {
+ const func = () => {
+ ref.current?.();
+ };
+
+ return debounce(func, 1000);
+ }, []);
+
+ return debouncedCallback;
+}
diff --git a/website/src/repl/useExamplePatterns.jsx b/website/src/repl/useExamplePatterns.jsx
index 08629d44..5c4277bb 100644
--- a/website/src/repl/useExamplePatterns.jsx
+++ b/website/src/repl/useExamplePatterns.jsx
@@ -1,4 +1,4 @@
-import { $featuredPatterns, $publicPatterns, collectionName } from '../user_pattern_utils.mjs';
+import { $featuredPatterns, $publicPatterns, patternFilterName } from '../user_pattern_utils.mjs';
import { useStore } from '@nanostores/react';
import { useMemo } from 'react';
import * as tunes from '../repl/tunes.mjs';
@@ -12,9 +12,9 @@ export const useExamplePatterns = () => {
const publicPatterns = useStore($publicPatterns);
const collections = useMemo(() => {
const pats = new Map();
- pats.set(collectionName.featured, featuredPatterns);
- pats.set(collectionName.public, publicPatterns);
- // pats.set(collectionName.stock, stockPatterns);
+ pats.set(patternFilterName.featured, featuredPatterns);
+ pats.set(patternFilterName.public, publicPatterns);
+ // pats.set(patternFilterName.stock, stockPatterns);
return pats;
}, [featuredPatterns, publicPatterns]);
diff --git a/website/src/user_pattern_utils.mjs b/website/src/user_pattern_utils.mjs
index 866491d0..5622d563 100644
--- a/website/src/user_pattern_utils.mjs
+++ b/website/src/user_pattern_utils.mjs
@@ -8,16 +8,12 @@ import { confirmDialog, parseJSON, supabase } from './repl/util.mjs';
export let $publicPatterns = atom([]);
export let $featuredPatterns = atom([]);
-export const collectionName = {
- user: 'user',
- public: 'Last Creations',
- stock: 'Stock Examples',
- featured: 'Featured',
-};
-
+const patternQueryLimit = 20;
export const patternFilterName = {
- community: 'community',
+ public: 'latest',
+ featured: 'featured',
user: 'user',
+ // stock: 'stock examples',
};
const sessionAtom = (name, initial = undefined) => {
@@ -36,7 +32,7 @@ const sessionAtom = (name, initial = undefined) => {
export let $viewingPatternData = sessionAtom('viewingPatternData', {
id: '',
code: '',
- collection: collectionName.user,
+ collection: patternFilterName.user,
created_at: Date.now(),
});
@@ -51,25 +47,50 @@ export const setViewingPatternData = (data) => {
$viewingPatternData.set(JSON.stringify(data));
};
-export function loadPublicPatterns() {
- return supabase.from('code_v1').select().eq('public', true).limit(20).order('id', { ascending: false });
+function parsePageNum(page) {
+ return isNaN(page) ? 0 : page;
+}
+export function loadPublicPatterns(page) {
+ page = parsePageNum(page);
+ const offset = page * patternQueryLimit;
+ return supabase
+ .from('code_v1')
+ .select()
+ .eq('public', true)
+ .range(offset, offset + patternQueryLimit)
+ .order('id', { ascending: false });
}
-export function loadFeaturedPatterns() {
- return supabase.from('code_v1').select().eq('featured', true).limit(20).order('id', { ascending: false });
+export function loadFeaturedPatterns(page = 0) {
+ page = parsePageNum(page);
+ const offset = page * patternQueryLimit;
+ return supabase
+ .from('code_v1')
+ .select()
+ .eq('featured', true)
+ .range(offset, offset + patternQueryLimit)
+ .order('id', { ascending: false });
+}
+
+export async function loadAndSetPublicPatterns(page) {
+ const p = await loadPublicPatterns(page);
+ const data = p?.data;
+ const pats = {};
+ data?.forEach((data, key) => (pats[data.id ?? key] = data));
+ $publicPatterns.set(pats);
+}
+export async function loadAndSetFeaturedPatterns(page) {
+ const p = await loadFeaturedPatterns(page);
+ const data = p?.data;
+ const pats = {};
+ data?.forEach((data, key) => (pats[data.id ?? key] = data));
+ $featuredPatterns.set(pats);
}
export async function loadDBPatterns() {
try {
- const { data: publicPatterns } = await loadPublicPatterns();
- const { data: featuredPatterns } = await loadFeaturedPatterns();
- const featured = {};
- const pub = {};
-
- publicPatterns?.forEach((data, key) => (pub[data.id ?? key] = data));
- featuredPatterns?.forEach((data, key) => (featured[data.id ?? key] = data));
- $publicPatterns.set(pub);
- $featuredPatterns.set(featured);
+ await loadAndSetPublicPatterns();
+ await loadAndSetFeaturedPatterns();
} catch (err) {
console.error('error loading patterns', err);
}
@@ -92,7 +113,7 @@ export const setLatestCode = (code) => settingsMap.setKey('latestCode', code);
const defaultCode = '';
export const userPattern = {
- collection: collectionName.user,
+ collection: patternFilterName.user,
getAll() {
const patterns = parseJSON(settingsMap.get().userPatterns);
return patterns ?? {};