Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

public sharing #910

Merged
merged 4 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
120 changes: 120 additions & 0 deletions website/database.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// generated with https://supabase.com/docs/reference/javascript/typescript-support#generating-typescript-types
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];

export interface Database {
public: {
Tables: {
code: {
Row: {
code: string | null;
created_at: string | null;
featured: boolean | null;
hash: string | null;
id: number;
public: boolean | null;
};
Insert: {
code?: string | null;
created_at?: string | null;
featured?: boolean | null;
hash?: string | null;
id?: number;
public?: boolean | null;
};
Update: {
code?: string | null;
created_at?: string | null;
featured?: boolean | null;
hash?: string | null;
id?: number;
public?: boolean | null;
};
Relationships: [];
};
};
Views: {
[_ in never]: never;
};
Functions: {
[_ in never]: never;
};
Enums: {
[_ in never]: never;
};
CompositeTypes: {
[_ in never]: never;
};
};
}

export type Tables<
PublicTableNameOrOptions extends
| keyof (Database['public']['Tables'] & Database['public']['Views'])
| { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] &
Database[PublicTableNameOrOptions['schema']]['Views'])
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? (Database[PublicTableNameOrOptions['schema']]['Tables'] &
Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends {
Row: infer R;
}
? R
: never
: PublicTableNameOrOptions extends keyof (Database['public']['Tables'] & Database['public']['Views'])
? (Database['public']['Tables'] & Database['public']['Views'])[PublicTableNameOrOptions] extends {
Row: infer R;
}
? R
: never
: never;

export type TablesInsert<
PublicTableNameOrOptions extends keyof Database['public']['Tables'] | { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions['schema']]['Tables']
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends {
Insert: infer I;
}
? I
: never
: PublicTableNameOrOptions extends keyof Database['public']['Tables']
? Database['public']['Tables'][PublicTableNameOrOptions] extends {
Insert: infer I;
}
? I
: never
: never;

export type TablesUpdate<
PublicTableNameOrOptions extends keyof Database['public']['Tables'] | { schema: keyof Database },
TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicTableNameOrOptions['schema']]['Tables']
: never = never,
> = PublicTableNameOrOptions extends { schema: keyof Database }
? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends {
Update: infer U;
}
? U
: never
: PublicTableNameOrOptions extends keyof Database['public']['Tables']
? Database['public']['Tables'][PublicTableNameOrOptions] extends {
Update: infer U;
}
? U
: never
: never;

export type Enums<
PublicEnumNameOrOptions extends keyof Database['public']['Enums'] | { schema: keyof Database },
EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
? keyof Database[PublicEnumNameOrOptions['schema']]['Enums']
: never = never,
> = PublicEnumNameOrOptions extends { schema: keyof Database }
? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName]
: PublicEnumNameOrOptions extends keyof Database['public']['Enums']
? Database['public']['Enums'][PublicEnumNameOrOptions]
: never;
61 changes: 60 additions & 1 deletion website/src/repl/panel/PatternsTab.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DocumentDuplicateIcon, PencilSquareIcon, TrashIcon } from '@heroicons/react/20/solid';
import { useMemo } from 'react';
import {
$featuredPatterns,
$publicPatterns,
clearUserPatterns,
deleteActivePattern,
duplicateActivePattern,
Expand All @@ -14,6 +16,8 @@ import {
useSettings,
} from '../../settings.mjs';
import * as tunes from '../tunes.mjs';
import { useStore } from '@nanostores/react';
import { getMetadata } from '../../metadata_parser';

function classNames(...classes) {
return classes.filter(Boolean).join(' ');
Expand All @@ -22,6 +26,8 @@ function classNames(...classes) {
export function PatternsTab({ context }) {
const { userPatterns } = useSettings();
const activePattern = useActivePattern();
const featuredPatterns = useStore($featuredPatterns);
const publicPatterns = useStore($publicPatterns);
const isExample = useMemo(() => activePattern && !!tunes[activePattern], [activePattern]);
return (
<div className="px-4 w-full dark:text-white text-stone-900 space-y-4 pb-4">
Expand Down Expand Up @@ -94,8 +100,52 @@ export function PatternsTab({ context }) {
</button>
</div>
</section>
{featuredPatterns && (
<section>
<h2 className="text-xl mb-2">Featured Patterns</h2>
<div className="font-mono text-sm">
{featuredPatterns.map((pattern) => (
<a
key={pattern.id}
className={classNames(
'mr-4 hover:opacity-50 cursor-pointer block',
pattern.hash === activePattern ? 'outline outline-1' : '',
)}
onClick={() => {
setActivePattern(pattern.hash);
context.handleUpdate(pattern.code, true);
}}
>
<PatternLabel pattern={pattern} />
</a>
))}
</div>
</section>
)}
{publicPatterns && (
<section>
<h2 className="text-xl mb-2">Last Creations</h2>
<div className="font-mono text-sm">
{publicPatterns.map((pattern) => (
<a
key={'public-' + pattern.id}
className={classNames(
'mr-4 hover:opacity-50 cursor-pointer block', // inline-block
pattern.hash === activePattern ? 'outline outline-1' : '',
)}
onClick={() => {
setActivePattern(pattern.hash);
context.handleUpdate(pattern.code, true);
}}
>
<PatternLabel pattern={pattern} />
</a>
))}
</div>
</section>
)}
<section>
<h2 className="text-xl mb-2">Examples</h2>
<h2 className="text-xl mb-2">Stock Examples</h2>
<div className="font-mono text-sm">
{Object.entries(tunes).map(([key, tune]) => (
<a
Expand All @@ -117,3 +167,12 @@ export function PatternsTab({ context }) {
</div>
);
}

export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) {
const meta = useMemo(() => getMetadata(pattern.code), [pattern]);
return (
<>
{pattern.id}. {meta.title || pattern.hash} by {meta.by.join(',') || 'Anonymous'}
</>
);
}
15 changes: 13 additions & 2 deletions website/src/repl/util.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { writeText } from '@tauri-apps/api/clipboard';
import { createContext } from 'react';

// Create a single supabase client for interacting with your database
const supabase = createClient(
export const supabase = createClient(
'https://pidxdsxphlhzjnzmifth.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
);
Expand Down Expand Up @@ -90,10 +90,13 @@ export async function shareCode(codeToShare) {
logger(`Link already generated!`, 'error');
return;
}
const isPublic = confirm(
'Do you want your pattern to be public? If no, press cancel and you will get just a private link.',
);
// generate uuid in the browser
const hash = nanoid(12);
const shareUrl = window.location.origin + window.location.pathname + '?' + hash;
const { data, error } = await supabase.from('code').insert([{ code: codeToShare, hash }]);
const { error } = await supabase.from('code').insert([{ code: codeToShare, hash, ['public']: isPublic }]);
if (!error) {
lastShared = codeToShare;
// copy shareUrl to clipboard
Expand Down Expand Up @@ -147,3 +150,11 @@ export const setAudioDevice = async (id) => {
}
initializeAudioOutput();
};

export function loadPublicPatterns() {
return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false });
}

export function loadFeaturedPatterns() {
return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false });
}
31 changes: 29 additions & 2 deletions website/src/settings.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import { atom } from 'nanostores';
import { persistentMap, persistentAtom } from '@nanostores/persistent';
import { useStore } from '@nanostores/react';
import { register } from '@strudel.cycles/core';
import * as tunes from './repl/tunes.mjs';
import { logger } from '@strudel.cycles/core';
import { loadPublicPatterns, loadFeaturedPatterns } from './repl/util.mjs';

export let $publicPatterns = atom([]);
export let $featuredPatterns = atom([]);

async function loadDBPatterns() {
const { data: publicPatterns } = await loadPublicPatterns();
$publicPatterns.set(publicPatterns);
const { data: featuredPatterns } = await loadFeaturedPatterns();
$featuredPatterns.set(featuredPatterns);
}

loadDBPatterns();

export const defaultAudioDeviceName = 'System Standard';

Expand Down Expand Up @@ -172,12 +186,25 @@ export function updateUserCode(code) {
setActivePattern(example);
return;
}

const publicPattern = $publicPatterns.get().find((pat) => pat.code === code);
if (publicPattern) {
setActivePattern(publicPattern.hash);
return;
}
const featuredPattern = $featuredPatterns.get().find((pat) => pat.code === code);
if (featuredPattern) {
setActivePattern(featuredPattern.hash);
return;
}
if (!activePattern) {
// create new user pattern
activePattern = newUserPattern();
setActivePattern(activePattern);
} else if (!!tunes[activePattern] && code !== tunes[activePattern]) {
} else if (
(!!tunes[activePattern] && code !== tunes[activePattern]) || // fork example tune?
$publicPatterns.get().find((p) => p.hash === activePattern) || // fork public pattern?
$featuredPatterns.get().find((p) => p.hash === activePattern) // fork featured pattern?
) {
// fork example
activePattern = getNextCloneName(activePattern);
setActivePattern(activePattern);
Expand Down