Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
788 changes: 475 additions & 313 deletions demo/package-lock.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@sveltejs/vite-plugin-svelte": "^6.1.3",
"@tsconfig/svelte": "^5.0.4",
"sass": "^1.83.4",
"svelte": "^5.15.0",
"svelte-check": "^4.1.1",
"typescript": "^5.7.3",
"vite": "^6.0.5"
"vite": "^7.1.3"
},
"dependencies": {
"@floating-ui/dom": "^1.7.4",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3"
"bootstrap-icons": "^1.11.3",
"svelte-highlight": "^7.8.3"
}
}
31 changes: 26 additions & 5 deletions demo/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
<script lang="ts">
import './app.scss';
import NavBar from './lib/NavBar.svelte';
import Tooltip from './lib/Tooltip.svelte';
import { Router, Route, Fallback, RouterTrace } from '@wjfe/n-savant';
import NotFound from './lib/NotFound.svelte';
import HomeView from './lib/views/home/HomeView.svelte';
import PathRoutingView from './lib/views/path-routing/PathRoutingView.svelte';
import HashRoutingView from './lib/views/hash-routing/HashRoutingView.svelte';
</script>

<svelte:head>
<script src="node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</svelte:head>
let showNavTooltip = $state(false);

// Show toolti<p after a short delay when app loads
$effect(() => {
const timer = setTimeout(() => {
showNavTooltip = true;
}, 2000);

// Hide tooltip after 10 seconds or when user interacts
const hideTimer = setTimeout(() => {
showNavTooltip = false;
}, 12000);

return () => {
clearTimeout(timer);
clearTimeout(hideTimer);
};
});
</script>

<div class="app">
<div class="d-flex flex-column h-100">
<Router id="root">
<NavBar />
<Tooltip shown={showNavTooltip} placement="bottom">
{#snippet reference(ref)}
<NavBar {@attach ref} />
{/snippet}
Use these navigation links to test-drive the routing capabilities of @wjfe/n-savant.
</Tooltip>
<main class="d-flex flex-column flex-fill overflow-auto mt-3">
<div class="container-fluid flex-fill d-flex flex-column">
<div class="grid flex-fill">
Expand Down
141 changes: 141 additions & 0 deletions demo/src/lib/CodeSnippet.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import Highlight, { type LanguageType } from 'svelte-highlight';
import 'svelte-highlight/styles/github.css';

interface Props extends HTMLAttributes<HTMLDivElement> {
language: LanguageType<string>;
code: string;
title?: string;
copyable?: boolean;
}

let { language, code, title, copyable = true, class: cssClass, ...restProps }: Props = $props();

let copied = $state(false);

async function copyToClipboard() {
try {
await navigator.clipboard.writeText(code);
copied = true;
setTimeout(() => {
copied = false;
}, 2000);
} catch (err) {
console.error('Failed to copy code: ', err);
}
}
</script>

<div class={['code-snippet', cssClass]} {...restProps}>
{#if title || copyable}
<div class="code-snippet-header">
{#if title}
<span class="code-snippet-title">{title}</span>
{/if}
{#if copyable}
<button
type="button"
class="btn btn-sm btn-outline-secondary copy-btn"
onclick={copyToClipboard}
disabled={copied}
>
{#if copied}
<i class="bi bi-check"></i> Copied!
{:else}
<i class="bi bi-clipboard"></i> Copy
{/if}
</button>
{/if}
</div>
{/if}
<div class="code-snippet-content">
<Highlight {language} {code} />
</div>
</div>

<!--
@component
# CodeSnippet
A syntax-highlighted code block with optional title and copy functionality.

## Props
- `language` (LanguageType): The language for syntax highlighting
- `code` (string): The code content to display
- `title` (string, optional): Optional title for the code snippet
- `copyable` (boolean, default: true): Whether to show the copy button

## Usage
```svelte
<script>
import CodeSnippet from './lib/CodeSnippet.svelte';
import typescript from "svelte-highlight/languages/typescript";
</script>

<CodeSnippet
language={typescript}
code="console.log('Hello, world!');"
title="Example"
/>
```
-->

<style>
.code-snippet {
border: 1px solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
background-color: var(--bs-body-bg);
margin: 1rem 0;
overflow: hidden;
}

.code-snippet-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 1rem;
background-color: var(--bs-light);
border-bottom: 1px solid var(--bs-border-color);
font-size: 0.875rem;
}

.code-snippet-title {
font-weight: 600;
color: var(--bs-secondary);
}

.copy-btn {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
transition: all 0.2s ease;
}

.copy-btn:disabled {
color: var(--bs-success);
border-color: var(--bs-success);
}

.code-snippet-content {
position: relative;
}

.code-snippet-content :global(pre) {
margin: 0 !important;
padding: 1rem !important;
background-color: transparent !important;
border: none !important;
border-radius: 0 !important;
}

.code-snippet-content :global(code) {
background-color: transparent !important;
}

/* Dark mode support */
@media (prefers-color-scheme: dark) {
.code-snippet-header {
background-color: var(--bs-dark);
border-bottom-color: var(--bs-secondary);
}
}
</style>
15 changes: 10 additions & 5 deletions demo/src/lib/NavBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@
import { Link, Route } from '@wjfe/n-savant';
import SubNav from './SubNav.svelte';
import { routingMode } from './hash-routing';
import type { HTMLAttributes } from 'svelte/elements';

let {
...restProps
}: HTMLAttributes<HTMLElement> = $props();

const pathRoutingLinks = [
{ text: 'Home', href: '/path-routing' },
{ text: 'Demo', href: '/path-routing/demo' }
{ text: 'Start Demo', href: '/path-routing/demo' }
];
const hashRoutingLinks = [
{ text: 'Home', href: '/hash-routing' },
{
text: 'Demo',
text: 'Start Demo',
href: '/hash-routing#' + (routingMode === 'multi' ? 'd1=/demo;d2=/demo' : '/demo')
}
];
</script>

<nav class="navbar navbar-expand-lg bg-primary-subtle">
<nav class="navbar navbar-expand-lg bg-primary-subtle" {...restProps}>
<div class="container-fluid">
<Link class="navbar-brand fw-bold" href="/">
<Link class="navbar-brand fw-bold" href="/" id="logoLink">
<svg style:height="1.7em" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- Outer circle -->
<circle cx="50" cy="50" r="48" stroke="black" stroke-width="2" fill="none" />
Expand Down Expand Up @@ -57,7 +62,7 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<Link class="nav-link" activeState={{ class: 'active', key: 'home' }} href="/">Home</Link>
<Link class="nav-link" activeState={{ class: 'active', key: 'home' }} href="/" id="homeLink">Home</Link>
</li>
<Route key="homeMenuPr" when={(rs) => !rs.pathRouting?.match}>
<li class="nav-item">
Expand Down
Loading