refac: styling
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
import TextToken from './MarkdownInlineTokens/TextToken.svelte';
|
import TextToken from './MarkdownInlineTokens/TextToken.svelte';
|
||||||
import CodespanToken from './MarkdownInlineTokens/CodespanToken.svelte';
|
import CodespanToken from './MarkdownInlineTokens/CodespanToken.svelte';
|
||||||
import MentionToken from './MarkdownInlineTokens/MentionToken.svelte';
|
import MentionToken from './MarkdownInlineTokens/MentionToken.svelte';
|
||||||
|
import NoteLinkToken from './MarkdownInlineTokens/NoteLinkToken.svelte';
|
||||||
import SourceToken from './SourceToken.svelte';
|
import SourceToken from './SourceToken.svelte';
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
@@ -26,6 +27,24 @@
|
|||||||
export let sourceIds = [];
|
export let sourceIds = [];
|
||||||
export let onSourceClick: Function = () => {};
|
export let onSourceClick: Function = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a URL is a same-origin note link and return the note ID if so.
|
||||||
|
*/
|
||||||
|
const getNoteIdFromHref = (href: string): string | null => {
|
||||||
|
try {
|
||||||
|
const url = new URL(href, window.location.origin);
|
||||||
|
if (url.origin === window.location.origin) {
|
||||||
|
const match = url.pathname.match(/^\/notes\/([^/]+)$/);
|
||||||
|
if (match) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Invalid URL
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle link clicks - intercept same-origin app URLs for in-app navigation
|
* Handle link clicks - intercept same-origin app URLs for in-app navigation
|
||||||
*/
|
*/
|
||||||
@@ -54,7 +73,10 @@
|
|||||||
{:else if token.type === 'html'}
|
{:else if token.type === 'html'}
|
||||||
<HtmlToken {id} {token} {onSourceClick} />
|
<HtmlToken {id} {token} {onSourceClick} />
|
||||||
{:else if token.type === 'link'}
|
{:else if token.type === 'link'}
|
||||||
{#if token.tokens}
|
{@const noteId = getNoteIdFromHref(token.href)}
|
||||||
|
{#if noteId}
|
||||||
|
<NoteLinkToken {noteId} href={token.href} />
|
||||||
|
{:else if token.tokens}
|
||||||
<a
|
<a
|
||||||
href={token.href}
|
href={token.href}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount, getContext } from 'svelte';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { getNoteById } from '$lib/apis/notes';
|
||||||
|
import { getUserInfoById } from '$lib/apis/users';
|
||||||
|
import { capitalizeFirstLetter } from '$lib/utils';
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
export let noteId: string;
|
||||||
|
export let href: string;
|
||||||
|
|
||||||
|
let title = '';
|
||||||
|
let author = '';
|
||||||
|
let loading = true;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
const note = await getNoteById(localStorage.token, noteId);
|
||||||
|
if (note) {
|
||||||
|
title = note.title || $i18n.t('Untitled');
|
||||||
|
|
||||||
|
if (note.user_id) {
|
||||||
|
try {
|
||||||
|
const userInfo = await getUserInfoById(localStorage.token, note.user_id);
|
||||||
|
if (userInfo) {
|
||||||
|
author = capitalizeFirstLetter(userInfo.name ?? userInfo.email ?? '');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// user lookup failed, skip author
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
title = $i18n.t('Note');
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
|
<button
|
||||||
|
class="relative group py-2 px-3 w-60 flex flex-col bg-white dark:bg-gray-850 border border-gray-50/30 dark:border-gray-800/30 rounded-xl text-left cursor-pointer"
|
||||||
|
type="button"
|
||||||
|
on:click|preventDefault|stopPropagation={() => {
|
||||||
|
try {
|
||||||
|
const url = new URL(href, window.location.origin);
|
||||||
|
goto(url.pathname);
|
||||||
|
} catch {
|
||||||
|
// fallback
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="flex flex-col justify-center w-full min-w-0">
|
||||||
|
<div class="dark:text-gray-100 text-sm flex justify-between items-center gap-2">
|
||||||
|
<div class="font-medium line-clamp-1 flex-1 min-w-0">
|
||||||
|
{#if loading}
|
||||||
|
<span class="text-gray-400">...</span>
|
||||||
|
{:else}
|
||||||
|
{title}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-500 text-xs shrink-0">{$i18n.t('Note')}</div>
|
||||||
|
</div>
|
||||||
|
{#if author}
|
||||||
|
<div class="text-gray-500 text-xs line-clamp-1 mt-0.5">
|
||||||
|
{$i18n.t('By {{name}}', { name: author })}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
Reference in New Issue
Block a user