Skip to content

Commit

Permalink
wip: CRUD for system templates
Browse files Browse the repository at this point in the history
it lists templates, can create new and update it
  • Loading branch information
fmaclen committed Jun 28, 2024
1 parent 7f09662 commit 84e7f84
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 66 deletions.
2 changes: 2 additions & 0 deletions src/lib/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { browser } from '$app/environment';
import { writable } from 'svelte/store';
import type { Session } from '$lib/sessions';
import type { OllamaModel } from './ollama';
import type { SystemTemplate } from './systemTemplates';

function createLocalStorageStore<T>(key: string, initialValue: T | null = null) {
const localStorageValue: string | null = browser ? window.localStorage.getItem(key) : null;
Expand Down Expand Up @@ -34,3 +35,4 @@ export interface Settings {

export const settingsStore = createLocalStorageStore<Settings>(`${LOCAL_STORAGE_PREFIX}-settings`);
export const sessionsStore = createLocalStorageStore<Session[]>(`${LOCAL_STORAGE_PREFIX}-sessions`);
export const systemTemplatesStore = createLocalStorageStore<SystemTemplate[]>(`${LOCAL_STORAGE_PREFIX}-system-templates`);
51 changes: 51 additions & 0 deletions src/lib/systemTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { get } from "svelte/store";
import { settingsStore, systemTemplatesStore } from "$lib/store";

export interface SystemTemplate {
id: string;
name: string;
content: string[];
updated_at: string;
}

export const loadSystemTemplate = (id: string): SystemTemplate => {
let systemTemplate: SystemTemplate | null = null;

// Retrieve the current sessions
const currentSystemTemplates = get(systemTemplatesStore);

// Find the session with the given id
if (currentSystemTemplates) {
const existingSystemTemplate = currentSystemTemplates.find(s => s.id === id);
existingSystemTemplate && (systemTemplate = existingSystemTemplate);
}

if (!systemTemplate) {
// Get the current model
const model = get(settingsStore)?.ollamaModel || "";

// Create a new session
systemTemplate = { id, name: "", content: [], updated_at: new Date().toISOString() };
}

return systemTemplate;
};

export const saveSystemTemplate = (systemTemplate: SystemTemplate): void => {
// Retrieve the current sessions
const currentSystemTemplates = get(systemTemplatesStore) || [];

// Find the index of the session with the same id, if it exists
const existingSystemTemplate = currentSystemTemplates.findIndex(s => s.id === systemTemplate.id);

if (existingSystemTemplate !== -1) {
// Update the existing session
currentSystemTemplates[existingSystemTemplate] = systemTemplate;
} else {
// Add the new session if it doesn't exist
currentSystemTemplates.push(systemTemplate);
}

// Update the store, which will trigger the localStorage update
systemTemplatesStore.set(currentSystemTemplates);
};
65 changes: 5 additions & 60 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,7 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { cubicOut } from "svelte/easing";
import type { TransitionConfig } from "svelte/transition";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
export function generateStorageId() {
return Math.random().toString(36).substring(2, 8); // E.g. `z7avx9`
}

type FlyAndScaleParams = {
y?: number;
x?: number;
start?: number;
duration?: number;
};

export const flyAndScale = (
node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;

const scaleConversion = (
valueA: number,
scaleA: [number, number],
scaleB: [number, number]
) => {
const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB;

const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;

return valueB;
};

const styleToString = (
style: Record<string, number | string | undefined>
): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, "");
};

return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);

return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};
export function getUpdatedAtDate() {
return new Date().toISOString();
}
16 changes: 10 additions & 6 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
import Separator from '$lib/components/Separator.svelte';
import { sessionsStore } from '$lib/store';
import { generateStorageId } from '$lib/utils';
let newSessionId: string;
function createNewSession() {
newSessionId = Math.random().toString(36).substring(2, 8); // E.g. `z7avx9`
function setSessionId() {
newSessionId = generateStorageId();
}
onMount(createNewSession);
onMount(setSessionId);
</script>

<svelte:head>
Expand All @@ -33,7 +34,7 @@
</svelte:head>

<div
class="grid h-screen w-screen grid-cols-[max-content,max-content,280px,max-content,1fr] text-current bg-body"
class="grid h-screen w-screen grid-cols-[max-content,max-content,280px,max-content,1fr] bg-body text-current"
>
<a href="/" class="flex flex-col items-center justify-between py-6 hover:bg-accent">
<img src="/favicon.png" alt="Hollama logo" width="48" height="48" />
Expand All @@ -52,7 +53,7 @@
class="w-full"
variant="outline"
href={`/${newSessionId}`}
on:click={createNewSession}
on:click={setSessionId}
>
New session
</Button>
Expand Down Expand Up @@ -88,7 +89,10 @@
</a>
{/each}
{:else}
<p transition:slide class="flex h-full w-full items-center justify-center text-sm text-muted-foreground">
<p
transition:slide
class="flex h-full w-full items-center justify-center text-sm text-muted-foreground"
>
No sessions in history
</p>
{/if}
Expand Down
41 changes: 41 additions & 0 deletions src/routes/templates/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script lang="ts">
import { onMount } from 'svelte';
import { systemTemplatesStore } from '$lib/store';
import { generateStorageId } from '$lib/utils';
import Button from '$lib/components/Button.svelte';
function deleteTemplate(id: string) {
const confirmed = confirm('Are you sure you want to delete this template?');
if (!confirmed) return;
if ($systemTemplatesStore) {
$systemTemplatesStore = $systemTemplatesStore.filter((s) => s.id !== id);
}
}
let newSessionId: string;
function setSessionId() {
newSessionId = generateStorageId();
}
onMount(setSessionId);
</script>

<div class="container">
<h1>System Templates</h1>

{#if $systemTemplatesStore}
<ul>
{#each $systemTemplatesStore as template}
<li>
<Button href="/templates/{template.id}">{template.name}</Button> — updated on: {template.updated_at}
<Button variant="secondary" on:click={() => deleteTemplate(template.id)}>Delete</Button>
</li>
{/each}
</ul>
{/if}

<a href={`templates/${newSessionId}`} on:click={setSessionId}>Create New Template</a>
</div>
33 changes: 33 additions & 0 deletions src/routes/templates/[id]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script lang="ts">
import type { PageData } from '../$types';
import { loadSystemTemplate, saveSystemTemplate } from '$lib/systemTemplates';
import Button from '$lib/components/Button.svelte';
import { getUpdatedAtDate } from '$lib/utils';
export let data: PageData;
let systemTemplate = loadSystemTemplate(data.id);
let { name, content, updated_at } = systemTemplate;
function handleSubmit() {
saveSystemTemplate({ id: systemTemplate.id, name, content, updated_at: getUpdatedAtDate() });
}
</script>

{#if systemTemplate}
<div class="container">
<ul>
<li><a href="/templates">/templates</a></li>
<li>id: {systemTemplate.id}</li>
<li>created_at: {systemTemplate.updated_at}</li>
<li>name: <input class="border border-neutral-500" bind:value={name} /></li>
<li>
content:
<textarea class="border border-neutral-500" bind:value={content}></textarea>
</li>
</ul>

<Button class="w-full" on:click={handleSubmit} disabled={!name && !content}>Save</Button>
</div>
{/if}
5 changes: 5 additions & 0 deletions src/routes/templates/[id]/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { PageLoad } from './$types';

export const load = (async ({ params }) => {
return { id: params.id };
}) satisfies PageLoad;

0 comments on commit 84e7f84

Please sign in to comment.