Skip to content

Commit

Permalink
Merge pull request #904 from MuckRock/allanlasser/issue865
Browse files Browse the repository at this point in the history
Expand/Collapse all search results
  • Loading branch information
allanlasser authored Dec 6, 2024
2 parents fc687b6 + ec16975 commit 36c413b
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 32 deletions.
4 changes: 3 additions & 1 deletion src/langs/json/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"reset": "Clear Search",
"help": "Use filters like <code>user:</code>, <code>project:</code> or <code>organization:</code> to refine searches. Use <code>sort:</code> to order results.",
"more": "Learn more",
"empty": "No matching results found."
"collapseAll": "Collapse all",
"expandAll": "Expand all",
"empty": "No matching results found"
},
"homeTemplate": {
"signedIn": "Signed in as {name}",
Expand Down
15 changes: 12 additions & 3 deletions src/lib/components/common/Highlight.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
export let title: string = "";
export let segments: string[] = [];
export let inlineTitle: boolean = false;
function sanitize(s: string): string {
return DOMPurify.sanitize(s, { ALLOWED_TAGS: ["em"] });
}
</script>

<div class="container">
<div class="container" class:inlineTitle>
{#if title}<h4 class="ellipsis">{@html sanitize(title)}</h4>{/if}
{#if segments.length > 0}
<blockquote>
Expand All @@ -23,6 +24,9 @@
<style>
.container {
width: 100%;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.container blockquote {
margin: 0;
Expand All @@ -31,11 +35,10 @@
overflow: hidden;
}
.container h4 {
flex: 0 0 4rem;
color: var(--gray-4);
font-weight: var(--font-semibold);
font-size: var(--font-sm);
margin-bottom: 0.5rem;
/* margin-bottom: 0.5rem; */
}
.segment {
margin-bottom: 0.5rem;
Expand All @@ -54,4 +57,10 @@
box-shadow: 0 0 0 0.125rem var(--yellow-2);
font-style: normal;
}
.container.inlineTitle {
flex-direction: row;
}
.container.inlineTitle h4 {
flex: 0 0 4rem;
}
</style>
89 changes: 83 additions & 6 deletions src/lib/components/common/HighlightGroup.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,79 @@
<!-- @component A collection of highlights from search results.-->

<script lang="ts" generics="H">
import { createEventDispatcher } from "svelte";
import { _ } from "svelte-i18n";
import {
ChevronDown12,
ChevronRight12,
Fold16,
Unfold16,
} from "svelte-octicons";
import { remToPx } from "$lib/utils/layout";
import Button from "./Button.svelte";
export let open = false;
export let highlights: [string, H][] = [];
export let getHref: (id: string) => string;
export let showAll = false;
let clientWidth = 1000;
$: isSmall = clientWidth < remToPx(27);
const dispatch = createEventDispatcher();
function collapseAll() {
open = false;
dispatch("collapseAll");
}
function expandAll() {
open = true;
dispatch("expandAll");
}
</script>

{#if highlights.length}
<details class="highlights" bind:open>
<details class="highlights" bind:open bind:clientWidth>
<summary>
<slot name="summary">
{$_("search.matchingResults", { values: { n: highlights.length } })}
</slot>
<div class="left">
{#if open}
<ChevronDown12 />
{:else}
<ChevronRight12 />
{/if}
<slot name="summary">
{$_("search.matchingResults", { values: { n: highlights.length } })}
</slot>
</div>
{#if showAll}
<div class="right">
{#if open}
<Button
minW={false}
size="small"
ghost
on:click={collapseAll}
title={$_("search.collapseAll")}
>
<Fold16 height={14} width={14} />
{#if !isSmall}{$_("search.collapseAll")}{/if}
</Button>
{:else}
<Button
minW={false}
size="small"
ghost
on:click={expandAll}
title={$_("search.expandAll")}
>
<Unfold16 height={14} width={14} />
{#if !isSmall}{$_("search.expandAll")}{/if}
</Button>
{/if}
</div>
{/if}
</summary>
<ul>
{#each highlights as [id, highlight]}
Expand All @@ -33,13 +93,30 @@
overflow: hidden;
}
.highlights summary {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
gap: 1rem;
color: var(--gray-4);
fill: var(--gray-4);
padding: 0.5rem 0.75rem;
font-size: var(--font-sm);
font-weight: var(--font-semibold);
}
.highlights summary::marker {
margin-right: 1rem;
.highlights summary .left,
.highlights summary .right {
display: flex;
align-items: center;
gap: 0.5rem;
white-space: no-wrap;
padding: 0 0.5rem 0 0.25rem;
border-radius: 0.5rem;
}
summary .left:hover,
summary .left:focus,
summary:hover .left,
summary:focus .left {
background-color: var(--blue-1);
}
.highlights ul {
list-style-type: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@
</svelte:fragment>
</HighlightGroup>
</Story>

<Story name="With All Controls">
<HighlightGroup {highlights} {getHref} showAll>
<svelte:fragment let:id let:highlight>
<Highlight title={id} segments={highlight} />
</svelte:fragment>
</HighlightGroup>
</Story>
25 changes: 21 additions & 4 deletions src/lib/components/documents/NoteHighlights.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,44 @@
-->

<script lang="ts">
import type { Writable } from "svelte/store";
import type { Document } from "$lib/api/types";
import { getContext } from "svelte";
import { _ } from "svelte-i18n";
import type { Document } from "$lib/api/types";
import { noteUrl } from "$lib/api/notes";
import Highlight from "../common/Highlight.svelte";
import HighlightGroup from "../common/HighlightGroup.svelte";
import { noteUrl } from "$lib/api/notes";
export let document: Document;
export let open = true;
const { subscribe } =
getContext<Writable<{ allOpen: boolean }>>("highlightState") ?? {};
$: subscribe?.((state) => {
open = state.allOpen;
});
$: highlights = Object.entries(document.note_highlights ?? {});
$: notes = new Map(document.notes?.map((n) => [n.id, n]));
function noteHref(id: string): string {
const note = notes.get(id);
if (!note) return "";
return noteUrl(document, note).toString();
return noteUrl(document, note).href;
}
</script>

<HighlightGroup {highlights} getHref={noteHref} bind:open>
<HighlightGroup
{highlights}
getHref={noteHref}
bind:open
showAll={Boolean(subscribe)}
on:collapseAll
on:expandAll
>
<svelte:fragment slot="summary">
{$_("documents.matchingNotes", { values: { n: highlights.length } })}
</svelte:fragment>
Expand Down
19 changes: 17 additions & 2 deletions src/lib/components/documents/PageHighlights.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
```
-->
<script lang="ts">
import type { Writable } from "svelte/store";
import type { Document } from "$lib/api/types";
import { getContext } from "svelte";
import { _ } from "svelte-i18n";
import Highlight from "../common/Highlight.svelte";
Expand All @@ -24,21 +26,34 @@
export let document: Document;
export let open = true;
const { subscribe } =
getContext<Writable<{ allOpen: boolean }>>("highlightState") ?? {};
$: subscribe?.((state) => {
open = state.allOpen;
});
$: highlights = Object.entries(document.highlights ?? {});
function pageHref(id: string): string {
const pageNo = pageNumber(id);
return pageUrl(document, pageNo).toString();
return pageUrl(document, pageNo).href;
}
</script>

<HighlightGroup {highlights} getHref={pageHref} bind:open>
<HighlightGroup
{highlights}
getHref={pageHref}
bind:open
showAll={Boolean(subscribe)}
on:collapseAll
on:expandAll
>
<svelte:fragment slot="summary">
{$_("documents.matchingPages", { values: { n: highlights.length } })}
</svelte:fragment>
<svelte:fragment let:id let:highlight>
<Highlight
title="{$_('documents.pageAbbrev')} {pageNumber(id)}"
inlineTitle
segments={highlight}
/>
</svelte:fragment>
Expand Down
Loading

0 comments on commit 36c413b

Please sign in to comment.