Skip to content

Commit

Permalink
refactor: Reduce repetition
Browse files Browse the repository at this point in the history
  • Loading branch information
Ushie committed Dec 19, 2024
1 parent 4e8ad76 commit 4eeda10
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 180 deletions.
4 changes: 4 additions & 0 deletions src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ body {
background-color: var(--tertiary);
}

mark {
background-color: var(--secondary);
}

/*-----headings-----*/

h1 {
Expand Down
55 changes: 17 additions & 38 deletions src/routes/announcements/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,44 @@
import { queries } from '$data/api';
import TagsHost from './TagsHost.svelte';
import Search from '$lib/components/Search.svelte';
import Fuse from 'fuse.js';
import { onMount } from 'svelte';
import type { ResponseAnnouncement } from '$lib/types';
import { admin_login } from '$lib/stores';
import Button from '$lib/components/Button.svelte';
import moment from 'moment';
import { debounce } from '$util/debounce';
import createFilter from '$util/filter';
let searchParams: Readable<URLSearchParams>;
if (building) searchParams = readable(new URLSearchParams());
else searchParams = derived(page, ($page) => $page.url.searchParams);
let searchTerm = $searchParams.get('s') || '';
let searcher: Fuse<ResponseAnnouncement>;
$: query = createQuery(queries.announcements());
$: tagsQuery = createQuery(queries.announcementTags());
$: selectedTags = $searchParams.getAll('tag');
function filter(announcements: Iterable<ResponseAnnouncement>, search: string) {
const announcementsArray = Array.from(announcements);
if (!search) {
if (selectedTags.length > 0)
return announcementsArray.filter((announcement) =>
selectedTags.some((tag) => announcement.tags.includes(tag))
);
return announcementsArray;
}
if (!searcher) {
searcher = new Fuse(announcementsArray, {
keys: ['title', 'content'],
shouldSort: true,
threshold: 0.3
});
}
function filterAnnouncements(
announcements: Iterable<ResponseAnnouncement>,
search: string,
selectedTags: string[]
): ResponseAnnouncement[] {
const announcementFilter = createFilter(Array.from(announcements), {
searcherOptions: {
keys: ['title', 'content']
},
additionalFilter: (announcement: ResponseAnnouncement, tags: string[]): boolean => {
return tags.length === 0 || tags.some((tag) => announcement.tags.includes(tag));
}
});
const result = searcher
.search(search)
.map(({ item }) => item)
.filter((item) => {
// Don't show if the announcement isn't under the selected tags
if (selectedTags.length > 0 && !selectedTags.some((tag) => item.tags.includes(tag)))
return false;
return true;
});
return result;
return announcementFilter(selectedTags, search);
}
// Make sure we don't have to filter the announcements after every key press
let displayedTerm = '';
const debounce = <T extends any[]>(f: (...args: T) => void) => {
let timeout: number;
return (...args: T) => {
clearTimeout(timeout);
timeout = setTimeout(() => f(...args), 350);
};
};
const update = () => {
displayedTerm = searchTerm;
Expand Down Expand Up @@ -113,7 +92,7 @@

<Query {query} let:data>
<div class="cards">
{#each filter(data.announcements, displayedTerm) as announcement}
{#each filterAnnouncements(data.announcements, displayedTerm, selectedTags) as announcement}
{#if !moment(announcement.archived_at).isBefore(moment()) || $admin_login.logged_in}
{#key selectedTags || displayedTerm}
<div in:fly={{ y: 10, easing: quintOut, duration: 750 }}>
Expand Down
97 changes: 13 additions & 84 deletions src/routes/announcements/AnnouncementCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import { queries } from '$data/api';
import { dev_log } from '$util/dev';
import { useQueryClient } from '@tanstack/svelte-query';
import TagChip from './TagChip.svelte';
import { read_announcements } from '$lib/stores';
import TagsHost from './TagsHost.svelte';
import Content from './[slug]/Content.svelte';
import ToolTip from '$lib/components/ToolTip.svelte';
import { relativeTime } from '$util/relativeTime';
export let announcement: ResponseAnnouncement;
Expand Down Expand Up @@ -62,19 +64,10 @@
<div class="header">
<h3>{announcement.title}</h3>
<span>
{#if moment().diff(moment(announcement.created_at), 'days') <= 7}
{moment(announcement.created_at).fromNow()}
{:else}
{moment(announcement.created_at).format('MMMM D, YYYY [at] h:mm A')}
{/if}

{#if moment(announcement.archived_at).isBefore(moment())}
{relativeTime(announcement.created_at)}
{#if announcement.archived_at && moment(announcement.archived_at).isBefore(moment())}
<ToolTip
content={`This announcement was archived ${
moment().diff(moment(announcement.archived_at), 'days') <= 7
? moment(announcement.archived_at).fromNow()
: moment(announcement.archived_at).format('on MMMM D, YYYY [at] h:mm A')
}`}
content={`This announcement was archived ${relativeTime(announcement.archived_at)}`}
>
<img src="../icons/archive.svg" alt="archive" />
</ToolTip>
Expand All @@ -83,17 +76,15 @@
</div>
<div class="footer">
{#if announcement.content}
<div class="description">
{@html announcement.content}
</div>
<Content content={announcement.content} clamp={true} />
{/if}
{#if announcement.tags.length > 0}
<hr />
<div class="tag-list">
{#each announcement.tags as tag}
<TagChip {tag} clickable={false} />
{/each}
</div>
<TagsHost
tags={announcement.tags.map((tag) => ({ name: tag }))}
expandable={false}
clickable={false}
/>
{/if}
</div>
</div>
Expand All @@ -102,15 +93,7 @@

<style lang="scss">
a {
color: inherit !important;
text-decoration: inherit !important;
font-weight: inherit !important;
font-size: inherit !important;
user-select: none !important;
}
hr {
justify-content: end;
text-decoration: inherit;
}
.card {
Expand Down Expand Up @@ -169,65 +152,11 @@
width: 24px;
}
}
.tag-list {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 4px;
}
}
.footer {
gap: 12px;
}
.description {
display: -webkit-inline-box;
line-clamp: 3;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
:global(a) {
color: var(--primary);
text-decoration: none;
pointer-events: none;
}
:global(h1),
:global(h2),
:global(h3),
:global(h4),
:global(h5),
:global(h6) {
color: var(--secondary);
line-height: 1.75rem;
margin: 0;
}
:global(h1) {
font-size: 1.75rem;
}
:global(h2) {
font-size: 1.25rem;
}
:global(h3) {
font-size: 1rem;
}
:global(h4) {
font-size: 0.5rem;
}
:global(li) {
list-style-position: inside;
font-size: 0.9rem;
font-weight: 500;
}
}
}
}
</style>
7 changes: 5 additions & 2 deletions src/routes/announcements/TagsHost.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import Button from '$lib/components/Button.svelte';
export let tags: Tags;
export let expandable: boolean = false;
export let clickable: boolean = true;
let showAllTags = false;
let showAllTags = expandable ? false : true;
const searchParams = derived(page, ($page) => $page.url.searchParams);
Expand Down Expand Up @@ -42,10 +44,11 @@
{tag}
selected={$searchParams.getAll('tag').includes(tag)}
onClick={() => handleClick(tag)}
{clickable}
/>
{/each}

{#if tags.length > 1}
{#if expandable && tags.length > 1}
<li class="button">
<Button type="text" on:click={() => (showAllTags = !showAllTags)}>
<img
Expand Down
2 changes: 1 addition & 1 deletion src/routes/announcements/[slug]/Announcement.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@

<style lang="scss">
.card {
background-color: var(--surface-eight);
display: flex;
flex-direction: column;
padding: 2rem;
margin-bottom: 3rem;
border-radius: 1rem;
background-color: var(--surface-eight);
}
.header {
Expand Down
59 changes: 53 additions & 6 deletions src/routes/announcements/[slug]/Content.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
<script lang="ts">
export let isEditing: boolean;
export let isCreating: boolean;
export let isPreviewing: boolean;
export let isEditing: boolean = false;
export let isCreating: boolean = false;
export let isPreviewing: boolean = false;
export let content: string | undefined;
export let contentInput: string | undefined;
export let contentInput: string | undefined = undefined;
export let clamp: boolean = false;
$: displayContent = isPreviewing ? contentInput : content;
</script>

{#if (isEditing || isCreating) && !isPreviewing}
<textarea bind:value={contentInput} class:empty={!content?.trim()} placeholder="Enter content" />
{:else if displayContent}
<div>
<div class:clamp>
{@html displayContent}
</div>
{/if}
Expand All @@ -32,7 +33,29 @@
div {
color: var(--text-four);
white-space: pre-wrap;
&.clamp {
display: -webkit-inline-box;
line-clamp: 3;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
:global(a) {
pointer-events: none;
}
:global(h1),
:global(h2),
:global(h3),
:global(h4),
:global(h5),
:global(h6) {
color: var(--secondary);
line-height: 1.75rem;
margin: 0;
}
}
:global(a) {
color: var(--primary);
Expand All @@ -56,6 +79,30 @@
margin-bottom: 1.25rem;
}
:global(h1) {
font-size: 1.8rem;
}
:global(h2) {
font-size: 1.6rem;
}
:global(h3) {
font-size: 1.4rem;
}
:global(h4) {
font-size: 1.2rem;
}
:global(h5) {
font-size: 1.1rem;
}
:global(h6) {
font-size: 1rem;
}
:global(li) {
list-style-position: inside;
font-size: 0.9rem;
Expand Down
Loading

0 comments on commit 4eeda10

Please sign in to comment.