From 1b25e5d03c4aebfc5024573af43a395716b933d7 Mon Sep 17 00:00:00 2001 From: Cole Bemis Date: Thu, 12 Dec 2024 15:41:51 -0800 Subject: [PATCH] Show tags in note preview --- src/components/command-menu.tsx | 12 +- src/components/link-highlight-provider.tsx | 19 ++- src/components/markdown.tsx | 6 +- src/components/note-preview-card.tsx | 2 +- src/components/note-preview.tsx | 34 ++++- src/hooks/search.ts | 1 - src/routes/notes_.$.tsx | 2 +- src/routes/settings.tsx | 11 +- src/routes/tags_.$.tsx | 27 ++-- src/styles/radix-colors.css | 152 +++++++++++++++++++++ src/styles/variables.css | 4 +- src/utils/parse-note.ts | 2 +- 12 files changed, 238 insertions(+), 34 deletions(-) diff --git a/src/components/command-menu.tsx b/src/components/command-menu.tsx index e0d1345a..56a8a7ed 100644 --- a/src/components/command-menu.tsx +++ b/src/components/command-menu.tsx @@ -2,10 +2,11 @@ import { useNavigate } from "@tanstack/react-router" import { parseDate } from "chrono-node" import { Command } from "cmdk" import { useAtomValue } from "jotai" +import { selectAtom, useAtomCallback } from "jotai/utils" import { useCallback, useMemo, useRef, useState } from "react" import { useHotkeys } from "react-hotkeys-hook" import { useDebounce } from "use-debounce" -import { pinnedNotesAtom, tagSearcherAtom } from "../global-state" +import { notesAtom, pinnedNotesAtom, tagSearcherAtom } from "../global-state" import { useSaveNote } from "../hooks/note" import { useSearchNotes } from "../hooks/search" import { Note } from "../schema" @@ -23,6 +24,9 @@ import { } from "./icons" import { NoteFavicon } from "./note-favicon" +const hasDailyNoteAtom = selectAtom(notesAtom, (notes) => notes.has(toDateString(new Date()))) +const hasWeeklyNoteAtom = selectAtom(notesAtom, (notes) => notes.has(toWeekString(new Date()))) + export function CommandMenu() { const navigate = useNavigate() @@ -30,6 +34,8 @@ export function CommandMenu() { const tagSearcher = useAtomValue(tagSearcherAtom) const saveNote = useSaveNote() const pinnedNotes = useAtomValue(pinnedNotesAtom) + const getHasDailyNote = useAtomCallback(useCallback((get) => get(hasDailyNoteAtom), [])) + const getHasWeeklyNote = useAtomCallback(useCallback((get) => get(hasWeeklyNoteAtom), [])) // Refs const prevActiveElement = useRef() @@ -98,7 +104,7 @@ export function CommandMenu() { _splat: toDateString(new Date()), }, search: { - mode: "read", + mode: getHasDailyNote() ? "read" : "write", query: undefined, view: "grid", }, @@ -115,7 +121,7 @@ export function CommandMenu() { _splat: toWeekString(new Date()), }, search: { - mode: "read", + mode: getHasWeeklyNote() ? "read" : "write", query: undefined, view: "grid", }, diff --git a/src/components/link-highlight-provider.tsx b/src/components/link-highlight-provider.tsx index 42ba08c7..49610031 100644 --- a/src/components/link-highlight-provider.tsx +++ b/src/components/link-highlight-provider.tsx @@ -1,14 +1,21 @@ -import React from "react" +import React, { useContext, useMemo } from "react" type LinkHighlightProviderProps = { href: string | string[] children?: React.ReactNode } +export const LinkHighlightContext = React.createContext([]) + export function LinkHighlightProvider({ href, children }: LinkHighlightProviderProps) { + const inheritedHrefs = useLinkHighlight() + // Scope styles using a unique ID - const id = React.useMemo(() => `id-${Math.random().toString(36).substring(2, 15)}`, []) - const hrefs = Array.isArray(href) ? href : [href] + const id = useMemo(() => `id-${Math.random().toString(36).substring(2, 15)}`, []) + const hrefs = useMemo(() => (Array.isArray(href) ? href : [href]), [href]) + + const contextValue = useMemo(() => [...inheritedHrefs, ...hrefs], [inheritedHrefs, hrefs]) + return (
- {children} + {children}
) } + +export function useLinkHighlight() { + return useContext(LinkHighlightContext) +} diff --git a/src/components/markdown.tsx b/src/components/markdown.tsx index ba1c9146..f149c209 100644 --- a/src/components/markdown.tsx +++ b/src/components/markdown.tsx @@ -103,7 +103,7 @@ export const Markdown = React.memo(

{parsedTemplate.data.name}

- + Template @@ -754,7 +754,7 @@ function NoteLink({ id, text }: NoteLinkProps) { > {isFirst && note && online ? ( {note ? ( - {note.content} + ) : ( diff --git a/src/components/note-preview-card.tsx b/src/components/note-preview-card.tsx index f74acca6..612c39de 100644 --- a/src/components/note-preview-card.tsx +++ b/src/components/note-preview-card.tsx @@ -74,7 +74,7 @@ const _NotePreviewCard = React.memo(function NoteCard({ id }: NoteCardProps) { isDropdownOpen && "ring-2 ring-border", )} > - {note?.content ?? ""} +
-
- {children} +
+
+
+ {note.content} +
+
+
+ {removeParentTags(note.tags).map((tag) => ( +
`/tags/${tag}`.startsWith(href)) + ? "bg-bg-highlight text-text-highlight" + : "bg-bg-secondary text-text-secondary", + )} + > + {tag} +
+ ))}
) diff --git a/src/hooks/search.ts b/src/hooks/search.ts index 16b9ae16..e499b8da 100644 --- a/src/hooks/search.ts +++ b/src/hooks/search.ts @@ -223,7 +223,6 @@ export function testQualifiers(qualifiers: Qualifier[], item: Note) { }) break - case "is": case "type": value = qualifier.values.includes(item.type) break diff --git a/src/routes/notes_.$.tsx b/src/routes/notes_.$.tsx index 058c3391..7b385a7e 100644 --- a/src/routes/notes_.$.tsx +++ b/src/routes/notes_.$.tsx @@ -320,7 +320,7 @@ function NotePage() { - {isDirty ? : null} + {isDirty ? : null} } icon={} diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx index b126e234..cf534b18 100644 --- a/src/routes/settings.tsx +++ b/src/routes/settings.tsx @@ -1,4 +1,4 @@ -import { createFileRoute } from "@tanstack/react-router" +import { createFileRoute, useNavigate } from "@tanstack/react-router" import { useAtomValue } from "jotai" import { useState } from "react" import { useNetworkState } from "react-use" @@ -45,6 +45,7 @@ function SettingsSection({ title, children }: { title: string; children: React.R } function GitHubSection() { + const navigate = useNavigate() const githubUser = useAtomValue(githubUserAtom) const githubRepo = useAtomValue(githubRepoAtom) const isRepoNotCloned = useAtomValue(isRepoNotClonedAtom) @@ -74,7 +75,13 @@ function GitHubSection() { {githubUser.login}
-
diff --git a/src/routes/tags_.$.tsx b/src/routes/tags_.$.tsx index 31ef5c26..3854ee6c 100644 --- a/src/routes/tags_.$.tsx +++ b/src/routes/tags_.$.tsx @@ -5,6 +5,7 @@ import { IconButton } from "../components/icon-button" import { EditIcon16, MoreIcon16, TagIcon16, TrashIcon16 } from "../components/icons" import { NoteList } from "../components/note-list" import { useDeleteTag, useRenameTag } from "../hooks/tag" +import { LinkHighlightProvider } from "../components/link-highlight-provider" type RouteSearch = { query: string | undefined @@ -85,18 +86,20 @@ function RouteComponent() { } >
- - navigate({ search: (prev) => ({ ...prev, query }), replace: true }) - } - onViewChange={(view) => - navigate({ search: (prev) => ({ ...prev, view }), replace: true }) - } - /> + + + navigate({ search: (prev) => ({ ...prev, query }), replace: true }) + } + onViewChange={(view) => + navigate({ search: (prev) => ({ ...prev, view }), replace: true }) + } + /> +
) diff --git a/src/styles/radix-colors.css b/src/styles/radix-colors.css index c05dd7b0..48916315 100644 --- a/src/styles/radix-colors.css +++ b/src/styles/radix-colors.css @@ -454,6 +454,158 @@ } } +/* -------------------------------------------------------------------------- */ +/* Amber */ +/* -------------------------------------------------------------------------- */ + +/* amber */ + +:root { + --amber-1: #fefdfb; + --amber-2: #fefbe9; + --amber-3: #fff7c2; + --amber-4: #ffee9c; + --amber-5: #fbe577; + --amber-6: #f3d673; + --amber-7: #e9c162; + --amber-8: #e2a336; + --amber-9: #ffc53d; + --amber-10: #ffba18; + --amber-11: #ab6400; + --amber-12: #4f3422; +} + +@supports (color: color(display-p3 1 1 1)) { + @media (color-gamut: p3) { + :root { + --amber-1: color(display-p3 0.995 0.992 0.985); + --amber-2: color(display-p3 0.994 0.986 0.921); + --amber-3: color(display-p3 0.994 0.969 0.782); + --amber-4: color(display-p3 0.989 0.937 0.65); + --amber-5: color(display-p3 0.97 0.902 0.527); + --amber-6: color(display-p3 0.936 0.844 0.506); + --amber-7: color(display-p3 0.89 0.762 0.443); + --amber-8: color(display-p3 0.85 0.65 0.3); + --amber-9: color(display-p3 1 0.77 0.26); + --amber-10: color(display-p3 0.959 0.741 0.274); + --amber-11: color(display-p3 0.64 0.4 0); + --amber-12: color(display-p3 0.294 0.208 0.145); + } + } +} + +/* amber-alpha */ + +:root { + --amber-a1: #c0800004; + --amber-a2: #f4d10016; + --amber-a3: #ffde003d; + --amber-a4: #ffd40063; + --amber-a5: #f8cf0088; + --amber-a6: #eab5008c; + --amber-a7: #dc9b009d; + --amber-a8: #da8a00c9; + --amber-a9: #ffb300c2; + --amber-a10: #ffb300e7; + --amber-a11: #ab6400; + --amber-a12: #341500dd; +} + +@supports (color: color(display-p3 1 1 1)) { + @media (color-gamut: p3) { + :root { + --amber-a1: color(display-p3 0.757 0.514 0.024 / 0.016); + --amber-a2: color(display-p3 0.902 0.804 0.008 / 0.079); + --amber-a3: color(display-p3 0.965 0.859 0.004 / 0.22); + --amber-a4: color(display-p3 0.969 0.82 0.004 / 0.35); + --amber-a5: color(display-p3 0.933 0.796 0.004 / 0.475); + --amber-a6: color(display-p3 0.875 0.682 0.004 / 0.495); + --amber-a7: color(display-p3 0.804 0.573 0 / 0.557); + --amber-a8: color(display-p3 0.788 0.502 0 / 0.699); + --amber-a9: color(display-p3 1 0.686 0 / 0.742); + --amber-a10: color(display-p3 0.945 0.643 0 / 0.726); + --amber-a11: color(display-p3 0.64 0.4 0); + --amber-a12: color(display-p3 0.294 0.208 0.145); + } + } +} + +/* amber-dark */ + +@media (prefers-color-scheme: dark) { + :root { + --amber-1: #16120c; + --amber-2: #1d180f; + --amber-3: #302008; + --amber-4: #3f2700; + --amber-5: #4d3000; + --amber-6: #5c3d05; + --amber-7: #714f19; + --amber-8: #8f6424; + --amber-9: #ffc53d; + --amber-10: #ffd60a; + --amber-11: #ffca16; + --amber-12: #ffe7b3; + } + + @supports (color: color(display-p3 1 1 1)) { + @media (color-gamut: p3) { + :root { + --amber-1: color(display-p3 0.082 0.07 0.05); + --amber-2: color(display-p3 0.111 0.094 0.064); + --amber-3: color(display-p3 0.178 0.128 0.049); + --amber-4: color(display-p3 0.239 0.156 0); + --amber-5: color(display-p3 0.29 0.193 0); + --amber-6: color(display-p3 0.344 0.245 0.076); + --amber-7: color(display-p3 0.422 0.314 0.141); + --amber-8: color(display-p3 0.535 0.399 0.189); + --amber-9: color(display-p3 1 0.77 0.26); + --amber-10: color(display-p3 1 0.87 0.15); + --amber-11: color(display-p3 1 0.8 0.29); + --amber-12: color(display-p3 0.984 0.909 0.726); + } + } + } +} + +/* amber-dark-alpha */ + +@media (prefers-color-scheme: dark) { + :root { + --amber-a1: #e63c0006; + --amber-a2: #fd9b000d; + --amber-a3: #fa820022; + --amber-a4: #fc820032; + --amber-a5: #fd8b0041; + --amber-a6: #fd9b0051; + --amber-a7: #ffab2567; + --amber-a8: #ffae3587; + --amber-a9: #ffc53d; + --amber-a10: #ffd60a; + --amber-a11: #ffca16; + --amber-a12: #ffe7b3; + } + + @supports (color: color(display-p3 1 1 1)) { + @media (color-gamut: p3) { + :root { + --amber-a1: color(display-p3 0.992 0.298 0 / 0.017); + --amber-a2: color(display-p3 0.988 0.651 0 / 0.047); + --amber-a3: color(display-p3 1 0.6 0 / 0.118); + --amber-a4: color(display-p3 1 0.557 0 / 0.185); + --amber-a5: color(display-p3 1 0.592 0 / 0.24); + --amber-a6: color(display-p3 1 0.659 0.094 / 0.299); + --amber-a7: color(display-p3 1 0.714 0.263 / 0.383); + --amber-a8: color(display-p3 0.996 0.729 0.306 / 0.5); + --amber-a9: color(display-p3 1 0.769 0.259); + --amber-a10: color(display-p3 1 0.871 0.149); + --amber-a11: color(display-p3 1 0.8 0.29); + --amber-a12: color(display-p3 0.984 0.909 0.726); + } + } + } +} + /* -------------------------------------------------------------------------- */ /* Green */ /* -------------------------------------------------------------------------- */ diff --git a/src/styles/variables.css b/src/styles/variables.css index 399c7ff3..2e5a6819 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -46,7 +46,7 @@ --color-bg-secondary: var(--neutral-a3); --color-bg-tertiary: var(--neutral-a4); --color-bg-code-block: var(--neutral-3); - --color-bg-highlight: var(--yellow-a3); + --color-bg-highlight: var(--yellow-a4); --color-bg-selection: var(--cyan-a4); /* Border colors */ @@ -56,7 +56,7 @@ --color-border-focus: var(--cyan-9); /* Syntax colors */ - --color-syntax-yellow: var(--yellow-11); + --color-syntax-yellow: var(--yellow11); --color-syntax-red: var(--red-11); --color-syntax-purple: var(--purple-11); --color-syntax-green: var(--green-11); diff --git a/src/utils/parse-note.ts b/src/utils/parse-note.ts index 79d7b53a..b7ed5995 100644 --- a/src/utils/parse-note.ts +++ b/src/utils/parse-note.ts @@ -177,7 +177,7 @@ export const parseNote = memoize((id: NoteId, content: string): Note => { displayName = formatWeek(id) break case "template": - displayName = (frontmatter.template as Template).name + displayName = `${(frontmatter.template as Template).name} template` break case "note": // If there's a title, use it as thedisplay name after removing any leading emoji