Browse Source

Merge remote-tracking branch 'onedev/master' into Issue#11#153

master
buttercat1791 11 months ago
parent
commit
59fec61da8
  1. 3
      import_map.json
  2. 2
      src/app.html
  3. 2
      src/lib/components/Login.svelte
  4. 9
      src/lib/components/Publication.svelte
  5. 4
      src/lib/components/util/CardActions.svelte
  6. 4
      src/lib/components/util/Profile.svelte
  7. 2
      src/lib/consts.ts
  8. 2
      src/lib/navigator/EventNetwork/Legend.svelte
  9. 130
      src/lib/navigator/EventNetwork/NodeTooltip.svelte
  10. 18
      src/lib/navigator/EventNetwork/index.svelte
  11. 2
      src/lib/stores.ts
  12. 29
      src/routes/+layout.svelte
  13. 30
      src/routes/about/+page.svelte
  14. 46
      src/routes/publication/+page.svelte
  15. 6
      src/routes/publication/+page.ts
  16. 71
      src/routes/visualize/+page.svelte
  17. BIN
      static/favicon.png
  18. BIN
      static/screenshots/old_books.jpg
  19. 21
      vite.config.ts

3
import_map.json

@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
"svelte": "npm:svelte@5.0.x",
"flowbite": "npm:flowbite@2.2.x",
"flowbite-svelte": "npm:flowbite-svelte@0.44.x",
"flowbite-svelte-icons": "npm:flowbite-svelte-icons@2.0.x"
"flowbite-svelte-icons": "npm:flowbite-svelte-icons@2.0.x",
"child_process": "node:child_process"
}
}

2
src/app.html

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="icon" href="%sveltekit.assets%/favicon.png?v=2" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>

2
src/lib/components/Login.svelte

@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
<Popover
class='popover-leather w-fit'
placement='bottom'
target='avatar'
triggeredBy='#avatar'
>
<div class='w-full flex space-x-2'>
<Button

9
src/lib/components/Publication.svelte

@ -14,8 +14,14 @@ @@ -14,8 +14,14 @@
import Preview from "./Preview.svelte";
import { pharosInstance } from "$lib/parser";
import { page } from "$app/state";
import { ndkInstance } from "$lib/ndk";
import type { NDKEvent } from "@nostr-dev-kit/ndk";
let { rootId, publicationType } = $props<{ rootId: string, publicationType: string }>();
let { rootId, publicationType, indexEvent } = $props<{
rootId: string,
publicationType: string,
indexEvent: NDKEvent
}>();
if (rootId !== $pharosInstance.getRootIndexId()) {
console.error("Root ID does not match parser root index ID");
@ -94,6 +100,7 @@ @@ -94,6 +100,7 @@
});
</script>
{#if showTocButton && !showToc}
<Button
class="btn-leather fixed top-20 left-4 h-6 w-6"

4
src/lib/components/util/CardActions.svelte

@ -138,8 +138,8 @@ @@ -138,8 +138,8 @@
</Popover>
{/if}
<!-- Event JSON -->
<Modal class='modal-leather' title='Event JSON' bind:open={jsonModalOpen} autoclose outsideclose size='sm'>
<div class="overflow-auto bg-highlight dark:bg-primary-900 text-sm rounded p-1">
<Modal class='modal-leather' title='Event JSON' bind:open={jsonModalOpen} autoclose outsideclose size='lg'>
<div class="overflow-auto bg-highlight dark:bg-primary-900 text-sm rounded p-1" style="max-height: 70vh;">
<pre><code>{JSON.stringify(event.rawEvent(), null, 2)}</code></pre>
</div>
</Modal>

4
src/lib/components/util/Profile.svelte

@ -46,10 +46,12 @@ function shortenNpub(long: string|undefined) { @@ -46,10 +46,12 @@ function shortenNpub(long: string|undefined) {
class='h-6 w-6 cursor-pointer'
src={pfp}
alt={username}
id="profile-avatar"
/>
{#key username || tag}
<Popover
target="avatar"
placement="bottom"
triggeredBy="#profile-avatar"
class='popover-leather w-[180px]'
trigger='hover'
>

2
src/lib/consts.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
export const wikiKind = 30818;
export const indexKind = 30040;
export const zettelKinds = [ 30041 ];
export const zettelKinds = [ 30041, 30818 ];
export const standardRelays = [ 'wss://thecitadel.nostr1.com', 'wss://relay.noswhere.com' ];
export const bootstrapRelays = [ 'wss://purplepag.es', 'wss://relay.noswhere.com' ];

2
src/lib/navigator/EventNetwork/Legend.svelte

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
<span class="legend-circle content"></span>
<span class="legend-letter">C</span>
</div>
<span>Content events (kind 30041) - Publication sections</span>
<span>Content events (kinds 30041, 30818) - Publication sections</span>
</li>
<li class="legend-item">
<svg class="w-6 h-6 mr-2" viewBox="0 0 24 24">

130
src/lib/navigator/EventNetwork/NodeTooltip.svelte

@ -1,38 +1,128 @@ @@ -1,38 +1,128 @@
<script lang="ts">
import type { NetworkNode } from "./types";
import { onMount, createEventDispatcher } from "svelte";
export let node: NetworkNode;
export let selected: boolean = false;
export let x: number;
export let y: number;
let { node, selected = false, x, y } = $props<{
node: NetworkNode;
selected?: boolean;
x: number;
y: number;
}>();
const dispatch = createEventDispatcher();
let tooltipElement: HTMLDivElement;
let tooltipX = $state(x + 10);
let tooltipY = $state(y - 10);
function getAuthorTag(node: NetworkNode): string {
if (node.event) {
const authorTags = node.event.getMatchingTags("author");
if (authorTags.length > 0) {
return authorTags[0][1];
}
}
return "Unknown";
}
function getSummaryTag(node: NetworkNode): string | null {
if (node.event) {
const summaryTags = node.event.getMatchingTags("summary");
if (summaryTags.length > 0) {
return summaryTags[0][1];
}
}
return null;
}
function getDTag(node: NetworkNode): string {
if (node.event) {
const dTags = node.event.getMatchingTags("d");
if (dTags.length > 0) {
return dTags[0][1];
}
}
return "View Publication";
}
function truncateContent(content: string, maxLength: number = 200): string {
if (content.length <= maxLength) return content;
return content.substring(0, maxLength) + "...";
}
function closeTooltip() {
dispatch('close');
}
// Ensure tooltip is fully visible on screen
onMount(() => {
if (tooltipElement) {
const rect = tooltipElement.getBoundingClientRect();
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
// Check if tooltip goes off the right edge
if (rect.right > windowWidth) {
tooltipX = windowWidth - rect.width - 10;
}
// Check if tooltip goes off the bottom edge
if (rect.bottom > windowHeight) {
tooltipY = windowHeight - rect.height - 10;
}
// Check if tooltip goes off the left edge
if (rect.left < 0) {
tooltipX = 10;
}
// Check if tooltip goes off the top edge
if (rect.top < 0) {
tooltipY = 10;
}
}
});
</script>
<div
bind:this={tooltipElement}
class="tooltip-leather fixed p-4 rounded shadow-lg bg-primary-0 dark:bg-primary-800
border border-gray-200 dark:border-gray-800 transition-colors duration-200"
style="left: {x + 10}px; top: {y - 10}px; z-index: 1000;"
style="left: {tooltipX}px; top: {tooltipY}px; z-index: 1000; max-width: 400px;"
>
<div class="space-y-2">
<div class="font-bold text-base">{node.title}</div>
<button
class="absolute top-2 left-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 rounded-full p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
onclick={closeTooltip}
aria-label="Close"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
<div class="space-y-2 pl-6">
<div class="font-bold text-base">
<a href="/publication?id={node.id}" class="text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500">
{node.title}
</a>
</div>
<div class="text-gray-600 dark:text-gray-400 text-sm">
{node.type} ({node.isContainer ? "30040" : "30041"})
{node.type} ({node.kind})
</div>
<div
class="text-gray-600 dark:text-gray-400 text-sm overflow-hidden text-ellipsis"
>
ID: {node.id}
{#if node.naddr}
<div>{node.naddr}</div>
{/if}
{#if node.nevent}
<div>{node.nevent}</div>
{/if}
<div class="text-gray-600 dark:text-gray-400 text-sm">
Author: {getAuthorTag(node)}
</div>
{#if node.isContainer && getSummaryTag(node)}
<div class="mt-2 text-xs bg-gray-100 dark:bg-gray-800 p-2 rounded overflow-auto max-h-40">
<span class="font-semibold">Summary:</span> {truncateContent(getSummaryTag(node) || "", 200)}
</div>
{/if}
{#if node.content}
<div
class="mt-2 text-xs bg-gray-100 dark:bg-gray-800 p-2 rounded overflow-auto max-h-40"
>
{node.content}
{truncateContent(node.content)}
</div>
{/if}
{#if selected}
@ -41,4 +131,4 @@ @@ -41,4 +131,4 @@
</div>
{/if}
</div>
</div>
</div>

18
src/lib/navigator/EventNetwork/index.svelte

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
import { createSimulation, setupDragHandlers, applyGlobalLogGravity, applyConnectedGravity } from "./utils/forceSimulation";
import Legend from "./Legend.svelte";
import NodeTooltip from "./NodeTooltip.svelte";
import type { NetworkNode, NetworkLink } from "./types";
let { events = [] } = $props<{ events?: NDKEvent[] }>();
@ -90,14 +91,14 @@ @@ -90,14 +91,14 @@
function updateGraph() {
if (!svg || !events?.length || !svgGroup) return;
const { nodes, links } = generateGraph(events, currentLevels);
const { nodes, links } = generateGraph(events, Number(currentLevels));
if (!nodes.length) return;
// Stop any existing simulation
if (simulation) simulation.stop();
// Create new simulation
simulation = createSimulation(nodes, links, nodeRadius, linkDistance);
simulation = createSimulation(nodes, links, Number(nodeRadius), Number(linkDistance));
const dragHandler = setupDragHandlers(simulation);
// Update links
@ -303,6 +304,11 @@ @@ -303,6 +304,11 @@
updateGraph();
}
});
function handleTooltipClose() {
tooltipVisible = false;
selectedNodeId = null;
}
</script>
<div
@ -321,15 +327,9 @@ @@ -321,15 +327,9 @@
selected={tooltipNode.id === selectedNodeId}
x={tooltipX}
y={tooltipY}
on:close={handleTooltipClose}
/>
{/if}
<Legend />
</div>
<style>
.tooltip {
max-width: 300px;
word-wrap: break-word;
}
</style>

2
src/lib/stores.ts

@ -3,6 +3,6 @@ import { FeedType } from "./consts"; @@ -3,6 +3,6 @@ import { FeedType } from "./consts";
export let idList = writable<string[]>([]);
export let alexandriaKinds = readable<number[]>([30040, 30041]);
export let alexandriaKinds = readable<number[]>([30040, 30041, 30818]);
export let feedType = writable<FeedType>(FeedType.StandardRelays);

29
src/routes/+layout.svelte

@ -2,15 +2,44 @@ @@ -2,15 +2,44 @@
import "../app.css";
import Navigation from "$lib/components/Navigation.svelte";
import { onMount } from "svelte";
import { page } from "$app/stores";
// Compute viewport height.
$: displayHeight = window.innerHeight;
// Get standard metadata for OpenGraph tags
let title = 'Library of Alexandria';
let currentUrl = $page.url.href;
// Get default image and summary for the Alexandria website
let image = '/screenshots/old_books.jpg';
let summary = 'Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.';
onMount(() => {
document.body.style.height = `${displayHeight}px`;
});
</script>
<svelte:head>
<!-- Basic meta tags -->
<title>{title}</title>
<meta name="description" content="{summary}" />
<!-- OpenGraph meta tags -->
<meta property="og:title" content="{title}" />
<meta property="og:description" content="{summary}" />
<meta property="og:url" content="{currentUrl}" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Alexandria" />
<meta property="og:image" content="{image}" />
<!-- Twitter Card meta tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{title}" />
<meta name="twitter:description" content="{summary}" />
<meta name="twitter:image" content="{image}" />
</svelte:head>
<div class={'leather min-h-full w-full flex flex-col items-center'}>
<Navigation class='sticky top-0' />
<slot />

30
src/routes/about/+page.svelte

@ -1,13 +1,23 @@ @@ -1,13 +1,23 @@
<script lang='ts'>
import { Heading, Img, P, A } from "flowbite-svelte";
// Get the git tag version from environment variables
const appVersion = import.meta.env.APP_VERSION || 'development';
const isVersionKnown = appVersion !== 'development';
</script>
<div class='w-full flex justify-center'>
<main class='main-leather flex flex-col space-y-6 max-w-2xl w-full my-6 px-4'>
<Heading tag='h1' class='h-leather text-left mb-4'>About</Heading>
<div class="flex justify-between items-center">
<Heading tag='h1' class='h-leather mb-2'>About the Library of Alexandria</Heading>
{#if isVersionKnown}
<span class="text-sm bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-nowrap">Version: {appVersion}</span>
{/if}
</div>
<Img src="/screenshots/old_books.jpg" alt="Alexandria icon" />
<P class="mb-3">
Alexandria is a reader and writer for <A href="/publication?d=gitcitadel-project-documentation-curated-publications-specification-7-by-stella-v-1">curated publications</A> (in Asciidoc), and will eventually also support long-form articles (Markdown) and wiki pages (Asciidoc). It is produced by the <A href="/publication?d=gitcitadel-project-documentation-gitcitadel-project-1-by-stella-v-1">GitCitadel project team</A>.
Alexandria is a reader and writer for <A href="/publication?d=gitcitadel-project-documentation-curated-publications-specification-7-by-stella-v-1">curated publications</A> (in Asciidoc), wiki pages (Asciidoc), and will eventually also support long-form articles (Markdown). It is produced by the <A href="/publication?d=gitcitadel-project-documentation-gitcitadel-project-1-by-stella-v-1">GitCitadel project team</A>.
</P>
<P class="mb-3">
@ -34,11 +44,11 @@ @@ -34,11 +44,11 @@
</P>
<P class="mb-3">
If you click on a card, which represents a 30040 index event, the associated reading view opens to the publication. The app then pulls all of the content events (30041s), in the order in which they are indexed, and displays them as a single document.
If you click on a card, which represents a 30040 index event, the associated reading view opens to the publication. The app then pulls all of the content events (30041s and 30818s for wiki pages), in the order in which they are indexed, and displays them as a single document.
</P>
<P class="mb-3">
Each 30041 section is also a level in the table of contents, which can be accessed from the floating icon top-left in the reading view. This allows for navigation within the publication. (This functionality has been temporarily disabled.)
Each content section (30041 or 30818) is also a level in the table of contents, which can be accessed from the floating icon top-left in the reading view. This allows for navigation within the publication. (This functionality has been temporarily disabled.)
</P>
<div class="flex flex-col items-center space-y-4 my-4">
@ -93,6 +103,16 @@ @@ -93,6 +103,16 @@
<div class="flex justify-center my-4">
<Img src="/screenshots/Documentation.png" alt="Documentation" class='image-border rounded-lg' width="400" />
</div>
<Heading tag='h3' class='h-leather mb-3'>For wiki pages</Heading>
<P class="mb-3">
Alexandria now supports wiki pages (kind 30818), allowing for collaborative knowledge bases and documentation. Wiki pages use the same Asciidoc format as other publications but are specifically designed for interconnected, evolving content.
</P>
<P class="mb-3">
Wiki pages can be linked to from other publications and can contain links to other wiki pages, creating a web of knowledge that can be navigated and explored.
</P>
</main>
</div>

46
src/routes/publication/+page.svelte

@ -4,20 +4,62 @@ @@ -4,20 +4,62 @@
import type { PageData } from "./$types";
import { onDestroy, setContext } from "svelte";
import { PublicationTree } from "$lib/data_structures/publication_tree";
import { page } from "$app/stores";
let { data }: { data: PageData } = $props();
// Extend the PageData type with the properties we need
interface ExtendedPageData extends PageData {
waitable: Promise<any>;
publicationType: string;
indexEvent: NDKEvent;
parser: any;
}
const publicationTree = new PublicationTree(data.publicationRootEvent, data.ndk);
setContext('publicationTree', publicationTree);
let { data } = $props<{ data: ExtendedPageData }>();
// Get publication metadata for OpenGraph tags
let title = $derived(data.indexEvent?.getMatchingTags('title')[0]?.[1] || data.parser?.getIndexTitle(data.parser?.getRootIndexId()) || 'Alexandria Publication');
let currentUrl = $page.url.href;
// Get image and summary from the event tags if available
// If image unavailable, use the Alexandria default pic.
let image = $derived(data.indexEvent?.getMatchingTags('image')[0]?.[1] || '/screenshots/old_books.jpg');
let summary = $derived(data.indexEvent?.getMatchingTags('summary')[0]?.[1] || 'Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.');
onDestroy(() => data.parser.reset());
</script>
<svelte:head>
<!-- Basic meta tags -->
<title>{title}</title>
<meta name="description" content="{summary}" />
<!-- OpenGraph meta tags -->
<meta property="og:title" content="{title}" />
<meta property="og:description" content="{summary}" />
<meta property="og:url" content="{currentUrl}" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Alexandria" />
<meta property="og:image" content="{image}" />
<!-- Twitter Card meta tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{title}" />
<meta name="twitter:description" content="{summary}" />
<meta name="twitter:image" content="{image}" />
</svelte:head>
<main>
{#await data.waitable}
<TextPlaceholder divClass='skeleton-leather w-full' size="xxl" />
{:then}
<Article rootId={data.parser.getRootIndexId()} publicationType={data.publicationType} />
<Article
rootId={data.parser.getRootIndexId()}
publicationType={data.publicationType}
indexEvent={data.indexEvent}
/>
{/await}
</main>

6
src/routes/publication/+page.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { error } from '@sveltejs/kit';
import type { Load } from '@sveltejs/kit';
import type { NDKEvent } from '@nostr-dev-kit/ndk';
import type { PageLoad } from './$types';
import { nip19 } from 'nostr-tools';
import { getActiveRelays } from '$lib/ndk.ts';
@ -82,7 +82,7 @@ async function fetchEventByDTag(ndk: any, dTag: string): Promise<NDKEvent> { @@ -82,7 +82,7 @@ async function fetchEventByDTag(ndk: any, dTag: string): Promise<NDKEvent> {
}
}
export const load: PageLoad = async ({ url, parent }: { url: URL; parent: () => Promise<any> }) => {
export const load: Load = async ({ url, parent }: { url: URL; parent: () => Promise<any> }) => {
const id = url.searchParams.get('id');
const dTag = url.searchParams.get('d');
const { ndk, parser } = await parent();
@ -102,6 +102,6 @@ export const load: PageLoad = async ({ url, parent }: { url: URL; parent: () => @@ -102,6 +102,6 @@ export const load: PageLoad = async ({ url, parent }: { url: URL; parent: () =>
return {
waitable: fetchPromise,
publicationType,
publicationRootEvent: indexEvent,
indexEvent,
};
};

71
src/routes/visualize/+page.svelte

@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
// Fetch the referenced content events
const contentEvents = await $ndkInstance.fetchEvents(
{
kinds: [30041],
kinds: [30041, 30818],
ids: Array.from(contentEventIds),
},
{
@ -79,44 +79,45 @@ @@ -79,44 +79,45 @@
</script>
<div class="leather w-full p-4 relative">
<h1 class="h-leather text-2xl font-bold mb-4">Publication Network</h1>
<!-- Settings Toggle Button -->
<!-- Settings Button - Using Flowbite Components -->
{#if !loading && !error}
<Button
class="btn-leather fixed right-4 top-24 z-40 rounded-lg min-w-[150px]"
size="sm"
on:click={() => (showSettings = !showSettings)}
>
<CogSolid class="mr-2 h-5 w-5" />
Settings
</Button>
<div class="flex items-center gap-4 mb-4">
<h1 class="h-leather text-2xl font-bold">Publication Network</h1>
<!-- Settings Button - Using Flowbite Components -->
{#if !loading && !error}
<Button
class="btn-leather z-10 rounded-lg min-w-[120px]"
on:click={() => (showSettings = !showSettings)}
>
<CogSolid class="mr-2 h-5 w-5" />
Settings
</Button>
{/if}
</div>
{#if !loading && !error && showSettings}
<!-- Settings Panel -->
{#if showSettings}
<div
class="fixed right-0 top-[140px] h-auto w-80 bg-white dark:bg-gray-800 p-4 shadow-lg z-30
overflow-y-auto max-h-[calc(100vh-96px)] rounded-l-lg border-l border-t border-b
border-gray-200 dark:border-gray-700"
transition:fly={{ duration: 300, x: 320, opacity: 1, easing: quintOut }}
>
<div class="card space-y-4">
<h2 class="text-xl font-bold mb-4 h-leather">
Visualization Settings
</h2>
<div
class="absolute left-[220px] top-14 h-auto w-80 bg-white dark:bg-gray-800 p-4 shadow-lg z-10
overflow-y-auto max-h-[calc(100vh-96px)] rounded-lg border
border-gray-200 dark:border-gray-700"
transition:fly={{ duration: 300, y: -10, opacity: 1, easing: quintOut }}
>
<div class="card space-y-4">
<h2 class="text-xl font-bold mb-4 h-leather">
Visualization Settings
</h2>
<div class="space-y-4">
<span class="text-sm text-gray-600 dark:text-gray-400">
Showing {events.length} events from {$networkFetchLimit} headers
</span>
<EventLimitControl on:update={handleLimitUpdate} />
<EventRenderLevelLimit on:update={handleLimitUpdate} />
</div>
<div class="space-y-4">
<span class="text-sm text-gray-600 dark:text-gray-400">
Showing {events.length} events from {$networkFetchLimit} headers
</span>
<EventLimitControl on:update={handleLimitUpdate} />
<EventRenderLevelLimit on:update={handleLimitUpdate} />
</div>
</div>
{/if}
</div>
{/if}
{#if loading}
<div class="flex justify-center items-center h-64">
<div role="status">
@ -155,6 +156,6 @@ @@ -155,6 +156,6 @@
</div>
{:else}
<EventNetwork {events} />
<div class="mt-8 prose dark:prose-invert max-w-none" />
<div class="mt-8 prose dark:prose-invert max-w-none"></div>
{/if}
</div>
</div>

BIN
static/favicon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
static/screenshots/old_books.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

21
vite.config.ts

@ -1,5 +1,22 @@ @@ -1,5 +1,22 @@
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import { execSync } from "child_process";
// Function to get the latest git tag
function getAppVersionString() {
// if running in ci context, we can assume the package has been properly versioned
if (process.env.ALEXANDIRA_IS_CI_BUILD && process.env.npm_package_version && process.env.npm_package_version.trim() !== '') {
return process.env.npm_package_version;
}
try {
// Get the latest git tag, assuming git is installed and tagged branch is available
const tag = execSync('git describe --tags --abbrev=0').toString().trim();
return tag;
} catch (error) {
return 'development';
}
}
export default defineConfig({
plugins: [sveltekit()],
@ -11,5 +28,9 @@ export default defineConfig({ @@ -11,5 +28,9 @@ export default defineConfig({
},
test: {
include: ['./tests/unit/**/*.unit-test.js']
},
define: {
// Expose the app version as a global variable
'import.meta.env.APP_VERSION': JSON.stringify(getAppVersionString())
}
});

Loading…
Cancel
Save