212 lines
5.0 KiB
Svelte
212 lines
5.0 KiB
Svelte
<script>
|
|
import { t } from './i18n'
|
|
|
|
export let onComplete = null
|
|
export let onQuit = null
|
|
|
|
let vaultPath = ''
|
|
let defaultPath = ''
|
|
let loading = false
|
|
let errorMsg = ''
|
|
let pathInfo = ''
|
|
let pathCheck = null
|
|
|
|
function wailsCall(method, ...args) {
|
|
try {
|
|
if (window['go'] && window['go']['main'] && window['go']['main']['App']) {
|
|
const fn = window['go']['main']['App'][method]
|
|
if (typeof fn === 'function') return fn(...args)
|
|
}
|
|
} catch (e) { console.error('Wails error:', method, e) }
|
|
return Promise.reject(new Error('Wails not connected: ' + method))
|
|
}
|
|
|
|
async function init() {
|
|
try {
|
|
const defaultVaultPath = await wailsCall('GetDefaultVaultPath')
|
|
defaultPath = defaultVaultPath || ''
|
|
vaultPath = defaultPath || ''
|
|
if (vaultPath) await checkPath()
|
|
} catch (e) { defaultPath = '' }
|
|
}
|
|
|
|
init()
|
|
|
|
async function browseFolder() {
|
|
try {
|
|
const chosen = await wailsCall('PickDirectory')
|
|
if (chosen) {
|
|
vaultPath = chosen
|
|
await checkPath()
|
|
}
|
|
} catch (e) { errorMsg = String(e) }
|
|
}
|
|
|
|
async function checkPath() {
|
|
if (!vaultPath || !vaultPath.trim()) {
|
|
pathInfo = ''
|
|
pathCheck = null
|
|
return
|
|
}
|
|
try {
|
|
pathCheck = await wailsCall('CheckVaultPath', vaultPath.trim())
|
|
if (pathCheck) {
|
|
pathInfo = pathCheck.description
|
|
}
|
|
} catch (e) { pathInfo = ''; pathCheck = null }
|
|
}
|
|
|
|
async function createWorkspace() {
|
|
if (!vaultPath || !vaultPath.trim()) return
|
|
loading = true
|
|
errorMsg = ''
|
|
|
|
if (pathCheck && !pathCheck.writable) {
|
|
errorMsg = t('firstrun.errorNoWrite')
|
|
loading = false
|
|
return
|
|
}
|
|
|
|
try {
|
|
const status = await wailsCall('CreateVault', vaultPath.trim())
|
|
if (status && status.status === 'ready' && onComplete) {
|
|
onComplete(status)
|
|
}
|
|
} catch (e) {
|
|
errorMsg = String(e)
|
|
}
|
|
loading = false
|
|
}
|
|
|
|
function handleQuit() {
|
|
if (onQuit) onQuit()
|
|
}
|
|
|
|
function handleKeydown(e) {
|
|
if (e.key === 'Enter' && !loading && vaultPath.trim()) createWorkspace()
|
|
}
|
|
</script>
|
|
|
|
<div class="first-run-screen">
|
|
<div class="first-run-card">
|
|
<img class="first-run-logo" src="/assets/app-icons/icon_64x64.png" width="64" height="64" alt="" />
|
|
<h1>{t('firstrun.title')}</h1>
|
|
<p class="first-run-desc">{t('firstrun.desc')}</p>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label" for="vault-path">{t('firstrun.pathLabel')}</label>
|
|
<div class="input-row">
|
|
<input
|
|
id="vault-path"
|
|
type="text"
|
|
bind:value={vaultPath}
|
|
on:input={checkPath}
|
|
on:keydown={handleKeydown}
|
|
placeholder={defaultPath || t('firstrun.defaultPath')}
|
|
disabled={loading}
|
|
/>
|
|
<button class="btn" on:click={browseFolder} disabled={loading}>{t('firstrun.browse')}</button>
|
|
</div>
|
|
</div>
|
|
|
|
{#if pathInfo}
|
|
<div class="path-info">{pathInfo}</div>
|
|
{/if}
|
|
|
|
{#if errorMsg}
|
|
<div class="error-msg">{errorMsg}</div>
|
|
{/if}
|
|
|
|
<div class="first-run-actions">
|
|
<button class="btn btn-primary btn-lg" on:click={createWorkspace}
|
|
disabled={!vaultPath.trim() || loading}>
|
|
{loading ? t('firstrun.creating') : t('firstrun.create')}
|
|
</button>
|
|
<button class="btn btn-lg" on:click={handleQuit}>{t('firstrun.quit')}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.first-run-screen {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 100vh;
|
|
padding: 2rem;
|
|
background: var(--bg, #13131f);
|
|
}
|
|
.first-run-card {
|
|
max-width: 520px;
|
|
width: 100%;
|
|
padding: 2.5rem;
|
|
background: var(--surface, #1e1e2e);
|
|
border-radius: 12px;
|
|
border: 1px solid var(--border, #2a2a3e);
|
|
text-align: center;
|
|
}
|
|
.first-run-logo {
|
|
display: block;
|
|
width: 64px;
|
|
height: 64px;
|
|
margin: 0 auto 0.5rem auto;
|
|
}
|
|
.first-run-card h1 {
|
|
margin: 0 0 0.75rem 0;
|
|
font-size: 1.5rem;
|
|
color: var(--text, #e0e0e0);
|
|
}
|
|
.first-run-desc {
|
|
color: var(--text-dim, #888);
|
|
margin-bottom: 1.5rem;
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
}
|
|
.input-row {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
.input-row input {
|
|
flex: 1;
|
|
}
|
|
.path-info {
|
|
text-align: left;
|
|
font-size: 0.85rem;
|
|
padding: 0.5rem 0.75rem;
|
|
margin-top: 0.5rem;
|
|
background: var(--surface-alt, #252538);
|
|
border-radius: 6px;
|
|
color: var(--text-dim, #888);
|
|
}
|
|
.error-msg {
|
|
text-align: left;
|
|
font-size: 0.85rem;
|
|
padding: 0.5rem 0.75rem;
|
|
margin-top: 0.5rem;
|
|
background: rgba(255, 107, 107, 0.1);
|
|
border: 1px solid rgba(255, 107, 107, 0.3);
|
|
border-radius: 6px;
|
|
color: #ff6b6b;
|
|
}
|
|
.first-run-actions {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
justify-content: center;
|
|
margin-top: 1.5rem;
|
|
}
|
|
.btn-lg {
|
|
padding: 0.65rem 1.5rem;
|
|
font-size: 1rem;
|
|
}
|
|
.form-group {
|
|
margin-bottom: 1rem;
|
|
text-align: left;
|
|
}
|
|
.form-label {
|
|
display: block;
|
|
font-size: 0.85rem;
|
|
color: var(--text-dim, #888);
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
</style>
|