Files
protocol-bicorder/bicorder-app/src/components/MetadataFields.svelte
2025-12-18 10:30:13 -07:00

237 lines
4.7 KiB
Svelte

<script lang="ts">
import { createEventDispatcher } from 'svelte';
import type { Metadata } from '../types';
export let metadata: Metadata;
const dispatch = createEventDispatcher<{
update: Partial<Metadata>;
}>();
function handleInput(field: keyof Metadata, value: string) {
dispatch('update', { [field]: value || null });
}
function handleToggle(field: keyof Metadata, value: boolean) {
dispatch('update', { [field]: value });
}
function updateTimestamp() {
dispatch('update', { timestamp: new Date().toISOString() });
}
function formatTimestamp(timestamp: string | null): string {
if (!timestamp) return '';
try {
return new Date(timestamp).toLocaleString();
} catch {
return timestamp;
}
}
</script>
<section class="metadata">
<div class="metadata-field">
<label for="protocol">Protocol:</label>
<input
id="protocol"
type="text"
placeholder="[Protocol]"
value={metadata.protocol || ''}
on:input={(e) => handleInput('protocol', e.currentTarget.value)}
/>
</div>
<div class="metadata-field">
<label for="description">Description:</label>
<textarea
id="description"
placeholder="[Description]"
value={metadata.description || ''}
on:input={(e) => handleInput('description', e.currentTarget.value)}
rows="3"
/>
</div>
<div class="metadata-field">
<label for="analyst">Analyst:</label>
<input
id="analyst"
type="text"
placeholder="[Analyst]"
value={metadata.analyst || ''}
on:input={(e) => handleInput('analyst', e.currentTarget.value)}
/>
</div>
<div class="metadata-field">
<label for="standpoint">Standpoint:</label>
<input
id="standpoint"
type="text"
placeholder="[Standpoint]"
value={metadata.standpoint || ''}
on:input={(e) => handleInput('standpoint', e.currentTarget.value)}
/>
</div>
<div class="metadata-field">
<label for="timestamp">Timestamp:</label>
<div class="timestamp-display">
<input
id="timestamp"
type="text"
readonly
value={formatTimestamp(metadata.timestamp)}
placeholder="[Auto-generated]"
/>
<button on:click={updateTimestamp} aria-label="Update timestamp">
🕐 Update
</button>
</div>
</div>
<div class="metadata-field toggle-field">
<label for="shortform">Short Form:</label>
<div class="toggle-container">
<label class="toggle-switch">
<input
id="shortform"
type="checkbox"
checked={metadata.shortform}
on:change={(e) => handleToggle('shortform', e.currentTarget.checked)}
/>
<span class="slider"></span>
</label>
<span class="toggle-label">{metadata.shortform ? 'Enabled' : 'Disabled'}</span>
</div>
</div>
</section>
<style>
.metadata {
margin: 2rem 0;
padding: 1rem;
border: 2px solid var(--border-color);
}
.metadata-field {
margin: 0.5rem 0;
}
label {
display: block;
margin-bottom: 0.25rem;
font-weight: bold;
}
textarea {
width: 100%;
padding: 0.5rem;
font-family: inherit;
font-size: inherit;
resize: vertical;
min-height: 4rem;
}
.timestamp-display {
display: flex;
gap: 0.5rem;
}
.timestamp-display input {
flex: 1;
opacity: 0.7;
}
.timestamp-display button {
flex-shrink: 0;
}
.toggle-field {
display: flex;
align-items: center;
gap: 1rem;
}
.toggle-field > label {
margin-bottom: 0;
}
.toggle-container {
display: flex;
align-items: center;
gap: 0.75rem;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 50px;
height: 26px;
margin-bottom: 0;
cursor: pointer;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
border-radius: 26px;
transition: 0.3s;
}
.slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 3px;
background-color: white;
border-radius: 50%;
transition: 0.3s;
}
.toggle-switch input:checked + .slider {
background-color: var(--primary-color, #4CAF50);
}
.toggle-switch input:checked + .slider:before {
transform: translateX(24px);
}
.toggle-label {
font-size: 0.9rem;
opacity: 0.8;
}
@media (max-width: 768px) {
.metadata {
padding: 0.5rem;
}
.timestamp-display {
flex-direction: column;
}
.timestamp-display button {
width: 100%;
}
.toggle-field {
flex-direction: column;
align-items: flex-start;
}
}
</style>