fix(journals): add type='button' to prevent form submission and migrate to V3 Action API for file downloads

This commit is contained in:
Scott Idem
2026-02-03 22:14:22 -05:00
parent 6abe4c897e
commit 281972cb5d
24 changed files with 104 additions and 132 deletions

View File

@@ -168,7 +168,7 @@
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
const file_id = hosted_file_obj.event_file_id || hosted_file_obj.hosted_file_id || hosted_file_id;
const obj_type_path = hosted_file_obj.event_file_id ? 'event_file' : 'hosted_file';
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&x_no_account_id_token=${$ae_api.account_id}`;
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&key=${$ae_api.account_id}`;
});
async function handle_click() {

View File

@@ -644,7 +644,7 @@ export const download_hosted_file = async function download_hosted_file({
const task_id = hosted_file_id;
const endpoint = `/hosted_file/${hosted_file_id}/download`;
const endpoint = `/v3/action/hosted_file/${hosted_file_id}/download`;
if (filename) {
params['filename'] = filename;
}
@@ -697,7 +697,7 @@ export const delete_hosted_file = async function delete_hosted_file({
}) {
console.log('*** stores_hosted_api.js: delete_hosted_file() ***');
const endpoint = `/hosted_file/${hosted_file_id}`;
const endpoint = `/v3/action/hosted_file/${hosted_file_id}`;
if (link_to_type) {
params['link_to_type'] = link_to_type;
}

View File

@@ -105,7 +105,7 @@
open_file_status_message = 'Downloading file to cache...';
// Use the PROVEN endpoint path from api.ts that is known to work in Default Mode.
const url = `${$ae_api.base_url}/v3/action/hosted_file/${event_file_obj.hosted_file_id}/download?return_file=true&filename=${encodeURIComponent(event_file_obj.filename)}&x_no_account_id_token=direct-download`;
const url = `${$ae_api.base_url}/v3/action/hosted_file/${event_file_obj.hosted_file_id}/download?return_file=true&filename=${encodeURIComponent(event_file_obj.filename)}&key=${$ae_api.account_id}`;
const dl_result = await native.download_to_cache({
url,

View File

@@ -394,7 +394,7 @@
<a
href="{$ae_api.base_url}/event/file/{event_file_obj?.event_file_id}/download?filename={ae_util.clean_filename(
event_file_obj?.filename
)}&key=${$ae_api.account_id}"
)}&key={$ae_api.account_id}"
class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs underline"
title={`Download this file:\n${ae_util.clean_filename(event_file_obj?.filename)}\n[API] SHA256: ${event_file_obj?.hash_sha256.slice(0, 10)}...\nHosted ID: ${event_file_obj?.hosted_file_id} Event File ID: ${event_file_obj?.event_file_id}`}
>
@@ -431,11 +431,11 @@
>
<span class="text-xs text-gray-500 w-32"> Session Name: </span>
<a
href="{$ae_api.base_url}/event/file/{event_file_obj?.event_file_id}/download?filename={event_file_obj?.event_session_code}-{ae_util
href="{$ae_api.base_url}/v3/action/event_file/{event_file_obj?.event_file_id}/download?filename={event_file_obj?.event_session_code}-{ae_util
.clean_filename(event_file_obj?.event_presentation_name)
.substring(0, 20)}-{ae_util.clean_filename(
event_file_obj?.event_presenter_full_name
)}.{event_file_obj?.extension}&key=${$ae_api.account_id}"
)}.{event_file_obj?.extension}&key={$ae_api.account_id}"
class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs underline"
title={`Download renamed with session name to: ${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_session_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}`}
>

View File

@@ -44,7 +44,6 @@
import Archive_content_obj_li from './ae_idaa_comp__archive_content_obj_li.svelte';
import Archive_content_obj_id_edit from './ae_idaa_comp__archive_content_obj_id_edit.svelte';
// import Media_player from './../ae_idaa_comp__media_player.svelte';
import Modal_media_player from './ae_idaa_comp__modal_media_player.svelte';
import Help_tech from '$lib/app_components/e_app_help_tech.svelte';

View File

@@ -91,8 +91,8 @@
<audio autoplay controls style="max-width: 100%; max-height: 65vh;" class="w-96 h-auto">
<source
id="view_archive_content_audio_source"
src="{$ae_api.base_url}/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key=${$ae_api.account_id}"
src="{$ae_api.base_url}/v3/action/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key={$ae_api.account_id}"
type="audio/mpeg"
/>
<!--<source src="audio.ogg" type="audio/ogg">-->
@@ -103,8 +103,8 @@
<!-- style="max-width: 100%; max-height: 65vh;" -->
<video autoplay controls class="w-full h-auto">
<source
src="{$ae_api.base_url}/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key=${$ae_api.account_id}"
src="{$ae_api.base_url}/v3/action/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key={$ae_api.account_id}"
type="video/mp4"
/>
<!--<source src="video.ogg" type="video/ogg">-->
@@ -113,15 +113,15 @@
</video>
{:else if file_icons[$idaa_slct.archive_content_obj.file_extension] == 'file-image'}
<img
src="{$ae_api.base_url}/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key=${$ae_api.account_id}"
src="{$ae_api.base_url}/v3/action/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key={$ae_api.account_id}"
alt={$idaa_slct.archive_content_obj.name}
style="max-width: 100%; max-height: 65vh;"
/>
{:else}
<a
href="{$ae_api.base_url}/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key=${$ae_api.account_id}"
href="{$ae_api.base_url}/v3/action/hosted_file/{$idaa_slct.archive_content_obj
?.hosted_file_id}/download?key={$ae_api.account_id}"
target="_blank"
class="
novi_btn

View File

@@ -136,7 +136,7 @@
</a>
<!-- <a href="/about" class="btn btn-sm">About</a> -->
<!-- <a href="/settings" class="btn btn-sm">Settings</a> -->
<button
<button type="button"
onclick={() => {
if ($ae_loc.edit_mode) {
// Confirm before clearing
@@ -249,8 +249,7 @@
"
>
<!-- Scroll to top button -->
<button
type="button"
<button type="button"
class="
ae_btn_success_outlined
@@ -291,9 +290,8 @@
<!-- Scroll to the right button -->
<!-- Temporarily hidden until I figure out a better way to do this -->
<button
<button type="button"
class:hidden={1 == 1}
type="button"
class="
ae_btn_success_outlined
@@ -320,8 +318,7 @@
</button>
<!-- Scroll to bottom button -->
<button
type="button"
<button type="button"
class="
ae_btn_success_outlined

View File

@@ -120,8 +120,7 @@
<!-- Administrative Action Bar (Edit Mode Only) -->
{#if $ae_loc.edit_mode}
<nav class="flex flex-row flex-wrap gap-3 items-center justify-center w-full py-4 border-y border-surface-500/10">
<button
type="button"
<button type="button"
class="btn variant-filled-secondary shadow-lg hover:scale-105 transition-transform"
onclick={() => $journals_sess.show__modal_new__journal_obj = true}
>
@@ -129,8 +128,7 @@
<span>New Journal</span>
</button>
<button
type="button"
<button type="button"
class="btn variant-filled-surface border border-surface-500/30 shadow-lg hover:scale-105 transition-transform"
onclick={() => show_import_modal = true}
>
@@ -138,8 +136,7 @@
<span>Import</span>
</button>
<button
type="button"
<button type="button"
class="btn variant-soft-surface shadow-lg hover:scale-105 transition-transform"
onclick={() => $journals_sess.show__modal__journals_config = true}
>
@@ -163,8 +160,7 @@
<SquareLibrary size="4em" class="mx-auto mb-4 opacity-20" />
<h3 class="text-2xl font-bold mb-2">No Journals Found</h3>
<p class="opacity-60 mb-6">You haven't created any journals yet. Start by creating one to begin your documentation journey.</p>
<button
type="button"
<button type="button"
class="btn variant-filled-primary"
onclick={() => $journals_sess.show__modal_new__journal_obj = true}
>

View File

@@ -99,8 +99,7 @@
"
>
<!-- If middle click then open the all journals page in a new tab. Otherwise show/hide the menu. -->
<button
type="button"
<button type="button"
onmousedown={(event) => {
if (event.button === 1) {
// Middle click - open in new tab
@@ -230,8 +229,7 @@ Middle-click to open in new tab`}
</a>
{:else}
<!-- Edit Journal button. Creates a modal to edit the journal. -->
<!-- <button
type="button"
<!-- <button type="button"
onclick={() => {
tmp_journal_obj = {
name: $lq__journal_obj?.name,
@@ -265,8 +263,7 @@ Middle-click to open in new tab`}
<!-- <span class="text-sm text-gray-500 hidden md:inline">
New entry:
</span> -->
<button
type="button"
<button type="button"
onclick={() => {
// $journals_sess.show__modal_new__journal_entry_obj = true;

View File

@@ -60,8 +60,8 @@
{#if $ae_loc.edit_mode && on_force_reset}
<div class="pt-4 border-t border-error-500/20">
<p class="text-xs mb-2 opacity-70 italic">Passcode lost? You can force a reset to plain text, but all currently encrypted data will be permanently deleted.</p>
<button
type="button"
<button type="button"
class="btn btn-sm variant-filled-error font-bold"
onclick={on_force_reset}
>
@@ -89,8 +89,7 @@
{/if}
<!-- Floating Save Button -->
<button
type="button"
<button type="button"
onclick={on_save}
disabled={!has_changed}
class="btn btn-sm md:btn-md lg:btn-lg fixed top-72 right-6 min-w-32 variant-filled-success shadow-xl z-20 transition-all"
@@ -100,8 +99,7 @@
</button>
<!-- Inline Save Button (Mobile/Context) -->
<button
type="button"
<button type="button"
onclick={on_save}
disabled={!has_changed}
class="btn variant-filled-warning w-full max-w-96 mt-4"

View File

@@ -58,8 +58,7 @@
</a>
<div class="flex items-center gap-2 grow">
<button
type="button"
<button type="button"
onclick={toggle_edit_mode}
class="btn-icon btn-icon-sm transition-all {has_changed && $journals_loc.entry.edit_kv[entry.journal_entry_id] === 'current' ? 'variant-filled-success' : 'variant-soft-surface'}"
>
@@ -90,7 +89,7 @@
<!-- Auto-Save indicator -->
{#if $journals_loc.entry.edit_kv[entry.journal_entry_id] === 'current'}
<div class="flex items-center gap-1 px-2 border-r border-surface-500/20 mr-1">
<button
<button type="button"
class="btn-icon btn-icon-sm { $journals_loc.entry.auto_save ? 'text-primary-500' : 'opacity-30'}"
onclick={() => $journals_loc.entry.auto_save = !$journals_loc.entry.auto_save}
title="Toggle Auto Save"
@@ -107,7 +106,7 @@
<!-- Decrypt Toggle (Lock) -->
{#if entry.private}
<button
<button type="button"
class="btn-icon btn-icon-sm transition-all {is_decrypted ? 'variant-filled-success shadow-lg shadow-success-500/20' : 'variant-soft-warning'}"
onclick={on_decrypt}
title={is_decrypted ? 'Lock Content' : 'Decrypt Content'}
@@ -119,7 +118,8 @@
<div class="w-[1px] h-6 bg-surface-500/20 mx-1"></div>
<!-- Unified Config Button -->
<button
<button type="button"
class="btn btn-sm variant-soft-primary font-bold"
onclick={on_show_config}
>
@@ -128,7 +128,7 @@
<!-- Explicit Save (Mobile/Backup) -->
{#if has_changed && save_status !== 'saving'}
<button class="btn btn-sm variant-filled-primary shadow-lg" onclick={on_save}>
<button type="button" class="btn btn-sm variant-filled-primary shadow-lg" onclick={on_save}>
<Save size="1.1em" class="mr-2" /> Save
</button>
{/if}

View File

@@ -173,8 +173,7 @@
</h3>
{#if $ae_loc.edit_mode}
<button
type="button"
<button type="button"
class="btn btn-sm variant-soft-warning font-semibold"
onclick={() => {
$ae_sess.files.add_to_use_files_method = ($ae_sess.files.add_to_use_files_method === 'upload') ? 'select' : 'upload';
@@ -207,7 +206,7 @@
<div class="flex items-center gap-1 ml-2">
{#if $ae_loc.edit_mode}
<button
<button type="button"
class="btn btn-sm variant-soft-error"
onclick={() => handle_remove_file(file_id)}
title="Remove attachment"

View File

@@ -376,7 +376,7 @@
<AlertCircle size="2.5em" />
<span class="text-xl">{decryption_error}</span>
</div>
<button class="btn btn-sm variant-filled-error shadow-lg font-bold" onclick={() => decryption_error = null}>
<button type="button" class="btn btn-sm variant-filled-error shadow-lg font-bold" onclick={() => decryption_error = null}>
<XCircle size="1.2em" class="mr-2" /> Dismiss
</button>
</div>

View File

@@ -193,8 +193,7 @@
<span class="flex flex-row flex-wrap gap-1 items-center justify-center">
{#if !journals_journal_entry_obj.private}
<!-- Button to copy the Markdown version -->
<button
type="button"
<button type="button"
onclick={() => {
let tmp_entry_obj = journals_journal_entry_obj;
@@ -217,8 +216,7 @@
</button>
<!-- Button to copy the rendered to HTML version -->
<button
type="button"
<button type="button"
onclick={() => {
let htmlContent =
journals_journal_entry_obj.content_md_html || '';
@@ -246,8 +244,7 @@
</button>
<!-- Button to copy the rich text (rendered HTML) version -->
<button
type="button"
<button type="button"
onclick={async () => {
const element = document.getElementById(
`rendered_journal_entry_content_${journals_journal_entry_obj.journal_entry_id}`
@@ -286,8 +283,7 @@
</button>
<!-- Clone entry -->
<button
type="button"
<button type="button"
onclick={() => {
let data_kv = {
code: journals_journal_entry_obj.code,
@@ -337,8 +333,7 @@
<span class="text-xs text-gray-500 hidden">Private</span>
<!-- Button to copy the Markdown version -->
<button
type="button"
<button type="button"
onclick={() => {
let tmp_entry_obj = journals_journal_entry_obj;
@@ -401,8 +396,7 @@
<!-- Category code for journal entry -->
{#if journals_journal_entry_obj.category_code}
<button
type="button"
<button type="button"
onclick={() => {
if (
$journals_loc.entry.qry__category_code ==
@@ -440,8 +434,7 @@ Journal ID: ${journals_journal_entry_obj?.journal_id}
</a>
<!-- Button to show a modal that will allow for a quick append to Journal Entry option. -->
<button
type="button"
<button type="button"
onclick={() => {
$journals_sess.show__modal_append__journal_entry_id =
journals_journal_entry_obj?.id;
@@ -561,8 +554,7 @@ Journal ID: ${journals_journal_entry_obj?.journal_id}
</span>
<!-- Set/unset hide (boolean) -->
<button
type="button"
<button type="button"
onclick={() => {
let data_kv = {
hide: journals_journal_entry_obj?.hide ? false : true

View File

@@ -123,8 +123,7 @@
</button>
<!-- Clear search text button -->
<button
type="button"
<button type="button"
class:hidden={!$journals_loc.entry.qry__search_text && !$journals_loc.entry.qry__category_code}
onclick={() => {
$journals_loc.entry.qry__search_text = '';

View File

@@ -124,6 +124,7 @@
</span>
<div class="flex justify-end space-x-2 grow sm:grow-0">
<button
type="button"
class="btn btn-sm variant-ghost-surface"
onclick={() => note_content = ""}
disabled={is_submitting || note_content.length === 0}
@@ -131,6 +132,7 @@
Clear
</button>
<button
type="button"
class="btn btn-sm variant-filled-primary font-bold shadow-md"
onclick={handle_submit}
disabled={is_submitting || !target_journal_id || note_content.length === 0}

View File

@@ -181,19 +181,19 @@
<div class="space-y-6 py-2 h-[75vh] overflow-y-auto px-4">
<!-- Navigation Tabs -->
<div class="flex justify-center gap-1 mb-4 p-1 bg-surface-500/10 rounded-lg max-w-fit mx-auto sticky top-0 z-10 backdrop-blur-sm">
<button class="btn btn-sm transition-all {tab === 'actions' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'actions')}>
<button type="button" class="btn btn-sm transition-all {tab === 'actions' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'actions')}>
<Zap size="1.1em" class="mr-1" /> Quick Actions
</button>
<button class="btn btn-sm transition-all {tab === 'general' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'general')}>
<button type="button" class="btn btn-sm transition-all {tab === 'general' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'general')}>
<Layout size="1.1em" class="mr-1" /> General
</button>
<button class="btn btn-sm transition-all {tab === 'security' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'security')}>
<button type="button" class="btn btn-sm transition-all {tab === 'security' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'security')}>
<ShieldCheck size="1.1em" class="mr-1" /> Status & Security
</button>
<button class="btn btn-sm transition-all {tab === 'ui' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'ui')}>
<button type="button" class="btn btn-sm transition-all {tab === 'ui' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'ui')}>
<Palette size="1.1em" class="mr-1" /> UI/Visuals
</button>
<button class="btn btn-sm transition-all {tab === 'json' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'json')}>
<button type="button" class="btn btn-sm transition-all {tab === 'json' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'json')}>
<CodeXml size="1.1em" class="mr-1" /> JSON
</button>
</div>
@@ -201,13 +201,13 @@
{#if tab === 'actions'}
<div class="space-y-6 animate-in fade-in duration-300">
<section class="grid grid-cols-1 md:grid-cols-2 gap-4">
<button class="btn variant-soft-secondary w-full py-4 text-lg font-bold" onclick={() => { show = false; on_new_entry?.(); }}>
<button type="button" class="btn variant-soft-secondary w-full py-4 text-lg font-bold" onclick={() => { show = false; on_new_entry?.(); }}>
<FilePlus size="1.5em" class="mr-2"/> New Journal Entry
</button>
<button class="btn variant-soft-surface w-full py-4" onclick={() => { show = false; on_show_export?.(); }}>
<button type="button" class="btn variant-soft-surface w-full py-4" onclick={() => { show = false; on_show_export?.(); }}>
<FileDown size="1.5em" class="mr-2"/> Export Entries
</button>
<button class="btn variant-soft-surface w-full py-4" onclick={() => { show = false; on_show_import?.(); }}>
<button type="button" class="btn variant-soft-surface w-full py-4" onclick={() => { show = false; on_show_import?.(); }}>
<FileUp size="1.5em" class="mr-2"/> Import Entries
</button>
</section>
@@ -252,12 +252,12 @@
<div class="flex gap-2 items-center">
<input type="text" bind:value={category.code} class="input input-sm w-32" placeholder="Code" />
<input type="text" bind:value={category.name} class="input input-sm grow" placeholder="Display Name" />
<button class="btn-icon btn-icon-sm variant-soft-error" onclick={() => { tmp__journal_obj.cfg_json.category_li.splice(i, 1); }}>
<button type="button" class="btn-icon btn-icon-sm variant-soft-error" onclick={() => { tmp__journal_obj.cfg_json.category_li.splice(i, 1); }}>
<Minus size="1em" />
</button>
</div>
{/each}
<button class="btn btn-sm variant-soft-primary w-full mt-2" onclick={() => {
<button type="button" class="btn btn-sm variant-soft-primary w-full mt-2" onclick={() => {
if(!tmp__journal_obj.cfg_json.category_li) tmp__journal_obj.cfg_json.category_li = [];
tmp__journal_obj.cfg_json.category_li.push({code: '', name: ''});
}}>
@@ -303,9 +303,9 @@
<span class="text-xs opacity-60">Manual list position</span>
</div>
<div class="flex items-center gap-2">
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp__journal_obj.sort = (tmp__journal_obj.sort ?? 0) - 1; handle_update_journal(false); }}><Minus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp__journal_obj.sort = (tmp__journal_obj.sort ?? 0) - 1; handle_update_journal(false); }}><Minus size="1em"/></button>
<span class="font-mono font-bold w-8 text-center text-lg">{tmp__journal_obj.sort ?? 0}</span>
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp__journal_obj.sort = (tmp__journal_obj.sort ?? 0) + 1; handle_update_journal(false); }}><Plus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp__journal_obj.sort = (tmp__journal_obj.sort ?? 0) + 1; handle_update_journal(false); }}><Plus size="1em"/></button>
</div>
</div>
</div>
@@ -339,7 +339,7 @@
</section>
<section class="pt-8">
<button class="btn btn-sm variant-filled-error w-full shadow-lg" onclick={delete_journal}>
<button type="button" class="btn btn-sm variant-filled-error w-full shadow-lg" onclick={delete_journal}>
<Trash2 size="1.1em" class="mr-2" /> Delete Entire Journal
</button>
</section>
@@ -505,10 +505,10 @@
{#snippet footer()}
<div class="flex gap-4">
<button class="btn variant-ghost-surface font-bold min-w-[100px]" onclick={() => (show = false)}>
<button type="button" class="btn variant-ghost-surface font-bold min-w-[100px]" onclick={() => (show = false)}>
<X size="1.2em" class="mr-2" /> Cancel
</button>
<button class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={() => handle_update_journal(true)}>
<button type="button" class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={() => handle_update_journal(true)}>
<Check size="1.2em" class="mr-2" /> Save Changes
</button>
</div>

View File

@@ -180,8 +180,7 @@
<div class="grow flex flex-row flex-wrap gap-2 items-center justify-end">
<!-- Simplified Config Trigger -->
<button
type="button"
<button type="button"
onclick={() => ($journals_sess.show__modal_edit__journal_obj = true)}
class="btn variant-filled-secondary py-1 px-3 shadow-md"
title="Journal Config & Actions"

View File

@@ -86,18 +86,21 @@
<!-- Navigation Tabs -->
<div class="flex justify-center gap-1 mb-4 p-1 bg-surface-500/10 rounded-lg max-w-fit mx-auto sticky top-0 z-10 backdrop-blur-sm">
<button
type="button"
class="btn btn-sm transition-all {tab === 'form' ? 'variant-filled-primary' : 'variant-soft-surface'}"
onclick={() => (tab = 'form')}
>
<Settings size="1.1em" class="mr-1" /> Config
</button>
<button
type="button"
class="btn btn-sm transition-all {tab === 'local_json' ? 'variant-filled-primary' : 'variant-soft-surface'}"
onclick={() => (tab = 'local_json')}
>
<Database size="1.1em" class="mr-1" /> Local JSON
</button>
<button
type="button"
class="btn btn-sm transition-all {tab === 'session_json' ? 'variant-filled-primary' : 'variant-soft-surface'}"
onclick={() => (tab = 'session_json')}
>
@@ -277,10 +280,10 @@
{#snippet footer()}
<div class="flex gap-4">
<button class="btn variant-ghost-surface font-bold min-w-[100px]" onclick={() => (show = false)}>
<button type="button" class="btn variant-ghost-surface font-bold min-w-[100px]" onclick={() => (show = false)}>
<X size="1.2em" class="mr-2" /> Cancel
</button>
<button class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={handle_save}>
<button type="button" class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={handle_save}>
<Check size="1.2em" class="mr-2" /> Save Changes
</button>
</div>

View File

@@ -172,8 +172,7 @@ async function handle_save() {
</div>
<div class="modal-action flex justify-end gap-2 mt-4">
<button
type="button"
<button type="button"
disabled={!has_changes}
onclick={handle_save}
class="btn btn-sm md:btn-md lg:btn-lg min-w-32 hover:variant-outline-success hover:preset-filled-success-500"
@@ -183,8 +182,7 @@ async function handle_save() {
<Check class="mr-1" />
Update
</button>
<button
type="button"
<button type="button"
onclick={on_close}
class="btn preset-tonal-surface border border-surface-500 hover:preset-filled-surface-500 transition"
>

View File

@@ -121,16 +121,16 @@
<div class="space-y-6 py-2 h-[60vh] overflow-y-auto px-4">
<!-- Navigation Tabs -->
<div class="flex justify-center gap-1 mb-4 p-1 bg-surface-500/10 rounded-lg max-w-fit mx-auto sticky top-0 z-10 backdrop-blur-sm">
<button class="btn btn-sm transition-all {tab === 'actions' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'actions')}>
<button type="button" class="btn btn-sm transition-all {tab === 'actions' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'actions')}>
<Zap size="1.1em" class="mr-1" /> Quick Actions
</button>
<button class="btn btn-sm transition-all {tab === 'meta' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'meta')}>
<button type="button" class="btn btn-sm transition-all {tab === 'meta' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'meta')}>
<Shapes size="1.1em" class="mr-1" /> Metadata
</button>
<button class="btn btn-sm transition-all {tab === 'security' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'security')}>
<button type="button" class="btn btn-sm transition-all {tab === 'security' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'security')}>
<ShieldCheck size="1.1em" class="mr-1" /> Status & Security
</button>
<button class="btn btn-sm transition-all {tab === 'json' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'json')}>
<button type="button" class="btn btn-sm transition-all {tab === 'json' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => (tab = 'json')}>
<CodeXml size="1.1em" class="mr-1" /> JSON
</button>
</div>
@@ -138,16 +138,16 @@
{#if tab === 'actions'}
<div class="space-y-6 animate-in fade-in duration-300">
<section class="grid grid-cols-1 md:grid-cols-2 gap-4">
<button class="btn variant-soft-secondary w-full" onclick={() => { show = false; on_prepend?.(); }}>
<button type="button" class="btn variant-soft-secondary w-full" onclick={() => { show = false; on_prepend?.(); }}>
<ArrowUpToLine size="1.2em" class="mr-2"/> Prepend Content
</button>
<button class="btn variant-soft-secondary w-full" onclick={() => { show = false; on_append?.(); }}>
<button type="button" class="btn variant-soft-secondary w-full" onclick={() => { show = false; on_append?.(); }}>
<ArrowDownToLine size="1.2em" class="mr-2"/> Append Content
</button>
<button class="btn variant-soft-surface w-full" onclick={() => { show = false; on_show_export?.(); }}>
<button type="button" class="btn variant-soft-surface w-full" onclick={() => { show = false; on_show_export?.(); }}>
<FileDown size="1.2em" class="mr-2"/> Export Entry
</button>
<button class="btn variant-soft-surface w-full" onclick={() => { /* Clone logic here */ alert('Clone not yet implemented in modal'); }}>
<button type="button" class="btn variant-soft-surface w-full" onclick={() => { /* Clone logic here */ alert('Clone not yet implemented in modal'); }}>
<Copy size="1.2em" class="mr-2"/> Clone Entry
</button>
</section>
@@ -156,7 +156,7 @@
<h4 class="text-xs font-bold uppercase opacity-50">Quick Category</h4>
<div class="flex flex-wrap gap-2">
{#each journal?.cfg_json?.category_li ?? [] as cat}
<button
<button type="button"
class="btn btn-sm {tmp_entry_obj.category_code === cat.code ? 'variant-filled-primary' : 'variant-soft-primary'}"
onclick={() => { tmp_entry_obj.category_code = cat.code; handle_update_entry(); on_save(); }}
>
@@ -195,9 +195,9 @@
<label class="label">
<span class="text-sm font-bold opacity-70">Sort Priority</span>
<div class="flex items-center gap-2">
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) - 1; handle_update_entry(); on_save(); }}><Minus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) - 1; handle_update_entry(); on_save(); }}><Minus size="1em"/></button>
<span class="font-mono font-bold w-8 text-center">{tmp_entry_obj.sort ?? 0}</span>
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) + 1; handle_update_entry(); on_save(); }}><Plus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) + 1; handle_update_entry(); on_save(); }}><Plus size="1em"/></button>
</div>
</label>
</div>
@@ -238,9 +238,9 @@
<span class="text-xs opacity-60">Manual list position</span>
</div>
<div class="flex items-center gap-2">
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) - 1; handle_update_entry(); on_save(); }}><Minus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) - 1; handle_update_entry(); on_save(); }}><Minus size="1em"/></button>
<span class="font-mono font-bold w-8 text-center text-lg">{tmp_entry_obj.sort ?? 0}</span>
<button class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) + 1; handle_update_entry(); on_save(); }}><Plus size="1em"/></button>
<button type="button" class="btn-icon btn-icon-sm variant-soft-surface" onclick={() => { tmp_entry_obj.sort = (tmp_entry_obj.sort ?? 0) + 1; handle_update_entry(); on_save(); }}><Plus size="1em"/></button>
</div>
</div>
</div>
@@ -267,7 +267,7 @@
<RefreshCcw size="1.2em" /> Disaster Recovery
</h4>
<p class="text-xs opacity-70 mb-4 italic">If the encryption passcode is lost, the data is unrecoverable. You can force a reset to plain text to reuse this entry ID.</p>
<button class="btn btn-sm variant-filled-error w-full font-bold" onclick={() => { show = false; on_force_reset?.(); }}>
<button type="button" class="btn btn-sm variant-filled-error w-full font-bold" onclick={() => { show = false; on_force_reset?.(); }}>
Force Reset to Plain Text
</button>
</div>
@@ -275,7 +275,7 @@
{/if}
<section class="pt-12">
<button class="btn btn-sm variant-soft-error w-full" onclick={() => { alert('Delete logic handled in parent component'); }}>
<button type="button" class="btn btn-sm variant-soft-error w-full" onclick={() => { alert('Delete logic handled in parent component'); }}>
<Trash2 size="1.1em" class="mr-2" /> Delete Entry
</button>
</section>
@@ -294,7 +294,7 @@
</div>
{#snippet footer()}
<button class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={() => (show = false)}>
<button type="button" class="btn variant-filled-primary font-bold shadow-lg min-w-[120px]" onclick={() => (show = false)}>
<Check size="1.2em" class="mr-2" />
Done
</button>

View File

@@ -111,7 +111,8 @@
</label>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-2">
{#each templates as template}
<button
<button type="button"
class="btn variant-ringed-surface flex flex-col gap-1 p-2 h-24 items-center justify-center border-2 text-center {selected_template_id === template.id ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/20' : 'opacity-60'}"
onclick={() => { selected_template_id = template.id; generate_preview(); }}
>
@@ -144,13 +145,13 @@
<!-- Actions -->
<div class="modal-action flex justify-between items-center">
<button class="btn preset-tonal-secondary" onclick={on_close}>Close</button>
<button type="button" class="btn preset-tonal-secondary" onclick={on_close}>Close</button>
<div class="flex gap-2">
<button class="btn variant-soft-primary" onclick={handle_copy}>
<button type="button" class="btn variant-soft-primary" onclick={handle_copy}>
<Copy class="mr-2" size="1.2em" /> Copy to Clipboard
</button>
<button class="btn preset-filled-primary" onclick={handle_download}>
<button type="button" class="btn preset-filled-primary" onclick={handle_download}>
<Download class="mr-2" size="1.2em" /> Download File
</button>
</div>

View File

@@ -232,8 +232,8 @@
{/if}
<div class="modal-action">
<button class="btn preset-tonal-secondary" onclick={on_close}>Cancel</button>
<button
<button type="button" class="btn preset-tonal-secondary" onclick={on_close}>Cancel</button>
<button type="button"
class="btn preset-filled-primary"
disabled={parsed_entries.length === 0 || is_importing}
onclick={handle_import}

View File

@@ -105,8 +105,7 @@
{obj_enable} -->
<!-- Set/unset priority (boolean) -->
<button
type="button"
<button type="button"
onclick={() => {
obj_priority = !obj_priority;
// update_journal_entry();
@@ -127,8 +126,7 @@
class:hidden={!$ae_loc.edit_mode}
class="flex flex-row flex-wrap items-center justify-center border border-gray-300 rounded-lg"
>
<button
type="button"
<button type="button"
onclick={() => {
obj_sort = obj_sort ? obj_sort + 1 : 1;
// update_journal_entry();
@@ -146,8 +144,7 @@
<ArrowDown10 />
{/if}
</span>
<button
type="button"
<button type="button"
onclick={() => {
obj_sort = obj_sort ? obj_sort - 1 : 0;
// update_journal_entry();
@@ -190,8 +187,7 @@
{#if obj_archive_on}
<!-- Button to clear the datetime -->
<button
type="button"
<button type="button"
onclick={() => {
obj_archive_on = null;
// update_journal_entry();
@@ -205,8 +201,7 @@
</button>
{:else}
<!-- Button to set the datetime to now -->
<button
type="button"
<button type="button"
onclick={() => {
// tmp_entry_obj.archive_on = new Date().toISOString();
// console.log('Archive on datetime set to now:', tmp_entry_obj.archive_on);
@@ -225,8 +220,7 @@
</span>
<!-- Set/unset hide (boolean) -->
<button
type="button"
<button type="button"
onclick={() => {
obj_hide = !obj_hide;
update_journal_entry();
@@ -244,8 +238,7 @@
</button>
<!-- Set/unset enable (boolean) -->
<button
type="button"
<button type="button"
onclick={() => {
obj_enable = !obj_enable;
// update_journal_entry();
@@ -264,8 +257,7 @@
</button>
<!-- Delete journal entry -->
<button
type="button"
<button type="button"
onclick={() => {
if (confirm(`Are you sure you want to delete this journal entry?`)) {
let delete_method = 'disable';