Compare commits
8 commits
4ce02977eb
...
26714cb341
Author | SHA1 | Date | |
---|---|---|---|
26714cb341 | |||
e3bb1fe499 | |||
c520fb2490 | |||
838e3323ce | |||
2d0929c1fc | |||
3303165624 | |||
53679215a4 | |||
a8e7bd38b3 |
5 changed files with 95 additions and 101 deletions
|
@ -1,4 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import CloseIcon from "eva-icons/fill/svg/close.svg";
|
||||||
|
|
||||||
export let onClose: () => void;
|
export let onClose: () => void;
|
||||||
|
|
||||||
function click(this: Element, event: Event) {
|
function click(this: Element, event: Event) {
|
||||||
|
@ -22,9 +24,14 @@
|
||||||
|
|
||||||
<div class="content-alignment" on:click={click} on:keydown={keydown}>
|
<div class="content-alignment" on:click={click} on:keydown={keydown}>
|
||||||
<div class="content shadow-xl">
|
<div class="content shadow-xl">
|
||||||
|
<div class="mb-3 flex items-center justify-between">
|
||||||
<h3 class="text-2xl" id="modal-title">
|
<h3 class="text-2xl" id="modal-title">
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
</h3>
|
</h3>
|
||||||
|
<button on:click={onClose}
|
||||||
|
><CloseIcon class="h-10 w-10 fill-current" /></button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
<!--<div
|
<!--<div
|
||||||
class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"
|
class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"
|
||||||
|
@ -123,14 +130,8 @@
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: 100%;
|
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -75,59 +75,23 @@
|
||||||
$: links = getLinks(state.selection.$to.parent);
|
$: links = getLinks(state.selection.$to.parent);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="linking">
|
<div class="mx-auto w-full max-w-7xl overflow-x-auto">
|
||||||
<div class="links">
|
<div class="flex min-w-min">
|
||||||
{#each links as link}
|
{#each links as link}
|
||||||
<a
|
<a
|
||||||
|
class="m-1 flex max-w-[45vw] items-center gap-1 rounded-full border border-neutral-200 bg-white px-4 py-3 no-underline dark:border-neutral-500 dark:bg-neutral-800"
|
||||||
href={"href" in link ? link.href : link.id}
|
href={"href" in link ? link.href : link.id}
|
||||||
target={link.type === "external" ? "_blank" : null}
|
target={link.type === "external" ? "_blank" : null}
|
||||||
>
|
>
|
||||||
{#if link.type === "internal"}
|
{#if link.type === "internal"}
|
||||||
<InternalLinkIcon />
|
<InternalLinkIcon class="h-5 w-5 shrink-0 fill-current" />
|
||||||
{:else}
|
{:else}
|
||||||
<LinkIcon />
|
<LinkIcon class="h-5 w-5 shrink-0 fill-current" />
|
||||||
{/if}
|
{/if}
|
||||||
<span>{link.content}</span>
|
<span class="overflow-hidden text-ellipsis whitespace-nowrap"
|
||||||
|
>{link.content}</span
|
||||||
|
>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
.linking {
|
|
||||||
max-width: 1280px;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
.links {
|
|
||||||
display: flex;
|
|
||||||
min-width: min-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
background: ButtonFace;
|
|
||||||
color: ButtonText;
|
|
||||||
padding: 0.7em 1em;
|
|
||||||
margin: 0.3em;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.25em;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 2em;
|
|
||||||
text-decoration: none;
|
|
||||||
max-width: 45vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
a > span {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.linking :global(svg) {
|
|
||||||
fill: currentColor;
|
|
||||||
width: 1.25em;
|
|
||||||
height: 1.25em;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ class BreadcrumbsStore {
|
||||||
} else {
|
} else {
|
||||||
crumbs.push(pageId);
|
crumbs.push(pageId);
|
||||||
}
|
}
|
||||||
|
if (crumbs.includes("index")) {
|
||||||
|
crumbs = crumbs.slice(crumbs.indexOf("index"));
|
||||||
|
}
|
||||||
map.set(worldId, crumbs);
|
map.set(worldId, crumbs);
|
||||||
return map;
|
return map;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,34 +1,15 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { XmlFragment } from "yjs";
|
import type { XmlFragment } from "yjs";
|
||||||
import { inject } from "regexparam";
|
import { inject } from "regexparam";
|
||||||
import ChevronRight from "eva-icons/fill/svg/chevron-right.svg";
|
|
||||||
import Editor from "../editor/Editor.svelte";
|
import Editor from "../editor/Editor.svelte";
|
||||||
import { getWorldPage, getWorldY, type WorldY } from "../lib/doc";
|
import { getWorldPage, getWorldY, type WorldY } from "../lib/doc";
|
||||||
import { routes } from "../lib/routes";
|
import { routes } from "../lib/routes";
|
||||||
import { loadWorlds } from "../lib/worldStorage";
|
import { loadWorlds } from "../lib/worldStorage";
|
||||||
import breadcrumbs from "../lib/breadcrumbs";
|
import Breadcrumbs from "./Page/Breadcrumbs.svelte";
|
||||||
import { pageStore } from "../lib/makeYdocStore";
|
|
||||||
import { derived } from "svelte/store";
|
|
||||||
import { getTitle } from "../lib/getTitle";
|
|
||||||
|
|
||||||
export let worldId: string;
|
export let worldId: string;
|
||||||
export let pageId: string;
|
export let pageId: string;
|
||||||
|
|
||||||
$: pageBreadcrumbs = breadcrumbs.worldStore(worldId);
|
|
||||||
$: crumbsTitles = derived(
|
|
||||||
[pageBreadcrumbs],
|
|
||||||
([crumbs], set: (val: (string | undefined)[]) => void) => {
|
|
||||||
return derived(
|
|
||||||
crumbs.map((c) => pageStore(worldId, c)),
|
|
||||||
(crumbPages) =>
|
|
||||||
crumbPages.map(
|
|
||||||
(x, index) =>
|
|
||||||
x && x.doc && getTitle(x.doc, `page/${crumbs[index]}`),
|
|
||||||
),
|
|
||||||
).subscribe(set);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
async function loadDoc(
|
async function loadDoc(
|
||||||
worldId: string,
|
worldId: string,
|
||||||
pageId: string,
|
pageId: string,
|
||||||
|
@ -67,28 +48,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<!-- https://devdojo.com/pines/docs/breadcrumbs -->
|
<Breadcrumbs {pageId} {worldId} />
|
||||||
<div
|
|
||||||
class="flex justify-between rounded-md border border-neutral-200/60 px-3.5 py-1"
|
|
||||||
>
|
|
||||||
<ol
|
|
||||||
class="inline-flex items-center space-x-1 text-xs text-neutral-500 sm:mb-0 [&_.active-breadcrumb]:font-medium [&_.active-breadcrumb]:text-neutral-600"
|
|
||||||
>
|
|
||||||
{#each $pageBreadcrumbs as crumb, index}
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href={inject(routes.Page, { worldId, pageId: crumb })}
|
|
||||||
class="inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none"
|
|
||||||
class:active-breadcrumb={crumb === pageId}
|
|
||||||
>{$crumbsTitles[index] || crumb}</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
{#if index !== $pageBreadcrumbs.length - 1}
|
|
||||||
<ChevronRight class="h-5 w-5 fill-current text-gray-400/70" />
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{#if state === "loading"}Cargando...{:else if "doc" in state}
|
{#if state === "loading"}Cargando...{:else if "doc" in state}
|
||||||
|
@ -97,9 +57,3 @@
|
||||||
{state.error}
|
{state.error}
|
||||||
<a href={routes.ChooseWorld}>Volver al inicio</a>
|
<a href={routes.ChooseWorld}>Volver al inicio</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
|
||||||
nav a {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
72
src/views/Page/Breadcrumbs.svelte
Normal file
72
src/views/Page/Breadcrumbs.svelte
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount, tick } from "svelte";
|
||||||
|
import ChevronRight from "eva-icons/fill/svg/chevron-right.svg";
|
||||||
|
import { inject } from "regexparam";
|
||||||
|
import breadcrumbs from "../../lib/breadcrumbs";
|
||||||
|
import { pageStore } from "../../lib/makeYdocStore";
|
||||||
|
import { derived } from "svelte/store";
|
||||||
|
import { getTitle } from "../../lib/getTitle";
|
||||||
|
import { routes } from "../../lib/routes";
|
||||||
|
|
||||||
|
export let worldId: string;
|
||||||
|
export let pageId: string;
|
||||||
|
|
||||||
|
$: pageBreadcrumbs = breadcrumbs.worldStore(worldId);
|
||||||
|
$: crumbsTitles = derived(
|
||||||
|
[pageBreadcrumbs],
|
||||||
|
([crumbs], set: (val: (string | undefined)[]) => void) => {
|
||||||
|
return derived(
|
||||||
|
crumbs.map((c) => pageStore(worldId, c)),
|
||||||
|
(crumbPages) =>
|
||||||
|
crumbPages.map(
|
||||||
|
(x, index) =>
|
||||||
|
x && x.doc && getTitle(x.doc, `page/${crumbs[index]}`),
|
||||||
|
),
|
||||||
|
).subscribe(set);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let breadcrumbsEl: HTMLDivElement;
|
||||||
|
const crumbsScrollToEnd = async () => {
|
||||||
|
await tick();
|
||||||
|
breadcrumbsEl?.scroll({
|
||||||
|
left: breadcrumbsEl.scrollWidth,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
crumbsScrollToEnd();
|
||||||
|
});
|
||||||
|
$: {
|
||||||
|
$crumbsTitles;
|
||||||
|
$pageBreadcrumbs;
|
||||||
|
crumbsScrollToEnd();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- https://devdojo.com/pines/docs/breadcrumbs -->
|
||||||
|
<div
|
||||||
|
class="flex justify-between overflow-x-auto rounded-md border border-neutral-200/60 px-3.5 py-1 dark:border-neutral-700"
|
||||||
|
bind:this={breadcrumbsEl}
|
||||||
|
>
|
||||||
|
<ol
|
||||||
|
class="inline-flex items-center space-x-1 text-xs text-neutral-500 dark:text-neutral-300 sm:mb-0 [&_.active-breadcrumb]:font-medium [&_.active-breadcrumb]:text-neutral-600 dark:[&_.active-breadcrumb]:text-neutral-200"
|
||||||
|
>
|
||||||
|
{#each $pageBreadcrumbs as crumb, index}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href={inject(routes.Page, { worldId, pageId: crumb })}
|
||||||
|
class="font-norma inline-flex items-center text-ellipsis whitespace-nowrap py-1 focus:outline-none"
|
||||||
|
class:active-breadcrumb={crumb === pageId}
|
||||||
|
>{$crumbsTitles[index] || crumb}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{#if index !== $pageBreadcrumbs.length - 1}
|
||||||
|
<ChevronRight
|
||||||
|
class="h-5 w-5 fill-current text-gray-400/70 dark:text-gray-500"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
</div>
|
Loading…
Reference in a new issue