refactor frontend
This commit is contained in:
156
src/components/config/ConfigurationView.vue
Normal file
156
src/components/config/ConfigurationView.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<script setup lang="ts">
|
||||
import { browserIconOptions, browserIconSrc } from "../../utils/icons";
|
||||
import type { BrowserConfigEntry, CreateCustomBrowserConfigInput } from "../../types/browser";
|
||||
|
||||
defineProps<{
|
||||
configError: string;
|
||||
configsLoading: boolean;
|
||||
browserConfigs: BrowserConfigEntry[];
|
||||
createConfigForm: CreateCustomBrowserConfigInput;
|
||||
savingConfig: boolean;
|
||||
configMonogram: (config: BrowserConfigEntry) => string;
|
||||
isDeletingConfig: (configId: string) => boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
updateName: [value: string];
|
||||
updateExecutablePath: [value: string];
|
||||
updateUserDataPath: [value: string];
|
||||
updateIconKey: [value: string];
|
||||
pickExecutablePath: [];
|
||||
pickUserDataPath: [];
|
||||
createConfig: [];
|
||||
deleteConfig: [configId: string];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="content-scroll-area">
|
||||
<section class="content-section">
|
||||
<div v-if="configError" class="inline-error">
|
||||
{{ configError }}
|
||||
</div>
|
||||
|
||||
<div class="config-form-card">
|
||||
<div class="config-form-header">
|
||||
<h3>Add Custom Browser</h3>
|
||||
<p>Provide a name, executable path, and Chromium user data path.</p>
|
||||
</div>
|
||||
<div class="config-form-layout">
|
||||
<div class="config-form-fields">
|
||||
<label class="field-group">
|
||||
<span>Name</span>
|
||||
<input
|
||||
:value="createConfigForm.name"
|
||||
placeholder="Work Chrome"
|
||||
@input="emit('updateName', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</label>
|
||||
<label class="field-group">
|
||||
<span>Executable Path</span>
|
||||
<div class="path-input-row">
|
||||
<input
|
||||
:value="createConfigForm.executablePath"
|
||||
placeholder="C:\Program Files\...\chrome.exe"
|
||||
@input="emit('updateExecutablePath', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
<button class="secondary-button" type="button" @click="emit('pickExecutablePath')">
|
||||
Browse File
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<label class="field-group">
|
||||
<span>User Data Path</span>
|
||||
<div class="path-input-row">
|
||||
<input
|
||||
:value="createConfigForm.userDataPath"
|
||||
placeholder="C:\Users\...\User Data"
|
||||
@input="emit('updateUserDataPath', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
<button class="secondary-button" type="button" @click="emit('pickUserDataPath')">
|
||||
Browse Folder
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="config-form-side">
|
||||
<label class="field-group">
|
||||
<span>Icon</span>
|
||||
<div class="icon-option-grid">
|
||||
<button
|
||||
v-for="option in browserIconOptions"
|
||||
:key="option.key"
|
||||
class="icon-option-button"
|
||||
:class="{ active: createConfigForm.iconKey === option.key }"
|
||||
type="button"
|
||||
@click="emit('updateIconKey', option.key)"
|
||||
>
|
||||
<img :src="option.src" :alt="option.label" />
|
||||
<span>{{ option.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<div class="config-form-actions">
|
||||
<button
|
||||
class="primary-button"
|
||||
type="button"
|
||||
:disabled="savingConfig"
|
||||
@click="emit('createConfig')"
|
||||
>
|
||||
{{ savingConfig ? "Saving..." : "Add Config" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="configsLoading" class="empty-card">
|
||||
<p>Loading browser configs...</p>
|
||||
</div>
|
||||
<div v-else class="stack-list">
|
||||
<article
|
||||
v-for="config in browserConfigs"
|
||||
:key="config.id"
|
||||
class="config-card"
|
||||
>
|
||||
<div class="config-card-header">
|
||||
<div class="config-card-lead">
|
||||
<div class="browser-nav-icon config-icon">
|
||||
<img
|
||||
v-if="browserIconSrc(config.iconKey ?? config.browserFamilyId)"
|
||||
:src="browserIconSrc(config.iconKey ?? config.browserFamilyId) ?? undefined"
|
||||
:alt="`${config.name} icon`"
|
||||
/>
|
||||
<span v-else>{{ configMonogram(config) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="config-title-row">
|
||||
<h4>{{ config.name }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
v-if="config.deletable"
|
||||
class="danger-button"
|
||||
type="button"
|
||||
:disabled="isDeletingConfig(config.id)"
|
||||
@click="emit('deleteConfig', config.id)"
|
||||
>
|
||||
{{ isDeletingConfig(config.id) ? "Deleting..." : "Delete" }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="config-meta">
|
||||
<div class="config-meta-row">
|
||||
<span class="config-label">Executable</span>
|
||||
<p :title="config.executablePath">{{ config.executablePath || "Not resolved" }}</p>
|
||||
</div>
|
||||
<div class="config-meta-row">
|
||||
<span class="config-label">User Data</span>
|
||||
<p :title="config.userDataPath">{{ config.userDataPath }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
Reference in New Issue
Block a user