feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
31a027c93a
225 files changed
+38042
No files matched your search
@@ -0,0 +1,66 @@
|
||||
import { type FormEvent, useEffect, useRef } from 'react'
|
||||
import { useOverlayDismiss } from '../hooks/useOverlayDismiss'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
defaultValue?: string
|
||||
placeholder?: string
|
||||
confirmLabel?: string
|
||||
onConfirm: (value: string) => void
|
||||
onCancel: () => void
|
||||
}
|
||||
|
||||
export default function InputDialog({ title, defaultValue = '', placeholder, confirmLabel = 'OK', onConfirm, onCancel }: Props) {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const overlay = useOverlayDismiss(onCancel)
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus()
|
||||
inputRef.current?.select()
|
||||
}, [])
|
||||
|
||||
function handleSubmit(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
const val = inputRef.current?.value.trim()
|
||||
if (val) onConfirm(val)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style={{ background: 'rgba(0,0,0,0.6)' }}
|
||||
{...overlay}>
|
||||
<div className="w-full max-w-sm rounded-xl p-5 shadow-2xl border"
|
||||
style={{ background: 'var(--color-surface)', borderColor: 'var(--color-border)' }}>
|
||||
<h2 className="font-semibold mb-4" style={{ color: 'var(--color-text)' }}>{title}</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-3">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
defaultValue={defaultValue}
|
||||
placeholder={placeholder}
|
||||
className="w-full rounded-lg px-3 py-2.5 text-sm outline-none"
|
||||
style={{
|
||||
background: 'var(--color-surface-2)',
|
||||
border: '1px solid var(--color-border)',
|
||||
color: 'var(--color-text)',
|
||||
}}
|
||||
onFocus={e => e.currentTarget.style.borderColor = 'var(--color-primary)'}
|
||||
onBlur={e => e.currentTarget.style.borderColor = 'var(--color-border)'}
|
||||
/>
|
||||
<div className="flex justify-end gap-2">
|
||||
<button type="button" onClick={onCancel}
|
||||
className="px-4 py-2 text-sm rounded-lg transition-opacity hover:opacity-70"
|
||||
style={{ color: 'var(--color-text-muted)' }}>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit"
|
||||
className="px-4 py-2 text-sm rounded-lg font-medium"
|
||||
style={{ background: 'var(--color-primary)', color: 'var(--color-primary-fg)' }}>
|
||||
{confirmLabel}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user