first working login and editing of file. bugg is för rendering with tiptap

This commit is contained in:
Björn Blomberg
2026-04-10 19:56:21 +02:00
parent 41dc1d9988
commit 05b773c14c
14 changed files with 9459 additions and 24 deletions

View File

@@ -0,0 +1,135 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { gql } from '@/lib/gql'
const props = defineProps<{
modelValue: string
label?: string
placeholder?: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
const open = ref(false)
const currentPath = ref(props.modelValue)
const directories = ref<{ name: string; path: string }[]>([])
const loading = ref(false)
async function fetchDirectories(path: string) {
loading.value = true
try {
const data = await gql<{ serverDirectories: { name: string; path: string }[] }>(
`query Dirs($p: String) { serverDirectories(path: $p) { name path } }`,
{ p: path || null }
)
directories.value = data.serverDirectories
// Update input box to the fetched path if we passed empty and it resolved to root
if (directories.value.length > 0 && path === '') {
// Find parent or use current
const parent = directories.value.find(d => d.name === '..')
if (parent) currentPath.value = parent.path + '/.' // hacky, but fine
}
} catch (err) {
console.error(err)
} finally {
loading.value = false
}
}
function handleOpen() {
open.value = true
currentPath.value = props.modelValue
fetchDirectories(currentPath.value)
}
function selectPath() {
emit('update:modelValue', currentPath.value)
open.value = false
}
function navigate(toPath: string) {
currentPath.value = toPath
fetchDirectories(toPath)
}
// Ensure local currentPath updates when props change externally
watch(() => props.modelValue, (val) => {
currentPath.value = val
})
</script>
<template>
<div class="relative">
<label v-if="label" class="label">{{ label }}</label>
<div class="flex gap-2">
<input
:value="modelValue"
@input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
class="input flex-1"
:placeholder="placeholder"
/>
<button type="button" class="btn-secondary" @click="handleOpen">Browse...</button>
</div>
<!-- Modal Modal -->
<transition name="fade">
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/50 backdrop-blur-sm p-4">
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-xl border border-slate-200 dark:border-slate-700 w-full max-w-lg overflow-hidden flex flex-col max-h-[80vh]">
<!-- Header -->
<div class="p-4 border-b border-slate-200 dark:border-slate-700 flex items-center justify-between">
<h3 class="text-lg font-semibold text-slate-900 dark:text-white">Select Folder</h3>
<button type="button" @click="open = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
</div>
<!-- Body -->
<div class="p-4 bg-slate-50 dark:bg-slate-900/50 flex-1 overflow-auto flex flex-col gap-3">
<input
v-model="currentPath"
@keydown.enter.prevent="fetchDirectories(currentPath)"
class="input font-mono text-sm"
placeholder="Path..."
/>
<div class="flex-1 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg overflow-y-auto min-h-[200px]">
<div v-if="loading" class="p-4 text-center text-slate-400 animate-pulse text-sm">
Loading...
</div>
<ul v-else class="divide-y divide-slate-100 dark:divide-slate-700/50">
<li v-if="directories.length === 0" class="p-3 text-sm text-slate-500 text-center">
No subdirectories
</li>
<li v-for="dir in directories" :key="dir.path">
<button
type="button"
class="w-fulltext-left flex items-center gap-2 px-3 py-2 w-full hover:bg-accent-50 dark:hover:bg-accent-500/10 focus:bg-accent-50 focus:outline-none transition group"
@click="navigate(dir.path)"
>
<svg class="w-4 h-4 text-accent-500 group-hover:text-accent-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"/></svg>
<span class="text-sm font-medium text-slate-700 dark:text-slate-300 truncate">{{ dir.name }}</span>
</button>
</li>
</ul>
</div>
</div>
<!-- Footer -->
<div class="p-4 border-t border-slate-200 dark:border-slate-700 flex justify-end gap-2 bg-white dark:bg-slate-800">
<button type="button" class="btn-ghost" @click="open = false">Cancel</button>
<button type="button" class="btn-primary" @click="selectPath">Select Reference</button>
</div>
</div>
</div>
</transition>
</div>
</template>
<style scoped>
.fade-enter-active, .fade-leave-active { transition: opacity 0.15s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>