mirror of
https://github.com/doolijb/serene-pub.git
synced 2026-07-09 15:58:23 +00:00
UI touchups
This commit is contained in:
parent
368c11d846
commit
372e478636
4 changed files with 215 additions and 13 deletions
134
src/lib/client/components/modals/OllamaInstallModal.svelte
Normal file
134
src/lib/client/components/modals/OllamaInstallModal.svelte
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<script lang="ts">
|
||||
import * as Icons from "@lucide/svelte"
|
||||
import { Modal } from "@skeletonlabs/skeleton-svelte"
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
modelName: string
|
||||
onclose: () => void
|
||||
onconfirm: (modelName: string) => void
|
||||
}
|
||||
|
||||
let { open = $bindable(), modelName, onclose, onconfirm }: Props = $props()
|
||||
|
||||
let inputValue = $state(modelName)
|
||||
let isLoading = $state(false)
|
||||
|
||||
// Function to clean the model name
|
||||
function cleanModelName(input: string): string {
|
||||
let cleaned = input.trim()
|
||||
|
||||
// Remove "ollama pull " prefix if present
|
||||
if (cleaned.toLowerCase().startsWith("ollama pull ")) {
|
||||
cleaned = cleaned.substring(12).trim()
|
||||
}
|
||||
|
||||
// Remove "ollama run " prefix if present
|
||||
if (cleaned.toLowerCase().startsWith("ollama run ")) {
|
||||
cleaned = cleaned.substring(11).trim()
|
||||
}
|
||||
|
||||
return cleaned
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
const cleanedName = cleanModelName(inputValue)
|
||||
if (cleanedName) {
|
||||
isLoading = true
|
||||
onconfirm(cleanedName)
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Enter") {
|
||||
handleConfirm()
|
||||
}
|
||||
}
|
||||
|
||||
// Reset input when modal opens
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
inputValue = modelName
|
||||
isLoading = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
{open}
|
||||
onOpenChange={(e) => {
|
||||
if (!e.open) {
|
||||
onclose()
|
||||
}
|
||||
}}
|
||||
contentBase="card bg-surface-100-900 p-4 space-y-4 shadow-xl w-[30em] max-w-dvw-lg border border-surface-300-700"
|
||||
backdropClasses="backdrop-blur-sm"
|
||||
>
|
||||
{#snippet content()}
|
||||
<div class="mb-6">
|
||||
<div class="mb-2 flex items-center gap-3">
|
||||
<div class="bg-primary-500/10 rounded-full p-2">
|
||||
<Icons.Download size={20} class="text-primary-500" />
|
||||
</div>
|
||||
<h3 class="text-foreground text-lg font-bold">Install Model</h3>
|
||||
</div>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Enter the model name to download. You can use formats like "ollama pull model", "ollama run model", or just "model".
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 space-y-3">
|
||||
<div>
|
||||
<label
|
||||
class="text-foreground mb-1 block text-sm font-medium"
|
||||
for="modelNameInput"
|
||||
>
|
||||
Model Name
|
||||
</label>
|
||||
<input
|
||||
id="modelNameInput"
|
||||
type="text"
|
||||
bind:value={inputValue}
|
||||
onkeydown={handleKeydown}
|
||||
placeholder="e.g., llama2, ollama pull llama2, ollama run llama2"
|
||||
class="input w-full"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if inputValue.trim()}
|
||||
<div class="bg-surface-100-900 rounded border p-3">
|
||||
<div class="text-muted-foreground text-xs font-medium mb-1">
|
||||
Will install:
|
||||
</div>
|
||||
<div class="text-foreground font-mono text-sm">
|
||||
{cleanModelName(inputValue)}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
class="btn btn-secondary flex-1"
|
||||
onclick={onclose}
|
||||
disabled={isLoading}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary flex-1"
|
||||
onclick={handleConfirm}
|
||||
disabled={isLoading || !inputValue.trim()}
|
||||
>
|
||||
{#if isLoading}
|
||||
<Icons.Loader2 size={14} class="animate-spin" />
|
||||
Installing...
|
||||
{:else}
|
||||
<Icons.Download size={14} />
|
||||
Install
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
import { toaster } from "$lib/client/utils/toaster"
|
||||
import * as skio from "sveltekit-io"
|
||||
import { onMount, onDestroy, getContext } from "svelte"
|
||||
import OllamaIcon from "../icons/OllamaIcon.svelte"
|
||||
|
||||
interface OllamaModel {
|
||||
name: string
|
||||
|
|
@ -21,10 +22,8 @@
|
|||
let currentVersion = $state("")
|
||||
let updateAvailable = $state(false)
|
||||
let latestVersion = $state("")
|
||||
let isConnected = $state(true)
|
||||
let isCheckingUpdates = $state(false)
|
||||
let isSavingBaseUrl = $state(false)
|
||||
let installedModels: OllamaModel[] = $state([])
|
||||
let showDeleteModal = $state(false)
|
||||
let modelToDelete: OllamaModel | null = $state(null)
|
||||
let baseUrlField = $state("")
|
||||
|
|
@ -158,6 +157,32 @@
|
|||
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Version Information -->
|
||||
<div class="text-center mt-8">
|
||||
<OllamaIcon class="text-muted-foreground mx-auto mb-4 h-16 w-16" />
|
||||
<span class="h5">Ollama</span>
|
||||
<!-- Links to documentation and GitHub -->
|
||||
<div class="flex items-center justify-center gap-4 mb-6">
|
||||
<a
|
||||
href="https://ollama.ai/docs"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-muted-foreground hover:text-primary-500 transition-colors text-xs flex items-center gap-1"
|
||||
>
|
||||
<Icons.BookOpen class="h-3 w-3" />
|
||||
Documentation
|
||||
</a>
|
||||
<div class="text-muted-foreground">•</div>
|
||||
<a
|
||||
href="https://github.com/ollama/ollama"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-muted-foreground hover:text-primary-500 transition-colors text-xs flex items-center gap-1"
|
||||
>
|
||||
<Icons.Github class="h-3 w-3" />
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-surface-100-800 flex flex-col gap-4 p-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium" for="baseUrl">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import OllamaDownloadsTab from "../ollamaManager/OllamaDownloadsTab.svelte"
|
||||
import * as skio from "sveltekit-io"
|
||||
import { toaster } from "$lib/client/utils/toaster"
|
||||
import OllamaIcon from "../icons/OllamaIcon.svelte"
|
||||
|
||||
interface Props {
|
||||
onclose?: () => Promise<boolean> | undefined
|
||||
|
|
@ -128,54 +129,78 @@
|
|||
</div>
|
||||
{:else if !isConnected}
|
||||
<!-- Connection setup -->
|
||||
<div class="flex flex-1 items-center justify-center p-4">
|
||||
<div class="w-full max-w-md space-y-4">
|
||||
<div class="flex items-center justify-center p-4 mt-10">
|
||||
<div class="w-full max-w-md space-y-6">
|
||||
<div class="text-center">
|
||||
<Icons.Server
|
||||
class="text-muted-foreground mx-auto mb-4 h-12 w-12"
|
||||
/>
|
||||
<OllamaIcon class="text-muted-foreground mx-auto mb-4 h-12 w-12" />
|
||||
<h3 class="text-foreground mb-2 text-lg font-semibold">
|
||||
Connect to Ollama
|
||||
</h3>
|
||||
<p class="text-muted-foreground mb-4 text-sm">
|
||||
Enter your Ollama server URL to get started.
|
||||
Connect to your Ollama server to manage AI models locally.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Don't have Ollama installed? -->
|
||||
<div class="bg-surface-200 dark:bg-surface-800 rounded-lg border p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<Icons.Download class="text-primary-500 mt-0.5 h-5 w-5 flex-shrink-0" />
|
||||
<div class="flex-1">
|
||||
<h4 class="text-foreground mb-1 text-sm font-medium">
|
||||
Don't have Ollama installed?
|
||||
</h4>
|
||||
<p class="text-muted-foreground mb-3 text-xs">
|
||||
Download and install Ollama to run AI models locally on your machine. It's easy!
|
||||
</p>
|
||||
<a
|
||||
href="https://ollama.ai/download"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-sm preset-filled-primary-500 inline-flex items-center gap-2"
|
||||
>
|
||||
<Icons.ExternalLink class="h-4 w-4" />
|
||||
Download Ollama
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Connection form -->
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label
|
||||
class="text-foreground mb-1 block text-sm font-medium"
|
||||
for="ollamaBaseUrl"
|
||||
>
|
||||
Ollama Base URL
|
||||
Ollama Server URL
|
||||
</label>
|
||||
<input
|
||||
id="ollamaBaseUrl"
|
||||
type="text"
|
||||
bind:value={baseUrlField}
|
||||
placeholder="http://localhost:11434/"
|
||||
placeholder="http://localhost:11434"
|
||||
class="input w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
class="btn btn-primary flex-1"
|
||||
class="btn preset-filled-primary-500 flex-1"
|
||||
onclick={handleSaveBaseUrl}
|
||||
disabled={isSavingBaseUrl}
|
||||
>
|
||||
{#if isSavingBaseUrl}
|
||||
<Icons.Loader2 class="h-4 w-4 animate-spin" />
|
||||
Saving...
|
||||
Connecting...
|
||||
{:else}
|
||||
<Icons.Save class="h-4 w-4" />
|
||||
Save & Connect
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
class="btn preset-filled-secondary-500"
|
||||
onclick={checkConnection}
|
||||
title="Test connection to Ollama server"
|
||||
>
|
||||
<Icons.RefreshCw class="h-4 w-4" />
|
||||
Test
|
||||
|
|
|
|||
|
|
@ -133,6 +133,24 @@
|
|||
<Icons.GitBranch size={16} />
|
||||
<span>Repository</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/doolijb/serene-pub/wiki"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn preset-filled-surface-500"
|
||||
>
|
||||
<Icons.BookOpen size={16} />
|
||||
<span>Wiki</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/3kUx3MDcSa"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn preset-filled-tertiary-500"
|
||||
>
|
||||
<Icons.MessageSquare size={16} />
|
||||
<span>Discord</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/doolijb/serene-pub/issues"
|
||||
target="_blank"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue