From 9de04b8be40e6fb95c52064904fce2ee8d009c6b Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Wed, 20 Mar 2024 10:52:34 -0400 Subject: [PATCH 01/28] Adds private value onto Project structure --- src/structure/project.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/structure/project.js b/src/structure/project.js index aaa7ee00e..19b78a276 100644 --- a/src/structure/project.js +++ b/src/structure/project.js @@ -31,6 +31,9 @@ export class Project extends Svue { description(project) { return project.description; }, + private(project) { + return project.private; + }, editAccess(project) { if (project.edit_access == null) return false; return project.edit_access; From 2ce0e5649949aaf2045c52fe089fa66348f29243 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 21 Mar 2024 16:00:12 -0400 Subject: [PATCH 02/28] Basic viewer layout --- .gitignore | 1 + src/lib/api/documents.ts | 5 +- src/lib/api/projects.test.js | 2 +- .../{sections.test.js => sections.test.ts} | 0 src/lib/api/{sections.js => sections.ts} | 0 src/lib/components/common/Metadata.svelte | 26 +++++++++ .../common/stories/Metadata.stories.svelte | 23 ++++++++ .../documents/[id]-[slug]/+layout.svelte | 42 +++++++++----- .../[id]-[slug]/{+layout.js => +layout.ts} | 2 +- .../[id]-[slug]/{+page.js => +page.ts} | 8 +-- .../sidebar/DocumentMetadata.svelte | 57 +++++++++++++++++++ src/style/kit.css | 19 +++++++ 12 files changed, 163 insertions(+), 22 deletions(-) rename src/lib/api/{sections.test.js => sections.test.ts} (100%) rename src/lib/api/{sections.js => sections.ts} (100%) create mode 100644 src/lib/components/common/Metadata.svelte create mode 100644 src/lib/components/common/stories/Metadata.stories.svelte rename src/routes/documents/[id]-[slug]/{+layout.js => +layout.ts} (89%) rename src/routes/documents/[id]-[slug]/{+page.js => +page.ts} (54%) create mode 100644 src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte diff --git a/.gitignore b/.gitignore index c95090079..c0f6cdf0e 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ tests/fixtures/development.json .vscode vite.config.js.timestamp-* vite.config.ts.timestamp-* +*.log # sveltekit /build diff --git a/src/lib/api/documents.ts b/src/lib/api/documents.ts index bf28c52e3..baeb07360 100644 --- a/src/lib/api/documents.ts +++ b/src/lib/api/documents.ts @@ -1,10 +1,13 @@ /** API helpers related to documents. * Lots of duplicated code here that should get consolidated at some point. */ +import type { Document } from "./types"; + import { error } from "@sveltejs/kit"; -import { APP_URL, BASE_API_URL } from "@/config/config.js"; + import { DEFAULT_EXPAND } from "@/api/common.js"; import { isOrg } from "@/api/types/orgAndUser"; +import { APP_URL, BASE_API_URL } from "@/config/config.js"; import { isErrorCode } from "../utils"; /** Search documents */ diff --git a/src/lib/api/projects.test.js b/src/lib/api/projects.test.js index c4bfc8ec1..9e44e0a84 100644 --- a/src/lib/api/projects.test.js +++ b/src/lib/api/projects.test.js @@ -1,6 +1,6 @@ import { describe, test, expect } from "vitest"; -import * as projects from "./projects.js"; +import * as projects from "./projects"; describe("project tests", () => { test.todo("projects.get"); diff --git a/src/lib/api/sections.test.js b/src/lib/api/sections.test.ts similarity index 100% rename from src/lib/api/sections.test.js rename to src/lib/api/sections.test.ts diff --git a/src/lib/api/sections.js b/src/lib/api/sections.ts similarity index 100% rename from src/lib/api/sections.js rename to src/lib/api/sections.ts diff --git a/src/lib/components/common/Metadata.svelte b/src/lib/components/common/Metadata.svelte new file mode 100644 index 000000000..4e1aaf37e --- /dev/null +++ b/src/lib/components/common/Metadata.svelte @@ -0,0 +1,26 @@ + + + + + diff --git a/src/lib/components/common/stories/Metadata.stories.svelte b/src/lib/components/common/stories/Metadata.stories.svelte new file mode 100644 index 000000000..3630ce0d6 --- /dev/null +++ b/src/lib/components/common/stories/Metadata.stories.svelte @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/src/routes/documents/[id]-[slug]/+layout.svelte b/src/routes/documents/[id]-[slug]/+layout.svelte index 3019b78af..b14863fe8 100644 --- a/src/routes/documents/[id]-[slug]/+layout.svelte +++ b/src/routes/documents/[id]-[slug]/+layout.svelte @@ -1,38 +1,50 @@ - + - {#if data.document.noindex || data.document.admin_noindex} + {#if document.noindex || document.admin_noindex} {/if} - - - - {data.document.title} - DocumentCloud + + + + {document.title} - DocumentCloud - {#if data.document?.description?.trim().length > 0} - + {#if document?.description?.trim().length > 0} + {/if} - + -

{data.document.title}

+ + + + + + - + + diff --git a/src/routes/documents/[id]-[slug]/+layout.js b/src/routes/documents/[id]-[slug]/+layout.ts similarity index 89% rename from src/routes/documents/[id]-[slug]/+layout.js rename to src/routes/documents/[id]-[slug]/+layout.ts index ee4225464..6fadec7d2 100644 --- a/src/routes/documents/[id]-[slug]/+layout.js +++ b/src/routes/documents/[id]-[slug]/+layout.ts @@ -9,7 +9,7 @@ import * as documents from "@/lib/api/documents"; /** @type {import('./$types').PageLoad} */ export async function load({ fetch, params }) { - const document = await documents.get(params.id, fetch); + const document = await documents.get(+params.id, fetch); if (document.slug !== params.slug) { const canonical = new URL(document.canonical_url); diff --git a/src/routes/documents/[id]-[slug]/+page.js b/src/routes/documents/[id]-[slug]/+page.ts similarity index 54% rename from src/routes/documents/[id]-[slug]/+page.js rename to src/routes/documents/[id]-[slug]/+page.ts index f8fe39cec..179c39ad5 100644 --- a/src/routes/documents/[id]-[slug]/+page.js +++ b/src/routes/documents/[id]-[slug]/+page.ts @@ -1,12 +1,12 @@ /** Load notes and sections for viewing a single document */ -import * as notes from "$lib/api/notes.js"; -import * as sections from "$lib/api/sections.js"; +import * as notes from "$lib/api/notes"; +import * as sections from "$lib/api/sections"; /** @type {import('./$types').PageLoad} */ export async function load({ params, fetch }) { // stream these, because we can wait on them return { - notes: notes.list(params.id, fetch), - sections: sections.list(params.id, fetch), + notes: notes.list(+params.id, fetch), + sections: sections.list(+params.id, fetch), }; } diff --git a/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte b/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte new file mode 100644 index 000000000..255904037 --- /dev/null +++ b/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte @@ -0,0 +1,57 @@ + + + + + +

{document.title}

+ + + Edit + +
+ +

+ {document.description} +

+ + + + + + + + + + +
diff --git a/src/style/kit.css b/src/style/kit.css index a084aedd9..dd24c3346 100644 --- a/src/style/kit.css +++ b/src/style/kit.css @@ -120,3 +120,22 @@ h5 { p { font-size: var(--font-m); } + +dl, +dt, +dd { + font-size: var(--font-m); + margin: 0; +} + +dt { + color: var(--gray-5, #233944); + font-size: 0.75rem; + font-weight: var(--font-semibold, 600); +} + +dd { + color: var(--gray-5, #233944); + font-size: 0.875rem; + font-weight: var(--font-regular, 400); +} From aa5c7f42a6e15079eae4a4f0f0b32c2f6e20962d Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 21 Mar 2024 16:20:43 -0400 Subject: [PATCH 03/28] Sections.svelte --- src/lib/api/documents.ts | 2 +- .../documents/[id]-[slug]/+layout.svelte | 3 +++ src/routes/documents/[id]-[slug]/+page.ts | 2 -- .../[id]-[slug]/sidebar/Sections.svelte | 25 +++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/routes/documents/[id]-[slug]/sidebar/Sections.svelte diff --git a/src/lib/api/documents.ts b/src/lib/api/documents.ts index baeb07360..172877675 100644 --- a/src/lib/api/documents.ts +++ b/src/lib/api/documents.ts @@ -40,7 +40,7 @@ export async function get( fetch: typeof globalThis.fetch, ): Promise { const endpoint = new URL(`documents/${id}.json`, BASE_API_URL); - const expand = ["user", "organization", "projects", "revisions"]; + const expand = ["user", "organization", "projects", "revisions", "sections"]; endpoint.searchParams.set("expand", expand.join(",")); const resp = await fetch(endpoint, { credentials: "include" }); diff --git a/src/routes/documents/[id]-[slug]/+layout.svelte b/src/routes/documents/[id]-[slug]/+layout.svelte index b14863fe8..7e7719ecb 100644 --- a/src/routes/documents/[id]-[slug]/+layout.svelte +++ b/src/routes/documents/[id]-[slug]/+layout.svelte @@ -3,6 +3,7 @@ import MainLayout from "$lib/components/MainLayout.svelte"; import DocumentMetadata from "./sidebar/DocumentMetadata.svelte"; + import Sections from "./sidebar/Sections.svelte"; import { embedUrl } from "@/api/embed.js"; import { pageImageUrl } from "@/api/viewer.js"; @@ -42,6 +43,8 @@ + + diff --git a/src/routes/documents/[id]-[slug]/+page.ts b/src/routes/documents/[id]-[slug]/+page.ts index 179c39ad5..5d274b196 100644 --- a/src/routes/documents/[id]-[slug]/+page.ts +++ b/src/routes/documents/[id]-[slug]/+page.ts @@ -1,12 +1,10 @@ /** Load notes and sections for viewing a single document */ import * as notes from "$lib/api/notes"; -import * as sections from "$lib/api/sections"; /** @type {import('./$types').PageLoad} */ export async function load({ params, fetch }) { // stream these, because we can wait on them return { notes: notes.list(+params.id, fetch), - sections: sections.list(+params.id, fetch), }; } diff --git a/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte b/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte new file mode 100644 index 000000000..985365896 --- /dev/null +++ b/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte @@ -0,0 +1,25 @@ + + + +

Sections

+ + {#each sections as section} + + {section.title} + + {:else} + +

Sections organize your document with a table of contents

+
+ {/each} +
From c85ff2b3472ffd0b6e127c839b9435b3dd260651 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 21 Mar 2024 17:08:08 -0400 Subject: [PATCH 04/28] Data and Projects sidebar components --- .../documents/[id]-[slug]/+layout.svelte | 9 ++++++ .../documents/[id]-[slug]/sidebar/Data.svelte | 30 +++++++++++++++++++ .../[id]-[slug]/sidebar/Projects.svelte | 26 ++++++++++++++++ .../[id]-[slug]/sidebar/Sections.svelte | 5 +++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/routes/documents/[id]-[slug]/sidebar/Data.svelte create mode 100644 src/routes/documents/[id]-[slug]/sidebar/Projects.svelte diff --git a/src/routes/documents/[id]-[slug]/+layout.svelte b/src/routes/documents/[id]-[slug]/+layout.svelte index 7e7719ecb..28b7b55ef 100644 --- a/src/routes/documents/[id]-[slug]/+layout.svelte +++ b/src/routes/documents/[id]-[slug]/+layout.svelte @@ -1,8 +1,12 @@ @@ -45,6 +50,10 @@ + + + + diff --git a/src/routes/documents/[id]-[slug]/sidebar/Data.svelte b/src/routes/documents/[id]-[slug]/sidebar/Data.svelte new file mode 100644 index 000000000..f880d9760 --- /dev/null +++ b/src/routes/documents/[id]-[slug]/sidebar/Data.svelte @@ -0,0 +1,30 @@ + + + +

+ + Data & Tags +

+ + {#if empty} + +

Use tags or key/value data to organize documents

+
+ + {/if} +
diff --git a/src/routes/documents/[id]-[slug]/sidebar/Projects.svelte b/src/routes/documents/[id]-[slug]/sidebar/Projects.svelte new file mode 100644 index 000000000..cd82c6057 --- /dev/null +++ b/src/routes/documents/[id]-[slug]/sidebar/Projects.svelte @@ -0,0 +1,26 @@ + + + +

+ + Projects +

+ + {#each projects as project} + + {project.title} + + {:else} + Add this document to projects + {/each} +
diff --git a/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte b/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte index 985365896..1d36e11e5 100644 --- a/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte +++ b/src/routes/documents/[id]-[slug]/sidebar/Sections.svelte @@ -11,7 +11,10 @@ -

Sections

+

+ + Sections +

{#each sections as section} From a23e28bb8fabf996c4b02d5e95b0cdfcb21c4f57 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 21 Mar 2024 17:35:37 -0400 Subject: [PATCH 05/28] viewer sidebars --- .../documents/[id]-[slug]/+layout.svelte | 13 +++- src/routes/documents/[id]-[slug]/+layout.ts | 6 +- .../[id]-[slug]/sidebar/Actions.svelte | 62 +++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/routes/documents/[id]-[slug]/sidebar/Actions.svelte diff --git a/src/routes/documents/[id]-[slug]/+layout.svelte b/src/routes/documents/[id]-[slug]/+layout.svelte index 28b7b55ef..01a3bdd60 100644 --- a/src/routes/documents/[id]-[slug]/+layout.svelte +++ b/src/routes/documents/[id]-[slug]/+layout.svelte @@ -4,7 +4,12 @@ import type { Project } from "$lib/api/types"; import MainLayout from "$lib/components/MainLayout.svelte"; + import SignedIn from "$lib/components/common/SignedIn.svelte"; + + // sidebars import DocumentMetadata from "./sidebar/DocumentMetadata.svelte"; + import Actions from "./sidebar/Actions.svelte"; + import AddOns from "@/routes/app/sidebar/AddOns.svelte"; import Data from "./sidebar/Data.svelte"; import Projects from "./sidebar/Projects.svelte"; import Sections from "./sidebar/Sections.svelte"; @@ -58,5 +63,11 @@ - + + + + + + +
diff --git a/src/routes/documents/[id]-[slug]/+layout.ts b/src/routes/documents/[id]-[slug]/+layout.ts index 6fadec7d2..f404e07fb 100644 --- a/src/routes/documents/[id]-[slug]/+layout.ts +++ b/src/routes/documents/[id]-[slug]/+layout.ts @@ -6,6 +6,7 @@ import { redirect } from "@sveltejs/kit"; import * as documents from "@/lib/api/documents"; +import { getPinnedAddons } from "$lib/api/addons.js"; /** @type {import('./$types').PageLoad} */ export async function load({ fetch, params }) { @@ -16,5 +17,8 @@ export async function load({ fetch, params }) { redirect(302, canonical.pathname); } - return { document }; + // stream this + const pinnedAddons = getPinnedAddons(fetch); + + return { document, pinnedAddons }; } diff --git a/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte b/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte new file mode 100644 index 000000000..dca78f5bb --- /dev/null +++ b/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte @@ -0,0 +1,62 @@ + + + + + + {document.access} access + + + + + Revision History + + + + + Download PDF + + + + + + + Share … + + + + + Add a note … + + + + + Redact … + + + + + Modify Pages … + + + + From a59808ea78f90af5a517182dd3d6e04da541d2db Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Mon, 25 Mar 2024 15:30:52 -0400 Subject: [PATCH 06/28] Add sidebar links in viewer --- src/lib/api/documents.test.ts | 7 ++- src/lib/api/documents.ts | 51 ++++++++++--------- .../[id]-[slug]/annotate/+page.svelte | 0 .../documents/[id]-[slug]/redact/+page.svelte | 0 .../[id]-[slug]/sidebar/Actions.svelte | 45 +++++++++++++--- .../sidebar/DocumentMetadata.svelte | 18 ++++--- 6 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 src/routes/documents/[id]-[slug]/annotate/+page.svelte create mode 100644 src/routes/documents/[id]-[slug]/redact/+page.svelte diff --git a/src/lib/api/documents.test.ts b/src/lib/api/documents.test.ts index bbb95d713..f1f6079d9 100644 --- a/src/lib/api/documents.test.ts +++ b/src/lib/api/documents.test.ts @@ -2,7 +2,7 @@ import { describe, test as base, expect } from "vitest"; import { APP_URL, IMAGE_WIDTHS_ENTRIES } from "@/config/config.js"; import * as documents from "./documents"; -import type { Document } from "./types"; +import type { Document, sizes } from "./types"; type Use = (value: T) => Promise; @@ -51,7 +51,9 @@ describe("document helper methods", () => { test("pageImageUrl", ({ document }) => { const page = 1; IMAGE_WIDTHS_ENTRIES.forEach(([size, width]) => { - expect(documents.pageImageUrl(document, page, size)).toStrictEqual( + expect( + documents.pageImageUrl(document, page, size as sizes), + ).toStrictEqual( new URL( `documents/${document.id}/pages/${document.slug}-p${page}-${size}.gif`, document.asset_url, @@ -88,4 +90,5 @@ describe("document helper methods", () => { }); test.todo("userOrgString"); + test.todo("pdfUrl"); }); diff --git a/src/lib/api/documents.ts b/src/lib/api/documents.ts index 172877675..3dfb4baaa 100644 --- a/src/lib/api/documents.ts +++ b/src/lib/api/documents.ts @@ -1,7 +1,7 @@ /** API helpers related to documents. * Lots of duplicated code here that should get consolidated at some point. */ -import type { Document } from "./types"; +import type { Document, sizes } from "./types"; import { error } from "@sveltejs/kit"; @@ -77,7 +77,7 @@ export async function process() {} * @param {import('./types').Document} document * @returns {URL} */ -export function canonicalUrl(document) { +export function canonicalUrl(document: Document): URL { const path = `/documents/${document.id}-${document.slug}/`; return new URL(path, APP_URL); } @@ -91,7 +91,7 @@ export function canonicalUrl(document) { * @param {number} page * @returns {URL} */ -export function canonicalPageUrl(document, page) { +export function canonicalPageUrl(document: Document, page: number): URL { return new URL(`/documents/${document.id}/pages/${page}/`, APP_URL); } @@ -99,10 +99,8 @@ export function canonicalPageUrl(document, page) { * Generate the hash for a path, without the host or path * * @export - * @param {number} page - * @returns {URL} */ -export function pageHashUrl(page) { +export function pageHashUrl(page: number): string { return `#document/p${page}`; } @@ -114,7 +112,7 @@ export function pageHashUrl(page) { * @param {number} page * @returns {URL} */ -export function pageUrl(document, page) { +export function pageUrl(document: Document, page: number): URL { return new URL(pageHashUrl(page), canonicalUrl(document)); } @@ -127,7 +125,11 @@ export function pageUrl(document, page) { * @param {import('./types').sizes} size * @returns {URL} */ -export function pageImageUrl(document, page, size) { +export function pageImageUrl( + document: Document, + page: number, + size: sizes, +): URL { return new URL( `documents/${document.id}/pages/${document.slug}-p${page}-${size}.gif`, document.asset_url, @@ -138,11 +140,8 @@ export function pageImageUrl(document, page, size) { * Asset URL for page text * * @export - * @param {import('./types').Document} document - * @param {number} page - * @returns {URL} */ -export function textUrl(document, page) { +export function textUrl(document: Document, page: number): URL { return new URL( `documents/${document.id}/pages/${document.slug}-p${page}.txt`, document.asset_url, @@ -153,10 +152,8 @@ export function textUrl(document, page) { * Asset URL for JSON text * * @export - * @param {import('./types').Document} document - * @returns {URL} */ -export function jsonUrl(document) { +export function jsonUrl(document: Document): URL { return new URL( `documents/${document.id}/${document.slug}.txt.json`, document.asset_url, @@ -167,25 +164,33 @@ export function jsonUrl(document) { * Asset URL for text positions * * @export - * @param {import('./types').Document} document - * @param {number} page - * @returns {URL} */ -export function selectableTextUrl(document, page) { +export function selectableTextUrl(document: Document, page: number): URL { return new URL( `documents/${document.id}/pages/${document.slug}-p${page}.position.json`, document.asset_url, ); } +/** + * Generate URL for the PDF version of a document. + * This will always be a PDF, regardless of the original file type. + * + * @export + */ +export function pdfUrl(document: Document): URL { + return new URL( + `documents/${document.id}/${document.slug}.pdf`, + document.asset_url, + ); +} + /** * Generate a user (organization) string * * @export - * @param {import('./types').Document} document - * @returns {string} */ -export function userOrgString(document) { +export function userOrgString(document: Document): string { // we have an org and user if (isOrg(document.organization) && typeof document.user === "object") { return `${document.user.name} (${document.organization.name})`; @@ -193,7 +198,7 @@ export function userOrgString(document) { // just a user if (typeof document.user === "object") { - return document.user; + return document.user.name; } // nothing, so return nothing diff --git a/src/routes/documents/[id]-[slug]/annotate/+page.svelte b/src/routes/documents/[id]-[slug]/annotate/+page.svelte new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/documents/[id]-[slug]/redact/+page.svelte b/src/routes/documents/[id]-[slug]/redact/+page.svelte new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte b/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte index dca78f5bb..7adbc68d2 100644 --- a/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte +++ b/src/routes/documents/[id]-[slug]/sidebar/Actions.svelte @@ -8,28 +8,50 @@ EyeClosed16, History16, Lock16, + Pencil16, Share16, } from "svelte-octicons"; - import Flex from "@/lib/components/common/Flex.svelte"; - import SidebarItem from "@/lib/components/sidebar/SidebarItem.svelte"; + + import Action from "$lib/components/common/Action.svelte"; + import Flex from "$lib/components/common/Flex.svelte"; + import SignedIn from "$lib/components/common/SignedIn.svelte"; + import SidebarItem from "$lib/components/sidebar/SidebarItem.svelte"; + + import { canonicalUrl, pdfUrl } from "$lib/api/documents"; export let document: Document; + + function relative(document: Document, path: string) { + return new URL(path, canonicalUrl(document)).toString(); + } + + // urls + $: edit = relative(document, "edit/"); + $: revisions = relative(document, "revisions/"); + $: pdf = pdfUrl(document).toString(); + $: annotate = relative(document, "annotate/"); + $: redact = relative(document, "redact/"); + $: modify = relative(document, "modify/"); {document.access} access + + + Edit + - Revision History + Revision History - Download PDF + Download PDF @@ -41,17 +63,17 @@ - Add a note … + Add a note … - Redact … + Redact … - Modify Pages … + Modify Pages … @@ -59,4 +81,13 @@ .access { text-transform: capitalize; } + + a { + color: var(--black); + text-decoration: none; + } + + a:hover { + text-decoration: underline; + } diff --git a/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte b/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte index 255904037..326e79294 100644 --- a/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte +++ b/src/routes/documents/[id]-[slug]/sidebar/DocumentMetadata.svelte @@ -10,13 +10,16 @@ import SidebarItem from "$lib/components/sidebar/SidebarItem.svelte"; - import { userOrgString } from "$lib/api/documents"; + import { canonicalUrl, userOrgString } from "$lib/api/documents"; export let document: Document; function dateFormat(date: Date | string) { return new Date(date).toLocaleDateString(); } + + // urls + $: edit = new URL("edit/", canonicalUrl(document)).toString(); From 891bde016e0dd17e223bee62abaf4673ca991e1f Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Tue, 26 Mar 2024 16:43:26 -0400 Subject: [PATCH 18/28] Both sizes Co-authored-by: Allan Lasser --- src/routes/documents/[id]-[slug]/sidebar/Data.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/documents/[id]-[slug]/sidebar/Data.svelte b/src/routes/documents/[id]-[slug]/sidebar/Data.svelte index 6a56d2505..7dc90800d 100644 --- a/src/routes/documents/[id]-[slug]/sidebar/Data.svelte +++ b/src/routes/documents/[id]-[slug]/sidebar/Data.svelte @@ -1,7 +1,7 @@ -
+ + {/if} + diff --git a/src/lib/components/documents/stories/ResultsList.stories.svelte b/src/lib/components/documents/stories/ResultsList.stories.svelte index 886307168..360d7dc3b 100644 --- a/src/lib/components/documents/stories/ResultsList.stories.svelte +++ b/src/lib/components/documents/stories/ResultsList.stories.svelte @@ -1,11 +1,13 @@ -
+
-
+
diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte index 08702a3fd..2a1f76f74 100644 --- a/src/routes/app/+page.svelte +++ b/src/routes/app/+page.svelte @@ -6,35 +6,11 @@ import PageToolbar from "$lib/components/common/PageToolbar.svelte"; import Search from "$lib/components/Search.svelte"; import Empty from "$lib/components/common/Empty.svelte"; - import Paginator from "@/common/Paginator.svelte"; - import type { DocumentResults } from "@/lib/api/types"; - export let data: { - query: string; - searchResults: Promise; - }; - - let page = 1; - let per_page = 25; - let error: Error; + export let data; $: searchResults = data.searchResults; $: query = data.query; - - async function load(url) { - const res = await fetch(url, { credentials: "include" }).catch((e) => { - error = e; - throw e; // if something went wrong here, something broke - }); - - if (!res.ok) { - // 404 or something similar - console.error(res.statusText); - error = { name: "Loading error", message: res.statusText }; - } - - data.searchResults = res.json(); - } @@ -44,7 +20,11 @@ {#await searchResults} Loading… {:then results} - + {/await} @@ -52,37 +32,5 @@ Select all - - - {#await searchResults then sr} - {@const count = sr.count} - {@const total_pages = Math.ceil(count / per_page)} - {@const next = sr.next} - {@const previous = sr.previous} - { - page = Math.min(total_pages, page + 1); - load(next); - }} - on:previous={(e) => { - page = Math.max(1, page - 1); - load(previous); - }} - /> - {/await} - - - diff --git a/src/routes/app/+page.ts b/src/routes/app/+page.ts index 2798376c6..cf9984f05 100644 --- a/src/routes/app/+page.ts +++ b/src/routes/app/+page.ts @@ -1,11 +1,30 @@ -import { search } from "$lib/api/documents.js"; +import type { SearchOptions } from "$lib/api/types"; +import { search } from "$lib/api/documents"; export async function load({ url, fetch }) { const query = url.searchParams.get("q") || ""; - const searchResults = search(query, true, fetch); + const per_page = +url.searchParams.get("per_page") || 25; + const cursor = url.searchParams.get("cursor") || ""; + + const options: SearchOptions = { + hl: Boolean(query), + version: "2.0", + }; + + if (per_page) { + options.per_page = per_page; + } + + if (cursor) { + options.cursor = cursor; + } + + const searchResults = search(query, options, fetch); return { - searchResults, query, + per_page, + cursor, + searchResults, }; } diff --git a/src/style/kit.css b/src/style/kit.css index d0b920685..1965f00cd 100644 --- a/src/style/kit.css +++ b/src/style/kit.css @@ -139,3 +139,21 @@ dd { font-size: var(--font-s, 0.875rem); font-weight: var(--font-regular, 400); } + +/* +Utility classes +*/ + +/* https://css-tricks.com/inclusively-hidden/ + * Hiding class, making content visible only to screen readers but not visually + * "sr" meaning "screen-reader" + */ +.sr-only:not(:focus):not(:active) { + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; +} From d94710a632c5013f00ac8ae0430a5a46d4635379 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 28 Mar 2024 22:10:12 -0400 Subject: [PATCH 22/28] intersection observer --- .../components/documents/ResultsList.svelte | 35 ++++++++++++++++++- src/routes/app/+page.svelte | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/lib/components/documents/ResultsList.svelte b/src/lib/components/documents/ResultsList.svelte index a1a679fe3..ffc3dd0eb 100644 --- a/src/lib/components/documents/ResultsList.svelte +++ b/src/lib/components/documents/ResultsList.svelte @@ -8,6 +8,7 @@
@@ -56,7 +89,7 @@

{$_("noDocuments.queryNoResults")}

{/each} -
+
{#if next} {/if} diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte index 2a1f76f74..8fb0cb914 100644 --- a/src/routes/app/+page.svelte +++ b/src/routes/app/+page.svelte @@ -24,6 +24,7 @@ results={results.results} count={results.count} next={results.next} + auto /> {/await} From c20023168662a66e59e9eb7c30b0ba53d9d7a570 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 28 Mar 2024 22:17:12 -0400 Subject: [PATCH 23/28] disable button while loading --- src/lib/components/documents/ResultsList.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/components/documents/ResultsList.svelte b/src/lib/components/documents/ResultsList.svelte index ffc3dd0eb..c85707982 100644 --- a/src/lib/components/documents/ResultsList.svelte +++ b/src/lib/components/documents/ResultsList.svelte @@ -91,7 +91,9 @@ {/each}
{#if next} - + {/if}
From 0577b6f189cdd49c135c48e990c8c6e9fa21a6ee Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Thu, 28 Mar 2024 22:22:26 -0400 Subject: [PATCH 24/28] Only watch in auto mode --- src/lib/components/documents/ResultsList.svelte | 12 ++++++++---- .../documents/stories/ResultsList.stories.svelte | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib/components/documents/ResultsList.svelte b/src/lib/components/documents/ResultsList.svelte index c85707982..f07bfa7e6 100644 --- a/src/lib/components/documents/ResultsList.svelte +++ b/src/lib/components/documents/ResultsList.svelte @@ -42,7 +42,7 @@ count = r.count; next = r.next; loading = false; - watch(); + if (auto) watch(); } function watch() { @@ -91,9 +91,13 @@ {/each}
{#if next} - + {/if}
diff --git a/src/lib/components/documents/stories/ResultsList.stories.svelte b/src/lib/components/documents/stories/ResultsList.stories.svelte index 360d7dc3b..9e31ad2a5 100644 --- a/src/lib/components/documents/stories/ResultsList.stories.svelte +++ b/src/lib/components/documents/stories/ResultsList.stories.svelte @@ -24,3 +24,7 @@
+ + +
+
From 83b535eccb09fddc41a1a88c9b3b980cab119d7b Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Fri, 29 Mar 2024 10:57:23 -0400 Subject: [PATCH 25/28] Connect results to toolbar and implement select-all --- .../components/documents/ResultsList.svelte | 36 +++++++++++++------ src/routes/app/+page.svelte | 34 ++++++++++++++++-- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/lib/components/documents/ResultsList.svelte b/src/lib/components/documents/ResultsList.svelte index f07bfa7e6..2143cf802 100644 --- a/src/lib/components/documents/ResultsList.svelte +++ b/src/lib/components/documents/ResultsList.svelte @@ -2,7 +2,12 @@ import { writable, type Writable } from "svelte/store"; import Button from "../common/Button.svelte"; - export const selected: Writable<(number | string)[]> = writable([]); + // IDs might be strings or numbers, depending on the API endpoint + // enforce type consistency here to avoid comparison bugs later + export const selected: Writable = writable([]); + export let visible: Writable> = writable(new Set()); + + export let total: Writable = writable(0); @@ -79,7 +89,11 @@ diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte index 8fb0cb914..45118d32c 100644 --- a/src/routes/app/+page.svelte +++ b/src/routes/app/+page.svelte @@ -1,7 +1,11 @@ @@ -30,8 +42,24 @@ + + + {#if $visible && $total} + Showing {$visible.size} of {$total} results + {/if} + From a958e760b7cf344d1c69a2a67f0c20792bb0a332 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Fri, 29 Mar 2024 11:06:05 -0400 Subject: [PATCH 26/28] locale strings because we can --- src/routes/app/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte index 45118d32c..ff28f8ddc 100644 --- a/src/routes/app/+page.svelte +++ b/src/routes/app/+page.svelte @@ -50,7 +50,7 @@ on:change={selectAll} /> {#if $selected.length > 0} - {$selected.length} selected + {$selected.length.toLocaleString()} selected {:else} Select all {/if} @@ -58,7 +58,7 @@ {#if $visible && $total} - Showing {$visible.size} of {$total} results + Showing {$visible.size.toLocaleString()} of {$total.toLocaleString()} results {/if} From 249223ac961ac6b7afc5f8d8b9bbc42b9e967d15 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Fri, 29 Mar 2024 16:57:28 -0400 Subject: [PATCH 27/28] style tweaks --- src/config/config.js | 1 + .../components/documents/ResultsList.svelte | 2 +- src/routes/app/+page.svelte | 18 ++++++++++++++++-- src/routes/app/+page.ts | 4 +++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index 73ff826d5..473668561 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -63,6 +63,7 @@ export const IMAGE_WIDTHS = IMAGE_WIDTHS_ENTRIES.map(([name, width]) => [ export const IMAGE_WIDTHS_MAP = new Map(IMAGE_WIDTHS_ENTRIES); +export const DEFAULT_PER_PAGE = 25; export const MAX_PER_PAGE = 100; export const PDF_SIZE_LIMIT = 525336576; diff --git a/src/lib/components/documents/ResultsList.svelte b/src/lib/components/documents/ResultsList.svelte index 2143cf802..59a7c10c5 100644 --- a/src/lib/components/documents/ResultsList.svelte +++ b/src/lib/components/documents/ResultsList.svelte @@ -1,6 +1,5 @@