From 8eb1c1f4393b612ea47f6c2d7607cad2159d4a88 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 2 May 2023 11:15:24 -0400 Subject: [PATCH 01/81] Page tags and aliases should be deleted when removed by user Fix #8627, fix #7720 and fix #8282 --- src/main/frontend/modules/outliner/core.cljs | 55 +++++++++-------- .../frontend/modules/outliner/core_test.cljs | 59 ++++++++++++++++++- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index 998a0ea514..ea4ae144b4 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -141,42 +141,49 @@ m (if (state/enable-block-timestamps?) (block-with-timestamps m) m) other-tx (:db/other-tx m) id (:db/id (:data this)) - block-entity (db/entity id) - remove-self-page #(remove (fn [b] - (= (:db/id b) (:db/id (:block/page block-entity)))) %) - old-refs (remove-self-page (:block/refs block-entity)) - new-refs (remove-self-page (:block/refs m))] + block-entity (db/entity id)] (when (seq other-tx) (swap! txs-state (fn [txs] (vec (concat txs other-tx))))) (when id + ;; Retract attributes to prepare for tx which rewrites block attributes (swap! txs-state (fn [txs] (vec (concat txs (map (fn [attribute] [:db/retract id attribute]) - db-schema/retract-attributes))))) + db-schema/retract-attributes))))) + ;; Update block's page attributes (when-let [e (:block/page block-entity)] - (let [m' {:db/id (:db/id e) - :block/updated-at (util/time-ms)} - m' (if (:block/created-at e) - m' - (assoc m' :block/created-at (util/time-ms))) - m' (if (or (:block/pre-block? block-entity) - (:block/pre-block? m)) - (let [properties (:block/properties m) - alias (set (:alias properties)) - tags (set (:tags properties)) - alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias) - tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags)] - (assoc m' - :block/alias alias - :block/tags tags - :block/properties properties)) - m')] - (swap! txs-state conj m')) + (let [m' (cond-> {:db/id (:db/id e) + :block/updated-at (util/time-ms)} + (not (:block/created-at e)) + (assoc :block/created-at (util/time-ms))) + txs (if (or (:block/pre-block? block-entity) + (:block/pre-block? m)) + (let [properties (:block/properties m) + alias (set (:alias properties)) + tags (set (:tags properties)) + alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias) + tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags) + deleteable-page-attributes {:block/alias alias + :block/tags tags + :block/properties properties + :block/properties-text-values (:block/properties-text-values m)} + ;; Retract page attributes to allow for deletion of page attributes + page-retractions + (mapv #(vector :db/retract (:db/id e) %) (keys deleteable-page-attributes))] + (conj page-retractions (merge m' deleteable-page-attributes))) + [m'])] + (swap! txs-state into txs))) + + ;; Remove orphaned refs from block + (let [remove-self-page #(remove (fn [b] + (= (:db/id b) (:db/id (:block/page block-entity)))) %) + old-refs (remove-self-page (:block/refs block-entity)) + new-refs (remove-self-page (:block/refs m))] (remove-orphaned-page-refs! (:db/id block-entity) txs-state old-refs new-refs))) (swap! txs-state conj (dissoc m :db/other-tx)) diff --git a/src/test/frontend/modules/outliner/core_test.cljs b/src/test/frontend/modules/outliner/core_test.cljs index 269ecf71cd..6a7fe15240 100644 --- a/src/test/frontend/modules/outliner/core_test.cljs +++ b/src/test/frontend/modules/outliner/core_test.cljs @@ -10,7 +10,7 @@ [clojure.walk :as walk] [logseq.graph-parser.block :as gp-block] [datascript.core :as d] - [frontend.test.helper :as test-helper] + [frontend.test.helper :as test-helper :refer [load-test-files]] [clojure.set :as set])) (def test-db test-helper/test-db) @@ -440,6 +440,63 @@ '(16 17) (map :block/uuid (tree/get-sorted-block-and-children test-db (:db/id (get-block 16)))))))) +(defn- save-block! + [block] + (outliner-tx/transact! {:graph test-db} + (outliner-core/save-block! block))) + +(deftest save-test + (load-test-files [{:file/path "pages/page1.md" + :file/content "alias:: foo, bar +tags:: tag1, tag2 +- block #blarg #bar"}]) + (testing "save deletes a page's tags" + (let [conn (db/get-db test-helper/test-db false) + pre-block (->> (d/q '[:find (pull ?b [*]) + :where [?b :block/pre-block? true]] + @conn) + ffirst) + _ (save-block! (-> pre-block + (update :block/properties dissoc :tags) + (update :block/properties-text-values dissoc :tags))) + updated-page (-> (d/q '[:find (pull ?bp [* {:block/alias [*]}]) + :where [?b :block/pre-block? true] + [?b :block/page ?bp]] + @conn) + ffirst)] + (is (nil? (:block/tags updated-page)) + "Page's tags are deleted") + (is (= #{"foo" "bar"} (set (map :block/name (:block/alias updated-page)))) + "Page's aliases remain the same") + (is (= {:block/properties {:alias #{"foo" "bar"}} + :block/properties-text-values {:alias "foo, bar"}} + (select-keys updated-page [:block/properties :block/properties-text-values])) + "Page property attributes are correct") + (is (= {:block/properties {:alias #{"foo" "bar"}} + :block/properties-text-values {:alias "foo, bar"}} + (-> (d/q '[:find (pull ?b [*]) + :where [?b :block/pre-block? true]] + @conn) + ffirst + (select-keys [:block/properties :block/properties-text-values]))) + "Pre-block property attributes are correct"))) + + (testing "save deletes orphaned pages when a block's refs change" + (let [conn (db/get-db test-helper/test-db false) + pages (set (map first (d/q '[:find ?bn :where [?b :block/name ?bn]] @conn))) + _ (assert (set/subset? #{"blarg" "bar"} pages) "Pages from block exist") + block-with-refs (ffirst (d/q '[:find (pull ?b [* {:block/refs [*]}]) + :where [?b :block/content "block #blarg #bar"]] + @conn)) + _ (save-block! (-> block-with-refs + (assoc :block/content "block" + :block/refs []))) + updated-pages (set (map first (d/q '[:find ?bn :where [?b :block/name ?bn]] @conn)))] + (is (not (contains? updated-pages "blarg")) + "Deleted, orphaned page no longer exists") + (is (contains? updated-pages "bar") + "Deleted but not orphaned page still exists")))) + ;;; Fuzzy tests (def init-id (atom 100)) From f4b4ecb52672164395885f42e02bb666c9486554 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Fri, 5 May 2023 12:58:26 +0300 Subject: [PATCH 02/81] fix: allow interactions with published embeds --- tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx | 5 +++-- tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx | 2 +- tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx index 939f8da63e..fa01a2be8f 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/IFrameShape.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as React from 'react' import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core' -import { HTMLContainer, TLComponentProps } from '@tldraw/react' +import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react' import { action } from 'mobx' import { observer } from 'mobx-react-lite' @@ -37,6 +37,7 @@ export class IFrameShape extends TLBoxShape { ReactComponent = observer(({ events, isErasing, isEditing }: TLComponentProps) => { const ref = React.useRef(null) + const app = useApp() return ( {
diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx index 77d560ef5b..25b237c470 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/TweetShape.tsx @@ -85,7 +85,7 @@ export class TweetShape extends TLBoxShape {
diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx index 0d636fd5ca..0efecdbbe2 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/YouTubeShape.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core' -import { HTMLContainer, TLComponentProps } from '@tldraw/react' +import { HTMLContainer, TLComponentProps, useApp} from '@tldraw/react' import { action, computed } from 'mobx' import { observer } from 'mobx-react-lite' import { withClampedStyles } from './style-props' @@ -45,6 +45,8 @@ export class YouTubeShape extends TLBoxShape { } ReactComponent = observer(({ events, isErasing, isEditing, isSelected }: TLComponentProps) => { + const app = useApp() + return ( {
Date: Fri, 5 May 2023 12:58:56 +0300 Subject: [PATCH 03/81] fix: hide lock/unlock on published whiteboards --- .../tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx b/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx index 0ae9138f3a..12beea3ee1 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ContextMenu/ContextMenu.tsx @@ -262,7 +262,7 @@ export const ContextMenu = observer(function ContextMenu({ Deselect all )} - {app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => !s.props.isLocked) && ( + {!app.readOnly && app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => !s.props.isLocked) && ( runAndTransition(() => app.setLocked(true))} @@ -272,7 +272,7 @@ export const ContextMenu = observer(function ContextMenu({ )} - {app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => s.props.isLocked) && ( + {!app.readOnly && app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => s.props.isLocked) && ( runAndTransition(() => app.setLocked(false))} From eee3862644c642c09c7ca4502bf16a516d07e2ad Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Fri, 5 May 2023 16:04:19 +0300 Subject: [PATCH 04/81] fix: drag to clone text shapes --- tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx index 25f64a0955..da56ea47b8 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/TextShape.tsx @@ -166,8 +166,6 @@ export class TextShape extends TLTextShape { elm.select() } }) - } else { - onEditingEnd?.() } }, [isEditing, onEditingEnd]) From c1c66a773ae605037b618796efd82316a9396d44 Mon Sep 17 00:00:00 2001 From: Inge Date: Fri, 5 May 2023 10:01:22 +0200 Subject: [PATCH 05/81] Updated Norwegian translations. --- src/main/frontend/dicts.cljc | 111 +++++++++++++++++- src/main/frontend/modules/shortcut/dicts.cljc | 42 ++++++- 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/dicts.cljc b/src/main/frontend/dicts.cljc index 375c6194e1..26bbf2f8e8 100644 --- a/src/main/frontend/dicts.cljc +++ b/src/main/frontend/dicts.cljc @@ -2727,7 +2727,116 @@ :asset/maximize "Maksimer bilde" :asset/open-in-browser "Åpne bilde i nettleser" :asset/show-in-folder "Vis bilde i mappe" - :linked-references/filter-search "Søk i lenkede referanser"} + :linked-references/filter-search "Søk i lenkede referanser" + :all-whiteboards "Alle whiteboard" + :auto-heading "Automatisk overskrift" + :heading "Overskrift {1}" + :new-whiteboard "Nytt whiteboard" + :remove-heading "Fjern overskrift" + :untitled "Uten navn" + :accessibility/skip-to-main-content "Hopp til hovedinnhold" + :color/blue "Blå" + :color/gray "Grå" + :color/green "Grønn" + :color/pink "Rosa" + :color/purple "Lilla"/logseq$ + :color/red "Rød" + :color/yellow "Gul" + :content/copy-block-url "Kopier blokk URL" + :content/copy-export-as "Kopier / Eksporter som.." + :content/copy-ref "Kopier denne referansen" + :content/delete-ref "Slett denne referansen" + :content/replace-with-embed "Erstatt med innebygging" + :content/replace-with-text "Erstatt med tekst" + :context-menu/input-template-name "Hva heter malen?" + :context-menu/make-a-flashcard "Lag et Flashcard" + :context-menu/make-a-template "Lag en Mal" + :context-menu/preview-flashcard "Forhåndsvis Flashcard" + :context-menu/template-exists-warning "Malen eksisterer allerde!" + :context-menu/template-include-parent-block "Inkluder overordnet blokk i malen?" + :context-menu/toggle-number-list "Veksle nummerliste" + :dev/show-block-ast "(Dev) Vis blokk AST" + :dev/show-block-data "(Dev) Vis blokk data" + :dev/show-page-ast "(Dev) Vis side AST" + :dev/show-page-data "(Dev) Vis side data" + :editor/collapse-block-children "Skjul alle" + :editor/cycle-todo "Roterer TODO statusen for gjeldende element" + :editor/delete-selection "Slett valgte blokker" + :editor/expand-block-children "Utvid alle" + :file/validate-existing-file-error "Siden eksisterer allerede i en annen fil: {1}, nåværen..." + :file-rn/all-action "Utfør alle Handlinger!" + :file-rn/apply-rename "Utfør omdøping av filen" + :file-rn/close-panel "Lukk Panel" + :file-rn/confirm-proceed "Oppdater format!" + :file-rn/filename-desc-1 "Denne innstillingen konfigurerer hvordan en side blir lagret til en ..." + :file-rn/filename-desc-2 "Noen tegn som \"/\" eller \"?\" er ikke gyldige for en..." + :file-rn/filename-desc-3 "Logseq erstatter ugyldige tegn med deres URL ..." + :file-rn/filename-desc-4 "Skilletegnet for navnerom \"/\" brukes også av \"_..." + :file-rn/format-deprecated "Du bruker for øyeblikket et utdatert format. Oppdat..." + :file-rn/instruct-1 "Det er en to-trinns prosess å oppdatere formatet for filnavn:" + :file-rn/instruct-2 "1. Klikk " + :file-rn/instruct-3 "2. Følg instruksjonene under for å gi filen et nytt navn..." + :file-rn/legend "🟢 Valgfri omdøping; 🟡 Omdøping kreves..." + :file-rn/need-action "Omdøping av fil er anbefalt for å matche de nye..." + :file-rn/no-action "Bra jobba! Well done! Ingen ytterligere tiltak kreves." + :file-rn/optional-rename "Forslag: " + :file-rn/or-select-actions " eller gi filer nytt navn individuelt under, så " + :file-rn/or-select-actions-2 ". Disse handlingene er ikke tilgjengelige når du lukker ..." + :file-rn/otherwise-breaking "Eller tittelen vil bli" + :file-rn/re-index "Re-indksering er sterkt anbefalt etter at filene er..." + :file-rn/rename "Omdøp fil \"{1}\" til \"{2}\"" + :file-rn/select-confirm-proceed "Dev: skriv format" + :file-rn/select-format "(Uviklermodus Operasjon, Farlig!) Velg filenav..." + :file-rn/suggest-rename "Handling kreves: " + :file-rn/unreachable-title "Advarsel! Navnet på siden vil bli {1} under nåvære.." + :left-side-bar/create "Opprett" + :left-side-bar/new-whiteboard "Nytt whiteboard" + :notification/clear-all "Fjern alt" + :on-boarding/tour-whiteboard-home "{1} Hjem for dine whiteboards" + :on-boarding/tour-whiteboard-home-description "Whiteboards har sin egen seksjon i appen hvo..." + :on-boarding/tour-whiteboard-new "{1} Lag nytt whiteboard" + :on-boarding/tour-whiteboard-new-description "Det er mange måter å lage et nytt whiteboard på..." + :on-boarding/welcome-whiteboard-modal-description "Whiteboards er et fantastisk verktøy for brainstorming og ..." + :on-boarding/welcome-whiteboard-modal-skip "Hopp over" + :on-boarding/welcome-whiteboard-modal-start "Start med whiteboard" + :on-boarding/welcome-whiteboard-modal-title "Et nytt lerret for dine tanker." + :page/logseq-is-having-a-problem "Logseq har et problem. Prøver å få den tilbake ..." + :page/show-whiteboards "Vis whiteboards" + :page/something-went-wrong "Noe gikk galt" + :page/step "Steg {1}" + :page/try "Prøv" + :pdf/doc-metadata "Dokument metadata" + :pdf/hl-block-colored "Farget merkelapp for å label for utheve blokk" + :plugin/found-n-updates "Fant {1} oppdatering" + :plugin/found-updates "Nye oppateringer" + :plugin/update-all-selected "Oppdater alle valgte" + :plugin/updates-downloading "Laster ned oppdateringer" + :plugin.install-from-file/menu-title "Installer fra plugins.edn" + :plugin.install-from-file/notice "Følgende plugins vil erstatte dine plugins:" + :plugin.install-from-file/success "Alle plugins er installert!" + :plugin.install-from-file/title "Installer plugins fra plugins.edn" + :right-side-bar/history "(Dev) Angre/Gjør om logg" + :right-side-bar/whiteboards "Whiteboards" + :search/items "elementer" + :search-item/block "Blokk" + :search-item/file "Fil" + :search-item/page "Side" + :search-item/whiteboard "Whiteboard" + :select/default-select-multiple "Velg en eller flere" + :settings-page/alpha-features "Alpha funksjoner" + :settings-page/auto-expand-block-refs "Utvid blokkreferanser automatisk når zoomet inn..." + :settings-page/beta-features "Beta funksjoner" + :settings-page/clear-cache-warning "Tømming av hurtigbufferen vil forkaste dine åpne grafer. Du m..." + :settings-page/custom-date-format-warning "Re-indeksering kreves! Eksisterernde dagbokreferanse vi..." + :settings-page/disable-sentry-desc "Logseq vil aldri samle inn dine lokale graf sin databas..." + :settings-page/edit-setting "Rediger" + :settings-page/enable-whiteboards "Whiteboards" + :settings-page/filename-format "Filnavn format" + :settings-page/login-prompt "For å få tilgang til nye funksjoner før alle andre må du..." + :settings-page/preferred-pasting-file "Foretrekk innliming av fil" + :settings-page/show-full-blocks "Vis alle linjer av en blokkreferanse" + :settings-page/tab-assets "Ressurser" + :whiteboard/link-whiteboard-or-block "Lenk whiteboard/side/blokk"} :pt-BR {:on-boarding/demo-graph "Esse é um grafo de demonstração, mudanças não serão salvas enquanto uma pasta local não for aberta." :on-boarding/add-graph "Adicionar grafo" diff --git a/src/main/frontend/modules/shortcut/dicts.cljc b/src/main/frontend/modules/shortcut/dicts.cljc index 836d76e5ab..8cedcb23a5 100644 --- a/src/main/frontend/modules/shortcut/dicts.cljc +++ b/src/main/frontend/modules/shortcut/dicts.cljc @@ -1135,7 +1135,47 @@ :command.ui/goto-plugins "Gå til dashbord for utvidelser" ;; :command.ui/open-new-window "Åpne et nytt vindu" :command.ui/select-theme-color "Velg tilgjengelige temafarger" - :command.ui/toggle-cards "Veksle kort"} + :command.ui/toggle-cards "Veksle kort" + :command.dev/show-block-ast "(Dev) Vis blokk AST" + :command.dev/show-block-data "(Dev) Vis blokk data" + :command.dev/show-page-ast "(Dev) Vis side AST" + :command.dev/show-page-data "(Dev) Vis side data" + :command.editor/copy-page-url "Kopier side url" + :command.editor/new-whiteboard "Nytt whiteboard" + :command.editor/select-parent "Velg overordnet blokk" + :command.editor/toggle-number-list "Veksle nummerliste" + :command.editor/toggle-undo-redo-mode "Veksle angremodus (global eller kun side)" + :command.go/whiteboards "Gå til whiteboards" + :command.graph/export-as-html "Eksporter offentlig graf som html" + :command.pdf/find "Pdf: Søk tekst i nåværende pdf doc" + :command.sidebar/close-top "Lukker øverste objekt i høyre sidestolpe" + :command.ui/clear-all-notifications "Fjern alle varsler" + :command.ui/install-plugins-from-file "Installer plugins fra plugins.edn" + :command.whiteboard/bring-forward "Flytt fremover" + :command.whiteboard/bring-to-front "Flytt fremst" + :command.whiteboard/connector "Koblingsverktøy" + :command.whiteboard/ellipse "Ellipseverktøy" + :command.whiteboard/eraser "Sletteverktøy" + :command.whiteboard/group "Velg gruppe" + :command.whiteboard/highlighter "Merkepenn" + :command.whiteboard/lock "Lås seleksjon" + :command.whiteboard/pan "Panoreringsverktøy" + :command.whiteboard/pencil "Blyantverktøy" + :command.whiteboard/portal "Portalverktøy" + :command.whiteboard/rectangle "Rektangelverktøy" + :command.whiteboard/reset-zoom "Tilbakestill zoom" + :command.whiteboard/select "Valg-verktøy" + :command.whiteboard/send-backward "Flytt bakover" + :command.whiteboard/send-to-back "Flytt bakerst" + :command.whiteboard/text "Tekst-verktøy" + :command.whiteboard/toggle-grid "Veksle rutenett på lerretet" + :command.whiteboard/ungroup "Del opp gruppe" + :command.whiteboard/unlock "Lås opp seleksjon" + :command.whiteboard/zoom-in "Zoom inn" + :command.whiteboard/zoom-out "Zoom ut" + :command.whiteboard/zoom-to-fit "Zoom til tegning" + :command.whiteboard/zoom-to-selection "Zoom for å passe seleksjonen" + :shortcut.category/whiteboard "Whiteboard"} :pt-PT {:shortcut.category/formatting "Formatação" :shortcut.category/basics "Básico" From c19094288bcf8d71c4b56ad59a4a43d3aa7116bc Mon Sep 17 00:00:00 2001 From: ingepettersen <47382243+ingepettersen@users.noreply.github.com> Date: Fri, 5 May 2023 10:16:55 +0200 Subject: [PATCH 06/81] Fixed bad paste --- src/main/frontend/dicts.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/dicts.cljc b/src/main/frontend/dicts.cljc index 26bbf2f8e8..0c4d181640 100644 --- a/src/main/frontend/dicts.cljc +++ b/src/main/frontend/dicts.cljc @@ -2739,7 +2739,7 @@ :color/gray "Grå" :color/green "Grønn" :color/pink "Rosa" - :color/purple "Lilla"/logseq$ + :color/purple "Lilla" :color/red "Rød" :color/yellow "Gul" :content/copy-block-url "Kopier blokk URL" From 2456c7f835c726c1b7bd384581d5085c6b7cbe34 Mon Sep 17 00:00:00 2001 From: Bad3r Date: Fri, 5 May 2023 15:24:56 -0400 Subject: [PATCH 07/81] enhance: update config.edn template (#9287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance: update config.edn template this is a replacement to #9034 - [x] Replace 'repo' w/ graph or graph folder, respectively. - [x] Each configuration options documentation must start with a capital letter and end with a dot to maintain uniformity. - [x] Maintain uniformity by using the same language and documentation style where applicable - [x] Validate spelling and grammar - [x] Uncomment UI configurable options and set them to the default value - At present, when a configuration option like `:ui/show-brackets? true` is commented out in the template; Logseq will add a new line to the bottom of the configuration template if the user toggles it from the UI instead of updating the existing variable. - [x] define default values where applicable - [x] Add warnings about potential issues - [x] Validate the completeness of the template - [x] Ensure that the `L` in Logseq is always capitalized - [x] Use "Logseq" instead of "the app" when referring to Logseq. - [x] Review Default Values * clean up 🧹 * enhance: add example for journal title date format * clean up 🧹 * fix: indentation --- templates/config.edn | 427 +++++++++++++++++++++++++------------------ 1 file changed, 249 insertions(+), 178 deletions(-) diff --git a/templates/config.edn b/templates/config.edn index e1972c2844..428491e1bd 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -1,137 +1,171 @@ {:meta/version 1 - ;; Currently, we support either "Markdown" or "Org". - ;; This can overwrite your global preference so that - ;; maybe your personal preferred format is Org but you'd - ;; need to use Markdown for some projects. - ;; :preferred-format "" + ;; Set the preferred format. + ;; Available options: + ;; - Markdown (default) + ;; - Org + :preferred-format "Markdown" - ;; Preferred workflow style. - ;; Value is either ":now" for NOW/LATER style, - ;; or ":todo" for TODO/DOING style. + ;; Set the preferred workflow style. + ;; Available options: + ;; - :now for NOW/LATER style (default) + ;; - :todo for TODO/DOING style :preferred-workflow :now - ;; The app will ignore those directories or files. - ;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"] + ;; Exclude directories/files. + ;; Example usage: + ;; :hidden ["/archived" "/test.md" "../assets/archived"] :hidden [] - ;; When creating the new journal page, the app will use your template if there is one. - ;; You only need to input your template name here. + ;; Define the default journal page template. + ;; Enter the template name between the quotes. :default-templates {:journals ""} - ;; Set a custom date format for journal page title - ;; Example: - ;; :journal/page-title-format "EEE, do MMM yyyy" + ;; Set a custom date format for the journal page title. + ;; Example usage: + ;; :journal/page-title-format "EEE do, MMM yyyy" + ;; e.g., "Tue 19th, Jan 2038" + ;; Default value: "MMM do, yyyy" + ;; e.g., "Jan 19th, 2038" + :journal/page-title-format "MMM do, yyyy" - ;; Whether to enable hover on tooltip preview feature - ;; Default is true, you can also toggle this via setting page + ;; Specify the journal filename format using a valid date format string. + ;; !Warning: + ;; This configuration is not retroactive and affects only new journals. + ;; To show old journal files in the app, manually rename the files in the + ;; journal directory to match the new format. + ;; Default value: "yyyy_MM_dd" + ;; :journal/file-name-format "yyyy_MM_dd" + + ;; Enable tooltip preview on hover. + ;; Default value: true :ui/enable-tooltip? true - ;; Show brackets around page references - ;; :ui/show-brackets? true + ;; Display brackets [[]] around page references. + ;; Default value: true + :ui/show-brackets? true - ;; Enable showing the body of blocks when referencing them. + ;; Display all lines of a block when referencing ((block)). + ;; Default value: false :ui/show-full-blocks? false - ;; Expand block references automatically when zoom-in + ;; Automatically expand block references when zooming in. + ;; Default value: true :ui/auto-expand-block-refs? true - ;; Enable Block timestamp + ;; Enable Block timestamps. + ;; Default value: false :feature/enable-block-timestamps? false - ;; Enable remove accents when searching. - ;; After toggle this option, please remember to rebuild your search index by press (cmd+c cmd+s). + ;; Disable accent marks when searching. + ;; After changing this setting, rebuild the search index by pressing (^C ^S). + ;; Default value: true :feature/enable-search-remove-accents? true - ;; Enable journals - ;; :feature/enable-journals? true + ;; Enable journals. + ;; Default value: true + :feature/enable-journals? true - ;; Enable flashcards - ;; :feature/enable-flashcards? true + ;; Enable flashcards. + ;; Default value: true + :feature/enable-flashcards? true - ;; Enable Whiteboards - ;; :feature/enable-whiteboards? true + ;; Enable whiteboards. + ;; Default value: true + :feature/enable-whiteboards? true - ;; Disable the built-in Scheduled tasks and deadlines query - ;; :feature/disable-scheduled-and-deadline-query? true + ;; Disable the journal's built-in 'Scheduled tasks and deadlines' query. + ;; Default value: false + :feature/disable-scheduled-and-deadline-query? false - ;; Specify the number of days in the future to display in the - ;; scheduled tasks and deadlines query, with a default value of 7 which - ;; displays tasks for the next 7 days. + ;; Specify the number of days displayed in the future for + ;; the 'scheduled tasks and deadlines' query. ;; Example usage: - ;; Display all scheduled and deadline blocks for the next 14 days + ;; Display all scheduled and deadline blocks for the next 14 days: ;; :scheduled/future-days 14 + ;; Default value: 7 + :scheduled/future-days 7 - ;; Specify the date on which the week starts. - ;; Goes from 0 to 6 (Monday to Sunday), default to 6 + ;; Specify the first day of the week. + ;; Available options: + ;; - integer from 0 to 6 (Monday to Sunday) + ;; Default value: 6 (Sunday) :start-of-week 6 - ;; Specify a custom CSS import - ;; This option take precedence over your local `logseq/custom.css` file - ;; You may find a list of awesome logseq themes here: - ;; https://github.com/logseq/awesome-logseq#css-themes - ;; Example: - ;; :custom-css-url "@import url('https://cdn.jsdelivr.net/gh/dracula/logseq@master/custom.css');" + ;; Import a custom CSS file. + ;; This option takes precedence over the local `logseq/custom.css` file. + ;; Example usage: + ;; :custom-css-url "https://cdn.logseq.com/custom.css" + :custom-css-url "" - ;; Specify a custom js import - ;; This option take precedence over your local `logseq/custom.js` file - ;; :custom-js-url "" + ;; Import a custom JS file. + ;; This option takes precedence over the local `logseq/custom.js` file. + ;; Example usage: + ;; :custom-js-url "https://cdn.logseq.com/custom.js" + :custom-js-url "" ;; Set a custom Arweave gateway ;; Default gateway: https://arweave.net - ;; :arweave/gateway "" + :arweave/gateway "https://arweave.net" - ;; Set Bullet indentation when exporting - ;; default option: tab - ;; Possible options for `:export/bullet-indentation` are - ;; 1. `:eight-spaces` as eight spaces - ;; 2. `:four-spaces` as four spaces - ;; 3. `:two-spaces` as two spaces - ;; :export/bullet-indentation :tab + ;; Set bullet indentation when exporting + ;; Available options: + ;; - `:eight-spaces` as eight spaces + ;; - `:four-spaces` as four spaces + ;; - `:two-spaces` as two spaces + ;; - `:tab` as a tab character (default) + :export/bullet-indentation :tab - ;; When :all-pages-public? true, export repo would export all pages within that repo. - ;; Regardless of whether you've set any page to public or not. - ;; Example: - ;; :publishing/all-pages-public? true + ;; Publish all pages within the Graph + ;; regardless of whether individual pages have been marked as public. + ;; Default value: false + :publishing/all-pages-public? false - ;; Specify default home page and sidebar status for Logseq - ;; If not specified, Logseq default opens journals page on startup - ;; value for `:page` is name of page - ;; Possible options for `:sidebar` are - ;; 1. `"Contents"` to open up `Contents` in sidebar by default - ;; 2. `page name` to open up some page in sidebar - ;; 3. Or multiple pages in an array ["Contents" "Page A" "Page B"] - ;; If `:sidebar` is not set, sidebar will be hidden - ;; Example: - ;; 1. Setup page "Changelog" as home page and "Contents" in sidebar + ;; Set the default home page and sidebar status. + ;; Define the default home page and sidebar status. + ;; If unspecified, Logseq will load the journal page by default on startup. + ;; The `:page` value represents the name of the page displayed at startup. + ;; Available options for `:sidebar` are: + ;; - "Contents" to display the Contents page in the right sidebar. + ;; - A specific page name to display in the right sidebar. + ;; - An array of multiple pages, e.g., ["Contents" "Page A" "Page B"]. + ;; If `:sidebar` remains unset, the right sidebar will stay hidden. + ;; Examples: + ;; 1. Set "Changelog" as the home page and display "Contents" in the right sidebar: ;; :default-home {:page "Changelog", :sidebar "Contents"} - ;; 2. Setup page "Jun 3rd, 2021" as home page without sidebar + ;; 2. Set "Jun 3rd, 2021" as the home page without the right sidebar: ;; :default-home {:page "Jun 3rd, 2021"} - ;; 3. Setup page "home" as home page with multiple pages in sidebar - ;; :default-home {:page "home" :sidebar ["page a" "page b"]} + ;; 3. Set "home" as the home page and display multiple pages in the right sidebar: + ;; :default-home {:page "home", :sidebar ["Page A" "Page B"]} + :default-home {} - ;; Tell logseq to use a specific folder in the repo as a default location for notes - ;; if not specified, notes are stored in `pages` directory - ;; :pages-directory "your-directory" + ;; Set the default location for storing notes. + ;; Default value: "pages" + :pages-directory "pages" - ;; Tell logseq to use a specific folder in the repo as a default location for journals - ;; if not specified, journals are stored in `journals` directory - ;; :journals-directory "your-directory" + ;; Set the default location for storing journals. + ;; Default value: "journals" + :journals-directory "journals" - ;; Set this to true will convert - ;; `[[Grant Ideas]]` to `[[file:./grant_ideas.org][Grant Ideas]]` for org-mode - ;; For more, see https://github.com/logseq/logseq/issues/672 - ;; :org-mode/insert-file-link? true + ;; Set the default location for storing whiteboards. + ;; If not specified, whiteboards will be stored in the 'whiteboards' subdirectory. + :whiteboards-directory "whiteboards" - ;; Setup custom shortcuts under `:shortcuts` key + ;; Enabling this option converts + ;; [[Grant Ideas]] to [[file:./grant_ideas.org][Grant Ideas]] for org-mode. + ;; For more information, visit https://github.com/logseq/logseq/issues/672 + :org-mode/insert-file-link? false + + ;; Configure custom shortcuts. ;; Syntax: - ;; 1. `+` means keys pressing simultaneously. eg: `ctrl+shift+a` - ;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s` - ;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac - ;; 4. use `false` to disable particular shortcut - ;; 5. you can define multiple bindings for one action, eg `["ctrl+j" "down"]` - ;; full list of configurable shortcuts are available below: + ;; 1. + indicates simultaneous key presses, e.g., `Ctrl+Ahift+a`. + ;; 2. A space between keys represents key chords, e.g., `t s` means + ;; pressing `t` followed by `s`. + ;; 3. mod refers to `Ctrl` for Windows/Linux and `Command` for Mac. + ;; 4. Use false to disable a specific shortcut. + ;; 5. You can define multiple bindings for a single action, e.g., ["ctrl+j" "down"]. + ;; The full list of configurable shortcuts is available at: ;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs ;; Example: ;; :shortcuts @@ -146,33 +180,37 @@ ;; :editor/right ["ctrl+l" "right"]} :shortcuts {} - ;; By default, pressing `Enter` in the document mode will create a new line. - ;; Set this to `true` so that it's the same behaviour as the usual outliner mode. + ;; Configure the behavior of pressing Enter in document mode. + ;; if set to true, pressing Enter will create a new block. + ;; Default value: false :shortcut/doc-mode-enter-for-new-block? false ;; Block content larger than `block/content-max-length` will not be searchable ;; or editable for performance. + ;; Default value: 10000 :block/content-max-length 10000 - ;; Whether to show command doc on hover + ;; Display command documentation on hover. + ;; Default value: true :ui/show-command-doc? true - ;; Whether to show empty bullets for non-document mode (the default mode) + ;; Display empty bullet points. :ui/show-empty-bullets? false - ;; Pre-defined :view function to use with advanced queries + ;; Pre-defined :view function to use with advanced queries. :query/views {:pprint (fn [r] [:pre.code (pprint r)])} - ;; Pre-defined :result-transform function for use with advanced queries + ;; Advanced queries `:result-transform` function. + ;; Transform the query result before displaying it. :query/result-transforms {:sort-by-priority (fn [result] (sort-by (fn [h] (get h :block/priority "Z")) result))} - ;; The app will show those queries in today's journal page, - ;; the "NOW" query asks the tasks which need to be finished "now", - ;; the "NEXT" query asks the future tasks. + ;; The following queries will be displayed at the bottom of today's journal page. + ;; The "NOW" query returns tasks with "NOW" or "DOING" status. + ;; The "NEXT" query returns tasks with "NOW", "LATER", or "TODO" status. :default-queries {:journals [{:title "🔨 NOW" @@ -207,25 +245,26 @@ :group-by-page? false :collapsed? false}]} - ;; Add your own commands to slash menu to speedup. - ;; E.g. + ;; Add custom commands to the command palette + ;; Example usage: ;; :commands ;; [ - ;; ["js" "Javascript"] - ;; ["md" "Markdown"] - ;; ] - :commands - [] + ;; ["js" "Javascript"] + ;; ["md" "Markdown"] + ;; ] + :commands [] - ;; By default, a block can only be collapsed if it has some children. - ;; `:outliner/block-title-collapse-enabled? true` enables a block with a title - ;; (multiple lines) can be collapsed too. For example: + ;; Enable collapsing blocks with titles but no children. + ;; By default, only blocks with children can be collapsed. + ;; Setting `:outliner/block-title-collapse-enabled?` to true allows collapsing + ;; blocks with titles (multiple lines) and content. For example: ;; - block title ;; block content + ;; Default value: false :outliner/block-title-collapse-enabled? false ;; Macros replace texts and will make you more productive. - ;; For example: + ;; Example usage: ;; Change the :macros value below to: ;; {"poem" "Rose is $1, violet's $2. Life's ordered: Org assists you."} ;; input "{{poem red,blue}}" @@ -233,119 +272,151 @@ ;; Rose is red, violet's blue. Life's ordered: Org assists you. :macros {} - ;; The default level to be opened for the linked references. - ;; For example, if we have some example blocks like this: + ;; Configure the default expansion level for linked references. + ;; For example, consider the following block hierarchy: ;; - a [[page]] (level 1) ;; - b (level 2) ;; - c (level 3) ;; - d (level 4) ;; - ;; With the default value of level 2, `b` will be collapsed. - ;; If we set the level's value to 3, `b` will be opened and `c` will be collapsed. + ;; With the default value of level 2, block b will be collapsed. + ;; If the level's value is set to 3, block c will be collapsed. + ;; Default value: 2 :ref/default-open-blocks-level 2 - :ref/linked-references-collapsed-threshold 50 + ;; Configure the threshold for linked references before collapsing. + ;; Default value: 100 + :ref/linked-references-collapsed-threshold 100 ;; Favorites to list on the left sidebar :favorites [] - ;; any number between 0 and 1 (the greater it is the faster the changes of the next-interval of card reviews) (default 0.5) - ;; :srs/learning-fraction 0.5 + ;; Set flashcards interval. + ;; Expected value: + ;; - Float between 0 and 1 + ;; higher values result in faster changes to the next review interval. + ;; Default value: 0.5 + :srs/learning-fraction 0.5 - ;; the initial interval after the first successful review of a card (default 4) - ;; :srs/initial-interval 4 + ;; Set the initial interval after the first successful review of a card. + ;; Default value: 4 + :srs/initial-interval 4 - ;; hide specific properties for blocks - ;; E.g. :block-hidden-properties #{:created-at :updated-at} - ;; :block-hidden-properties #{} + ;; Hide specific block properties. + ;; Example usage: + ;; :block-hidden-properties #{:public :icon} + :block-hidden-properties #{} - ;; Enable all your properties to have corresponding pages - :property-pages/enabled? true + ;; Create a page for all properties. + ;; Default value: false + :property-pages/enabled? false ;; Properties to exclude from having property pages - ;; E.g.:property-pages/excludelist #{:duration :author} - ;; :property-pages/excludelist + ;; Example usage: + ;; :property-pages/excludelist #{:duration :author} + :property-pages-exclude-list #{} ;; By default, property value separated by commas will not be treated as ;; page references. You can add properties to enable it. - ;; E.g. :property/separated-by-commas #{:alias :tags} - ;; :property/separated-by-commas #{} + ;; Example usage: + ;; :property/separated-by-commas #{:alias :tags} + :property/separated-by-commas #{} ;; Properties that are ignored when parsing property values for references - ;; :ignored-page-references-keywords #{:author :startup} + ;; Example usage: + ;; :ignored-page-references-keywords #{:author :website} + :ignored-page-references-keywords #{} - ;; logbook setup - ;; :logbook/settings - ;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated - ;; :enabled-in-all-blocks true ;display logbook in all blocks after timetracking - ;; :enabled-in-timestamped-blocks false ;don't display logbook at all - ;; } + ;; logbook configuration. + :logbook/settings + {; Disable logbook. (Default value: false) + :enabled-in-timestamped-blocks false + ;; limit logbook to minutes, eliminating seconds. (Default value: false) + :with-second-support? false + ;; display logbook in all blocks after time-tracking. (Default value: false) + :enabled-in-all-blocks false} - ;; Mobile photo uploading setup - ;; :mobile/photo - ;; {:allow-editing? true - ;; :quality 80} + ;; Mobile photo upload configuration. + :mobile/photo + {:allow-editing? true + :quality 80} ;; Mobile features options ;; Gestures - ;; :mobile + ;; Example usage: + ;; :mobile ;; {:gestures/disabled-in-block-with-tags ["kanban"]} + :mobile + {:gestures/disabled-in-block-with-tags []} ;; Extra CodeMirror options ;; See https://codemirror.net/5/doc/manual.html#config for possible options + ;; Example usage: ;; :editor/extra-codemirror-options {:keyMap "emacs" :lineWrapping true} + :editor/extra-codemirror-options + {:lineWrapping false ; Default value: false + :lineNumbers true ; Default value: true + :readOnly false} ; Default value: false ;; Enable logical outdenting - ;; :editor/logical-outdenting? true + ;; Default value: false + :editor/logical-outdenting? false - ;; When both text and a file are in the clipboard, paste the file - ;; :editor/preferred-pasting-file? true + ;; Prefer pasting the file when text and a file are in the clipboard. + ;; Default value: false + :editor/preferred-pasting-file? false - ;; Quick capture templates for receiving contents from other apps. + ;; Quick capture templates for receiving content from other apps. ;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded - ;; by received contents from other apps. Note: the {} cannot be omitted. + ;; by receiving content from other apps. Note: the {} cannot be omitted. ;; - {time}: capture time ;; - {date}: capture date using current date format, use `[[{date}]]` to get a page reference ;; - {text}: text that users selected before sharing. - ;; - {url}: url or assets path for media files stored in Logseq. - ;; You can also reorder them, or even only use one or two of them in the template. - ;; You can also insert or format any text in the template as shown in the following examples. + ;; - {url}: URL or assets path for media files stored in Logseq. + ;; You can also reorder them or use only one or two of them in the template. + ;; You can also insert or format any text in the template, as shown in the following examples. ;; :quick-capture-templates - ;; {:text "[[quick capture]] **{time}**: {text} from {url}" - ;; :media "[[quick capture]] **{time}**: {url}"} + :quick-capture-templates + {:text "[[quick capture]] **{time}**: {text} — {url}" + :media "[[quick capture]] **{time}**: {url}"} + + ;; Quick capture options. + ;; - insert-today? Insert the capture at the end of today's journal page (boolean). + ;; - redirect-page? Redirect to the quick capture page after capturing (boolean). + ;; - default-page The default page to capture to if insert-today? is false (string). + :quick-capture-options + {:insert-today? false ;; Default value: true + :redirect-page? false ;; Default value: false + :default-page "quick capture"} ;; Default page: "quick capture" - ;; Quick capture options - ;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page "my page"} ;; File sync options ;; Ignore these files when syncing, regexp is supported. - ;; :file-sync/ignore-files [] + :file-sync/ignore-files [] - ;; dwim (do what I mean) for Enter key when editing. - ;; Context-awareness of Enter key makes editing more easily - ; :dwim/settings { - ; :admonition&src? true - ; :markup? false - ; :block-ref? true - ; :page-ref? true - ; :properties? true - ; :list? true - ; } + ;; Configure the Enter key behavior for + ;; context-aware editing with DWIM (Do What I Mean). + ;; context-aware Enter key behavior implies that pressing Enter will + ;; have different outcomes based on the context. + ;; For instance, pressing Enter within a list generates a new list item, + ;; whereas pressing Enter in a block reference opens the referenced block. + :dwim/settings + {:admonition&src? true ;; Default value: true + :markup? false ;; Default value: false + :block-ref? true ;; Default value: true + :page-ref? true ;; Default value: true + :properties? true ;; Default value: true + :list? true} ;; Default value: true - ;; Decide the way to escape the special characters in the page title. + ;; Configure the escaping method for special characters in page titles. ;; Warning: - ;; This is a dangerous operation. If you want to change the setting, - ;; should access the setting `Filename format` and follow the instructions. - ;; Or you have to rename all the affected files manually then re-index on all - ;; clients after the files are synced. Wrong handling may cause page titles - ;; containing special characters to be messy. - ;; Available values: - ;; :file/name-format :triple-lowbar - ;; ;use triple underscore `___` for slash `/` in page title - ;; ;use Percent-encoding for other invalid characters - :file/name-format :triple-lowbar - - ;; specify the format of the filename for journal files - ;; :journal/file-name-format "yyyy_MM_dd" - - } + ;; This is a dangerous operation. To modify the setting, + ;; access the 'Filename format' setting and follow the instructions. + ;; Othwerwise, You may need to manually rename all affected files and + ;; re-index them on all clients after synchronization. + ;; Incorrect handling may result in messy page titles. + ;; Available options: + ;; - :triple-lowbar (default) + ;; ;use triple underscore `___` for slash `/` in page title + ;; ;use Percent-encoding for other invalid characters + :file/name-format :triple-lowbar} From f6cf60af3d58efa3cb98de25d893ca6524f3a0ff Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 5 May 2023 15:25:16 -0400 Subject: [PATCH 08/81] Followup to #9287 - Address feedback about commenting new values - Revert comments on custom-css-url and custom-js-url as they are more acccurate - Revert config values that were changed --- templates/config.edn | 124 +++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 69 deletions(-) diff --git a/templates/config.edn b/templates/config.edn index 428491e1bd..d312618e53 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -4,7 +4,7 @@ ;; Available options: ;; - Markdown (default) ;; - Org - :preferred-format "Markdown" + ;; :preferred-format "Markdown" ;; Set the preferred workflow style. ;; Available options: @@ -23,12 +23,10 @@ {:journals ""} ;; Set a custom date format for the journal page title. - ;; Example usage: - ;; :journal/page-title-format "EEE do, MMM yyyy" - ;; e.g., "Tue 19th, Jan 2038" ;; Default value: "MMM do, yyyy" ;; e.g., "Jan 19th, 2038" - :journal/page-title-format "MMM do, yyyy" + ;; Example usage e.g., "Tue 19th, Jan 2038" + ;; :journal/page-title-format "EEE do, MMM yyyy" ;; Specify the journal filename format using a valid date format string. ;; !Warning: @@ -44,7 +42,7 @@ ;; Display brackets [[]] around page references. ;; Default value: true - :ui/show-brackets? true + ;; :ui/show-brackets? true ;; Display all lines of a block when referencing ((block)). ;; Default value: false @@ -65,19 +63,19 @@ ;; Enable journals. ;; Default value: true - :feature/enable-journals? true + ;; :feature/enable-journals? true ;; Enable flashcards. ;; Default value: true - :feature/enable-flashcards? true + ;; :feature/enable-flashcards? true ;; Enable whiteboards. ;; Default value: true - :feature/enable-whiteboards? true + ;; :feature/enable-whiteboards? true ;; Disable the journal's built-in 'Scheduled tasks and deadlines' query. ;; Default value: false - :feature/disable-scheduled-and-deadline-query? false + ;; :feature/disable-scheduled-and-deadline-query? false ;; Specify the number of days displayed in the future for ;; the 'scheduled tasks and deadlines' query. @@ -85,7 +83,7 @@ ;; Display all scheduled and deadline blocks for the next 14 days: ;; :scheduled/future-days 14 ;; Default value: 7 - :scheduled/future-days 7 + ;; :scheduled/future-days 7 ;; Specify the first day of the week. ;; Available options: @@ -93,21 +91,19 @@ ;; Default value: 6 (Sunday) :start-of-week 6 - ;; Import a custom CSS file. + ;; Specify a custom CSS import. ;; This option takes precedence over the local `logseq/custom.css` file. ;; Example usage: - ;; :custom-css-url "https://cdn.logseq.com/custom.css" - :custom-css-url "" + ;; :custom-css-url "@import url('https://cdn.jsdelivr.net/gh/dracula/logseq@master/custom.css');" - ;; Import a custom JS file. + ;; Specify a custom JS import. ;; This option takes precedence over the local `logseq/custom.js` file. ;; Example usage: ;; :custom-js-url "https://cdn.logseq.com/custom.js" - :custom-js-url "" ;; Set a custom Arweave gateway ;; Default gateway: https://arweave.net - :arweave/gateway "https://arweave.net" + ;; :arweave/gateway "https://arweave.net" ;; Set bullet indentation when exporting ;; Available options: @@ -115,12 +111,12 @@ ;; - `:four-spaces` as four spaces ;; - `:two-spaces` as two spaces ;; - `:tab` as a tab character (default) - :export/bullet-indentation :tab + ;; :export/bullet-indentation :tab ;; Publish all pages within the Graph ;; regardless of whether individual pages have been marked as public. ;; Default value: false - :publishing/all-pages-public? false + ;; :publishing/all-pages-public? false ;; Set the default home page and sidebar status. ;; Define the default home page and sidebar status. @@ -138,28 +134,27 @@ ;; :default-home {:page "Jun 3rd, 2021"} ;; 3. Set "home" as the home page and display multiple pages in the right sidebar: ;; :default-home {:page "home", :sidebar ["Page A" "Page B"]} - :default-home {} ;; Set the default location for storing notes. ;; Default value: "pages" - :pages-directory "pages" + ;; :pages-directory "pages" ;; Set the default location for storing journals. ;; Default value: "journals" - :journals-directory "journals" + ;; :journals-directory "journals" ;; Set the default location for storing whiteboards. ;; If not specified, whiteboards will be stored in the 'whiteboards' subdirectory. - :whiteboards-directory "whiteboards" + ;; :whiteboards-directory "whiteboards" ;; Enabling this option converts ;; [[Grant Ideas]] to [[file:./grant_ideas.org][Grant Ideas]] for org-mode. ;; For more information, visit https://github.com/logseq/logseq/issues/672 - :org-mode/insert-file-link? false + ;; :org-mode/insert-file-link? false ;; Configure custom shortcuts. ;; Syntax: - ;; 1. + indicates simultaneous key presses, e.g., `Ctrl+Ahift+a`. + ;; 1. + indicates simultaneous key presses, e.g., `Ctrl+Shift+a`. ;; 2. A space between keys represents key chords, e.g., `t s` means ;; pressing `t` followed by `s`. ;; 3. mod refers to `Ctrl` for Windows/Linux and `Command` for Mac. @@ -286,7 +281,7 @@ ;; Configure the threshold for linked references before collapsing. ;; Default value: 100 - :ref/linked-references-collapsed-threshold 100 + :ref/linked-references-collapsed-threshold 50 ;; Favorites to list on the left sidebar :favorites [] @@ -296,75 +291,66 @@ ;; - Float between 0 and 1 ;; higher values result in faster changes to the next review interval. ;; Default value: 0.5 - :srs/learning-fraction 0.5 + ;; :srs/learning-fraction 0.5 ;; Set the initial interval after the first successful review of a card. ;; Default value: 4 - :srs/initial-interval 4 + ;; :srs/initial-interval 4 ;; Hide specific block properties. ;; Example usage: ;; :block-hidden-properties #{:public :icon} - :block-hidden-properties #{} ;; Create a page for all properties. ;; Default value: false - :property-pages/enabled? false + :property-pages/enabled? true ;; Properties to exclude from having property pages ;; Example usage: ;; :property-pages/excludelist #{:duration :author} - :property-pages-exclude-list #{} ;; By default, property value separated by commas will not be treated as ;; page references. You can add properties to enable it. ;; Example usage: ;; :property/separated-by-commas #{:alias :tags} - :property/separated-by-commas #{} ;; Properties that are ignored when parsing property values for references ;; Example usage: ;; :ignored-page-references-keywords #{:author :website} - :ignored-page-references-keywords #{} ;; logbook configuration. - :logbook/settings - {; Disable logbook. (Default value: false) - :enabled-in-timestamped-blocks false - ;; limit logbook to minutes, eliminating seconds. (Default value: false) - :with-second-support? false - ;; display logbook in all blocks after time-tracking. (Default value: false) - :enabled-in-all-blocks false} + ;; :logbook/settings + ;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated + ;; :enabled-in-all-blocks true ;display logbook in all blocks after timetracking + ;; :enabled-in-timestamped-blocks false ;don't display logbook at all + ;; } ;; Mobile photo upload configuration. - :mobile/photo - {:allow-editing? true - :quality 80} + ;; :mobile/photo + ;; {:allow-editing? true + ;; :quality 80} ;; Mobile features options ;; Gestures ;; Example usage: ;; :mobile ;; {:gestures/disabled-in-block-with-tags ["kanban"]} - :mobile - {:gestures/disabled-in-block-with-tags []} ;; Extra CodeMirror options ;; See https://codemirror.net/5/doc/manual.html#config for possible options ;; Example usage: - ;; :editor/extra-codemirror-options {:keyMap "emacs" :lineWrapping true} - :editor/extra-codemirror-options - {:lineWrapping false ; Default value: false - :lineNumbers true ; Default value: true - :readOnly false} ; Default value: false + ;; :editor/extra-codemirror-options + ;; {:lineWrapping false ; Default value: false + ;; :lineNumbers true ; Default value: true + ;; :readOnly false} ; Default value: false ;; Enable logical outdenting - ;; Default value: false - :editor/logical-outdenting? false + ;; Default value: false + ;; :editor/logical-outdenting? false ;; Prefer pasting the file when text and a file are in the clipboard. - ;; Default value: false - :editor/preferred-pasting-file? false + ;; Default value: false + ;; :editor/preferred-pasting-file? false ;; Quick capture templates for receiving content from other apps. ;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded @@ -376,23 +362,23 @@ ;; You can also reorder them or use only one or two of them in the template. ;; You can also insert or format any text in the template, as shown in the following examples. ;; :quick-capture-templates - :quick-capture-templates - {:text "[[quick capture]] **{time}**: {text} — {url}" - :media "[[quick capture]] **{time}**: {url}"} + ;; :quick-capture-templates + ;; {:text "[[quick capture]] **{time}**: {text} from {url}" + ;; :media "[[quick capture]] **{time}**: {url}"} ;; Quick capture options. ;; - insert-today? Insert the capture at the end of today's journal page (boolean). ;; - redirect-page? Redirect to the quick capture page after capturing (boolean). ;; - default-page The default page to capture to if insert-today? is false (string). - :quick-capture-options - {:insert-today? false ;; Default value: true - :redirect-page? false ;; Default value: false - :default-page "quick capture"} ;; Default page: "quick capture" + ;; :quick-capture-options + ;; {:insert-today? false ;; Default value: true + ;; :redirect-page? false ;; Default value: false + ;; :default-page "quick capture"} ;; Default page: "quick capture" ;; File sync options ;; Ignore these files when syncing, regexp is supported. - :file-sync/ignore-files [] + ;; :file-sync/ignore-files [] ;; Configure the Enter key behavior for ;; context-aware editing with DWIM (Do What I Mean). @@ -400,13 +386,13 @@ ;; have different outcomes based on the context. ;; For instance, pressing Enter within a list generates a new list item, ;; whereas pressing Enter in a block reference opens the referenced block. - :dwim/settings - {:admonition&src? true ;; Default value: true - :markup? false ;; Default value: false - :block-ref? true ;; Default value: true - :page-ref? true ;; Default value: true - :properties? true ;; Default value: true - :list? true} ;; Default value: true + ;; :dwim/settings + ;; {:admonition&src? true ;; Default value: true + ;; :markup? false ;; Default value: false + ;; :block-ref? true ;; Default value: true + ;; :page-ref? true ;; Default value: true + ;; :properties? true ;; Default value: true + ;; :list? true} ;; Default value: true ;; Configure the escaping method for special characters in page titles. ;; Warning: From ea94b3aa6365ecbffb6ced3bdce92eea3e7bdea8 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 5 May 2023 15:27:59 -0400 Subject: [PATCH 09/81] Update dwim list comment as value changed in #9235 --- templates/config.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/config.edn b/templates/config.edn index d312618e53..ec213b7bfc 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -392,7 +392,7 @@ ;; :block-ref? true ;; Default value: true ;; :page-ref? true ;; Default value: true ;; :properties? true ;; Default value: true - ;; :list? true} ;; Default value: true + ;; :list? false} ;; Default value: false ;; Configure the escaping method for special characters in page titles. ;; Warning: From dbeb49b8d2bf5c07e2292b10fdfd7b81773b21ae Mon Sep 17 00:00:00 2001 From: Zhizhen He Date: Sat, 6 May 2023 15:55:00 +0800 Subject: [PATCH 10/81] chore: remove duplicated line --- templates/config.edn | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/config.edn b/templates/config.edn index ec213b7bfc..5e809e2a2c 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -362,7 +362,6 @@ ;; You can also reorder them or use only one or two of them in the template. ;; You can also insert or format any text in the template, as shown in the following examples. ;; :quick-capture-templates - ;; :quick-capture-templates ;; {:text "[[quick capture]] **{time}**: {text} from {url}" ;; :media "[[quick capture]] **{time}**: {url}"} @@ -375,7 +374,6 @@ ;; :redirect-page? false ;; Default value: false ;; :default-page "quick capture"} ;; Default page: "quick capture" - ;; File sync options ;; Ignore these files when syncing, regexp is supported. ;; :file-sync/ignore-files [] From 2effe080545a5d01b32a59d1c22e7abb9ed5aaee Mon Sep 17 00:00:00 2001 From: Andelf Date: Mon, 8 May 2023 16:50:12 +0800 Subject: [PATCH 11/81] fix(android): paste with native input device - use legacy method on Android --- src/main/frontend/handler/paste.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/handler/paste.cljs b/src/main/frontend/handler/paste.cljs index 2ae65968b8..90cdef121c 100644 --- a/src/main/frontend/handler/paste.cljs +++ b/src/main/frontend/handler/paste.cljs @@ -84,7 +84,9 @@ ;; See https://developer.chrome.com/blog/web-custom-formats-for-the-async-clipboard-api/ ;; for a similar example (defn get-copied-blocks [] - (p/let [clipboard-items (when (and js/window (gobj/get js/window "navigator") js/navigator.clipboard) + ;; NOTE: Avoid using navigator clipboard API on Android, it will report a permission error + (p/let [clipboard-items (when (and (not (mobile-util/native-android?)) + js/window (gobj/get js/window "navigator") js/navigator.clipboard) (js/navigator.clipboard.read)) blocks-blob ^js (when clipboard-items (let [types (.-types ^js (first clipboard-items))] From 5c400112ec9d63e8d907eec7e6c8e8c8caff747e Mon Sep 17 00:00:00 2001 From: PerfectPan Date: Sun, 7 May 2023 18:14:58 +0800 Subject: [PATCH 12/81] fix: adjust repeater ui --- src/main/frontend/components/datetime.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/components/datetime.cljs b/src/main/frontend/components/datetime.cljs index 0c82c95a1a..a27642a6cf 100644 --- a/src/main/frontend/components/datetime.cljs +++ b/src/main/frontend/components/datetime.cljs @@ -46,7 +46,7 @@ (let [show? (rum/react *show-repeater?)] (if (or show? (and num duration kind)) [:div.w.full.flex.flex-row.justify-left - [:input#repeater-num.form-input.mt-1.w-8.px-1.sm:w-20.sm:px-2.text-center + [:input#repeater-num.form-input.w-8.mr-2.px-1.sm:w-20.sm:px-2.text-center {:default-value num :on-change (fn [event] (let [value (util/evalue event)] @@ -66,7 +66,7 @@ (swap! *timestamp assoc-in [:repeater :duration] value)) nil) - [:a.ml-1.self-center {:on-click (fn [] + [:a.ml-2.self-center {:on-click (fn [] (reset! *show-repeater? false) (swap! *timestamp assoc :repeater {}))} svg/close]] From fdcf2820f8b7925835fc6ac68b937a2cf123e27c Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Mon, 8 May 2023 13:17:55 +0300 Subject: [PATCH 13/81] fix: delete selection shortcut on whiteboards --- src/main/frontend/handler/editor.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index a160eb1b67..a42434a931 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -3118,7 +3118,7 @@ (state/selection?) (shortcut-delete-selection e) - (whiteboard?) + (and (whiteboard?) (not (state/editing?))) (.deleteShapes (.-api ^js (state/active-tldraw-app))) :else From 8b8bd04ced018dc0f9a35412719ad23c33e13c26 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Mon, 8 May 2023 13:23:17 +0300 Subject: [PATCH 14/81] fix: stop propagation on select component --- tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx b/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx index be24bb2a8f..f992d16aa1 100644 --- a/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/inputs/SelectInput.tsx @@ -56,6 +56,7 @@ export function SelectInput({ position="popper" sideOffset={14} align="center" + onKeyDown={e => e.stopPropagation()} > From 6b94181116dbaec8d72a2fc6dae5dd424f3a5bd1 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 8 May 2023 19:26:14 +0800 Subject: [PATCH 15/81] fix: nested page title can't be clicked --- src/main/frontend/components/page.cljs | 44 +++++++++++++++----------- src/main/frontend/components/page.css | 2 +- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 6484437179..69e5a7fc95 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -37,7 +37,9 @@ [logseq.graph-parser.util :as gp-util] [medley.core :as medley] [reitit.frontend.easy :as rfe] - [rum.core :as rum])) + [rum.core :as rum] + [logseq.graph-parser.util.page-ref :as page-ref] + [logseq.graph-parser.mldoc :as gp-mldoc])) (defn- get-page-name [state] @@ -292,8 +294,8 @@ (rum/local false ::edit?) (rum/local "" ::input-value) {:init (fn [state] - (assoc state ::title-value (atom (nth (:rum/args state) 2))))} - [state page-name icon title _format fmt-journal?] + (assoc state ::title-value (atom (nth (:rum/args state) 3))))} + [state page page-name icon title _format fmt-journal?] (when title (let [*title-value (get state ::title-value) *edit? (get state ::edit?) @@ -304,7 +306,9 @@ untitled? (and whiteboard-page? (parse-uuid page-name)) ;; normal page cannot be untitled right? title (if hls-page? [:a.asset-ref (pdf-utils/fix-local-asset-pagename title)] - (if fmt-journal? (date/journal-title->custom-format title) title)) + (if fmt-journal? + (date/journal-title->custom-format title) + title)) old-name (or title page-name)] [:h1.page-title.flex.cursor-pointer.gap-1.w-full {:class (when-not whiteboard-page? "title") @@ -312,16 +316,16 @@ (when (util/right-click? e) (state/set-state! :page-title/context {:page page-name}))) :on-click (fn [e] - (.preventDefault e) - (if (gobj/get e "shiftKey") - (when-let [page (db/pull repo '[*] [:block/name page-name])] - (state/sidebar-add-block! - repo - (:db/id page) - :page)) - (when (and (not hls-page?) (not fmt-journal?) (not config/publishing?)) - (reset! *input-value (if untitled? "" old-name)) - (reset! *edit? true))))} + (.preventDefault e) + (if (gobj/get e "shiftKey") + (when-let [page (db/pull repo '[*] [:block/name page-name])] + (state/sidebar-add-block! + repo + (:db/id page) + :page)) + (when (and (not hls-page?) (not fmt-journal?) (not config/publishing?)) + (reset! *input-value (if untitled? "" old-name)) + (reset! *edit? true))))} (when (not= icon "") [:span.page-icon icon]) [:div.page-title-sizer-wrapper.relative (when @*edit? @@ -337,9 +341,13 @@ {:data-value @*input-value :data-ref page-name :style {:opacity (when @*edit? 0)}} - (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] - untitled? [:span.opacity-50 (t :untitled)] - :else title)]]]))) + (let [nested? (and (string/includes? title page-ref/left-brackets) + (string/includes? title page-ref/right-brackets))] + (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] + untitled? [:span.opacity-50 (t :untitled)] + nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config + (:block/format page)))) + :else title))]]]))) (defn- page-mouse-over [e *control-show? *all-collapsed?] @@ -440,7 +448,7 @@ (page-blocks-collapse-control title *control-show? *all-collapsed?)]) (when-not whiteboard? [:div.ls-page-title.flex-1.flex-row.w-full - (page-title page-name icon title format fmt-journal?)]) + (page-title page page-name icon title format fmt-journal?)]) (when (not config/publishing?) (when config/lsp-enabled? [:div.flex.flex-row diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index 43ff0d6f57..a0bbc5df8a 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -276,7 +276,7 @@ a.page-title { } > .title { - @apply w-full pointer-events-none overflow-hidden overflow-ellipsis; + @apply w-full overflow-hidden overflow-ellipsis; } .edit-input { From 88c15a1b83a54c20933aeca3998ec24ac5cc9ca7 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 8 May 2023 19:34:06 +0800 Subject: [PATCH 16/81] fix: lint --- src/main/frontend/components/page.cljs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 69e5a7fc95..5e09a8e44d 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -294,10 +294,11 @@ (rum/local false ::edit?) (rum/local "" ::input-value) {:init (fn [state] - (assoc state ::title-value (atom (nth (:rum/args state) 3))))} - [state page page-name icon title _format fmt-journal?] + (assoc state ::title-value (atom (nth (:rum/args state) 2))))} + [state page-name icon title _format fmt-journal?] (when title - (let [*title-value (get state ::title-value) + (let [page (when page-name (db/entity [:block/name page-name])) + *title-value (get state ::title-value) *edit? (get state ::edit?) *input-value (get state ::input-value) repo (state/get-current-repo) @@ -448,7 +449,7 @@ (page-blocks-collapse-control title *control-show? *all-collapsed?)]) (when-not whiteboard? [:div.ls-page-title.flex-1.flex-row.w-full - (page-title page page-name icon title format fmt-journal?)]) + (page-title page-name icon title format fmt-journal?)]) (when (not config/publishing?) (when config/lsp-enabled? [:div.flex.flex-row From d092670b8b35c1beaa8e88f81053e9f3dab5739b Mon Sep 17 00:00:00 2001 From: Zhizhen He Date: Sun, 7 May 2023 19:43:42 +0800 Subject: [PATCH 17/81] enhance: add settings for graph view --- templates/config.edn | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/config.edn b/templates/config.edn index 5e809e2a2c..bf70d27900 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -283,6 +283,13 @@ ;; Default value: 100 :ref/linked-references-collapsed-threshold 50 + ;; Graph view configuration. + ;; Example usage: + ;; :graph/settings + ;; {:orphan-pages? true ; Default value: true + ;; :builtin-pages? false ; Default value: false + ;; :journal? false} ; Default value: false + ;; Favorites to list on the left sidebar :favorites [] From 74e53c3f03849ea02e2fae0cf1db6a88e1b6e941 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 8 May 2023 10:16:20 -0400 Subject: [PATCH 18/81] Add missing subkey and schema key as part of #9325 --- src/main/frontend/schema/handler/common_config.cljc | 1 + templates/config.edn | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/frontend/schema/handler/common_config.cljc b/src/main/frontend/schema/handler/common_config.cljc index 4aae6697a8..15d96da531 100644 --- a/src/main/frontend/schema/handler/common_config.cljc +++ b/src/main/frontend/schema/handler/common_config.cljc @@ -62,6 +62,7 @@ :string]] [:ref/default-open-blocks-level :int] [:ref/linked-references-collapsed-threshold :int] + [:graph/settings [:map-of :keyword :boolean]] [:favorites [:vector :string]] ;; There isn't a :float yet [:srs/learning-fraction float?] diff --git a/templates/config.edn b/templates/config.edn index bf70d27900..e6f083f3d2 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -288,6 +288,7 @@ ;; :graph/settings ;; {:orphan-pages? true ; Default value: true ;; :builtin-pages? false ; Default value: false + ;; :excluded-pages? false ; Default value: false ;; :journal? false} ; Default value: false ;; Favorites to list on the left sidebar From 4be671526bab7604d0d9407607f91a16e0185f9d Mon Sep 17 00:00:00 2001 From: queeup Date: Sat, 6 May 2023 22:42:30 +0300 Subject: [PATCH 19/81] i18n: update Turkish translation --- src/main/frontend/dicts.cljc | 1 + src/main/frontend/modules/shortcut/dicts.cljc | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/main/frontend/dicts.cljc b/src/main/frontend/dicts.cljc index 0c4d181640..5869b543b0 100644 --- a/src/main/frontend/dicts.cljc +++ b/src/main/frontend/dicts.cljc @@ -4518,6 +4518,7 @@ :content/open-in-sidebar "Kenar çubuğunda aç" :content/click-to-edit "Düzenlemek için tıklayın" :context-menu/make-a-flashcard "Bilgi Kartı Oluştur" + :context-menu/toggle-number-list "Numaralı liste olarak değiştir" :context-menu/preview-flashcard "Bilgi Kartını Önizle" :context-menu/make-a-template "Bir Şablon Oluştur" :context-menu/input-template-name "Şablonun adı nedir?" diff --git a/src/main/frontend/modules/shortcut/dicts.cljc b/src/main/frontend/modules/shortcut/dicts.cljc index 8cedcb23a5..5ebbd48586 100644 --- a/src/main/frontend/modules/shortcut/dicts.cljc +++ b/src/main/frontend/modules/shortcut/dicts.cljc @@ -1695,6 +1695,7 @@ :shortcut.category/block-command-editing "Blok düzenleme komutuları" :shortcut.category/block-selection "Blok seçimi (seçimden çıkmak için Esc tuşuna basın)" :shortcut.category/toggle "Aç/Kapat" + :shortcut.category/whiteboard "Beyaz tahta" :shortcut.category/others "Diğer" :command.date-picker/complete "Tarih seçici: Seçilen günü seç" :command.date-picker/prev-day "Tarih seçici: Önceki günü seç" @@ -1767,6 +1768,31 @@ :command.editor/zoom-in "Düzenlenen bloğu yakınlaştır / Aksi takdirde ileri git" :command.editor/zoom-out "Düzenlenen bloğu uzaklaştır / Aksi takdirde geri git" :command.editor/toggle-undo-redo-mode "Geri alma / yineleme modunu değiştir (yalnızca sayfa veya genel)" + :command.editor/toggle-number-list "Numaralı liste olarak değiştir" + :command.whiteboard/select "Seçim aracı" + :command.whiteboard/pan "Kaydırma aracı" + :command.whiteboard/portal "Portal aracı" + :command.whiteboard/pencil "Kalem aracı" + :command.whiteboard/highlighter "Vurgulayıcı aracı" + :command.whiteboard/eraser "Silgi aracı" + :command.whiteboard/connector "Bağlayıcı aracı" + :command.whiteboard/text "Metin aracı" + :command.whiteboard/rectangle "Dikdörtgen aracı" + :command.whiteboard/ellipse "Elips aracı" + :command.whiteboard/reset-zoom "Yakınlaştırmayı sıfırla" + :command.whiteboard/zoom-to-fit "Çizimi yakınlaştır" + :command.whiteboard/zoom-to-selection "Seçimi sığacak kadar yakınlaştır" + :command.whiteboard/zoom-out "Uzaklaştır" + :command.whiteboard/zoom-in "Yakınlaştır" + :command.whiteboard/send-backward "Geriye git" + :command.whiteboard/send-to-back "Geriye taşı" + :command.whiteboard/bring-forward "İleriye git" + :command.whiteboard/bring-to-front "Öne taşı" + :command.whiteboard/lock "Seçimi kilitle" + :command.whiteboard/unlock "Seçimin Kilidini aç" + :command.whiteboard/group "Seçimi gruplandır" + :command.whiteboard/ungroup "Seçimi gruptan çıkar" + :command.whiteboard/toggle-grid "Tuval ızgarasını değiştir" :command.ui/toggle-brackets "Köşeli ayraçların görüntülenip görüntülenmeyeceğini değiştir" :command.go/search-in-page "Geçerli sayfada ara" :command.go/electron-find-in-page "Sayfada bul" From 01479ef9dabf16041daf873af3c7576609670119 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 9 May 2023 17:24:09 +0800 Subject: [PATCH 20/81] enhance(perf): insert and delete blocks (#9142) * enhance(perf): improve performance for both insert and delete * fix: remember cursor pos before executing the body in a transaction Otherwise, the edit-block and position could be changed * fix: disable delete-concat when there's no child or right sibling --------- Co-authored-by: Gabriel Horner <97210743+logseq-cldwalker@users.noreply.github.com> Co-authored-by: Gabriel Horner --- .carve/ignore | 2 + e2e-tests/editor.spec.ts | 2 +- src/main/frontend/components/block.cljs | 3 +- src/main/frontend/db/model.cljs | 11 +- src/main/frontend/db/react.cljs | 2 +- src/main/frontend/handler/block.cljs | 10 +- src/main/frontend/handler/editor.cljs | 70 +++++----- src/main/frontend/handler/events.cljs | 5 +- .../frontend/modules/editor/undo_redo.cljs | 126 ++++++++++-------- src/main/frontend/modules/outliner/core.cljs | 19 +-- .../frontend/modules/outliner/datascript.cljc | 13 +- .../modules/outliner/transaction.cljc | 5 +- src/main/frontend/state.cljs | 4 +- src/main/logseq/api.cljs | 11 +- src/test/frontend/db/model_test.cljs | 16 +++ 15 files changed, 168 insertions(+), 131 deletions(-) diff --git a/.carve/ignore b/.carve/ignore index f0efb24db7..8cd677525c 100644 --- a/.carve/ignore +++ b/.carve/ignore @@ -82,3 +82,5 @@ logseq.graph-parser.nbb-test-runner/run-tests ;; For debugging frontend.fs.sync/debug-print-sync-events-loop frontend.fs.sync/stop-debug-print-sync-events-loop +;; Used in macro +frontend.state/get-current-edit-block-and-position diff --git a/e2e-tests/editor.spec.ts b/e2e-tests/editor.spec.ts index 65fb6de47b..d680ae5912 100644 --- a/e2e-tests/editor.spec.ts +++ b/e2e-tests/editor.spec.ts @@ -260,7 +260,7 @@ test('undo and redo after starting an action should not destroy text #6267', asy // And it should keep what was undone as a redo action await page.keyboard.press(modKey + '+Shift+z') - await expect(page.locator('text="text2"')).toHaveCount(1) + await expect(page.locator('text="text1 text2 [[]]"')).toHaveCount(1) }) test('undo after starting an action should close the action menu #6269', async ({ page, block }) => { diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 8f300e2b8c..f17b75ae1b 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -927,8 +927,7 @@ [:span.warning.mr-1 {:title "Block ref invalid"} (block-ref/->block-ref id)])) [:span.warning.mr-1 {:title "Block ref invalid"} - (block-ref/->block-ref id)] -)) + (block-ref/->block-ref id)])) (defn inline-text ([format v] diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index e3e2e8da9e..42da9a1cbb 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -957,15 +957,8 @@ independent of format as format specific heading characters are stripped" "Doesn't include nested children." [repo block-uuid] (when-let [db (conn/get-db repo)] - (-> (d/q - '[:find [(pull ?b [*]) ...] - :in $ ?parent-id - :where - [?parent :block/uuid ?parent-id] - [?b :block/parent ?parent]] - db - block-uuid) - (sort-by-left (db-utils/entity [:block/uuid block-uuid]))))) + (when-let [parent (db-utils/entity repo [:block/uuid block-uuid])] + (sort-by-left (:block/_parent parent) parent)))) (defn get-block-children "Including nested children." diff --git a/src/main/frontend/db/react.cljs b/src/main/frontend/db/react.cljs index 0af0431e5b..e8115dbaf5 100644 --- a/src/main/frontend/db/react.cljs +++ b/src/main/frontend/db/react.cljs @@ -16,7 +16,7 @@ ;;; keywords specs for reactive query, used by `react/q` calls ;; ::block ;; pull-block react-query -(s/def ::block (s/tuple #(= ::block %) uuid?)) +(s/def ::block (s/tuple #(= ::block %) int?)) ;; ::page-blocks ;; get page-blocks react-query (s/def ::page-blocks (s/tuple #(= ::page-blocks %) int?)) diff --git a/src/main/frontend/handler/block.cljs b/src/main/frontend/handler/block.cljs index 1a7e673c29..5a475b376f 100644 --- a/src/main/frontend/handler/block.cljs +++ b/src/main/frontend/handler/block.cljs @@ -6,7 +6,6 @@ [frontend.db :as db] [frontend.db.model :as db-model] [frontend.db.react :as react] - [frontend.db.utils :as db-utils] [frontend.mobile.haptics :as haptics] [frontend.modules.outliner.core :as outliner-core] [frontend.modules.outliner.transaction :as outliner-tx] @@ -70,14 +69,9 @@ (util/distinct-by :db/id)))))) (defn indentable? - [{:block/keys [parent] :as block}] + [{:block/keys [parent left]}] (when parent - (let [parent-block (db-utils/pull (:db/id parent)) - first-child (first - (db-model/get-block-immediate-children - (state/get-current-repo) - (:block/uuid parent-block)))] - (not= (:db/id block) (:db/id first-child))))) + (not= parent left))) (defn outdentable? [{:block/keys [level] :as _block}] diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index a42434a931..cab9e2f908 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -753,30 +753,28 @@ (outliner-core/delete-blocks! [block] {:children? children?}))))) (defn- move-to-prev-block - ([repo sibling-block format id value] - (move-to-prev-block repo sibling-block format id value true)) - ([repo sibling-block format id value edit?] - (when (and repo sibling-block) - (when-let [sibling-block-id (dom/attr sibling-block "blockid")] - (when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])] - (let [original-content (util/trim-safe (:block/content block)) - value' (-> (property/remove-built-in-properties format original-content) - (drawer/remove-logbook)) - new-value (str value' value) - tail-len (count value) - pos (max - (if original-content - (gobj/get (utf8/encode original-content) "length") - 0) - 0)] - (when edit? - (edit-block! block pos id - {:custom-content new-value - :tail-len tail-len - :move-cursor? false})) - {:prev-block block - :new-content new-value - :pos pos})))))) + [repo sibling-block format id value move?] + (when (and repo sibling-block) + (when-let [sibling-block-id (dom/attr sibling-block "blockid")] + (when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])] + (let [original-content (util/trim-safe (:block/content block)) + value' (-> (property/remove-built-in-properties format original-content) + (drawer/remove-logbook)) + new-value (str value' value) + tail-len (count value) + pos (max + (if original-content + (gobj/get (utf8/encode original-content) "length") + 0) + 0) + f (fn [] (edit-block! block pos id + {:custom-content new-value + :tail-len tail-len + :move-cursor? false}))] + (when move? (f)) + {:prev-block block + :new-content new-value + :move-fn f}))))) (declare save-block!) @@ -802,7 +800,7 @@ (when block-parent-id (let [block-parent (gdom/getElement block-parent-id) sibling-block (util/get-prev-block-non-collapsed-non-embed block-parent) - {:keys [prev-block new-content]} (move-to-prev-block repo sibling-block format id value) + {:keys [prev-block new-content move-fn]} (move-to-prev-block repo sibling-block format id value false) concat-prev-block? (boolean (and prev-block new-content)) transact-opts (cond-> {:outliner-op :delete-block} @@ -812,7 +810,8 @@ (outliner-tx/transact! transact-opts (when concat-prev-block? (save-block! repo prev-block new-content)) - (delete-block-aux! block delete-children?)))))))))) + (delete-block-aux! block delete-children?)) + (move-fn))))))))) (state/set-editor-op! nil))) (defn delete-blocks! @@ -829,7 +828,8 @@ (move-to-prev-block repo sibling-block (:block/format block) (dom/attr sibling-block "id") - ""))))) + "" + true))))) (defn- set-block-property-aux! [block-or-id key value] @@ -1962,7 +1962,7 @@ keep-uuid?] :or {exclude-properties []}}] (let [editing-block (when-let [editing-block (state/get-edit-block)] - (some-> (db/pull (:db/id editing-block)) + (some-> (db/pull [:block/uuid (:block/uuid editing-block)]) (assoc :block/content (state/get-edit-content)))) has-unsaved-edits (and editing-block (not= (:block/content (db/pull (:db/id editing-block))) @@ -2425,8 +2425,9 @@ :else (profile "Insert block" - (do (save-current-block!) - (insert-new-block! state))))))))) + (outliner-tx/transact! {:outliner-op :insert-blocks} + (save-current-block!) + (insert-new-block! state))))))))) (defn- inside-of-single-block "When we are in a single block wrapper, we should always insert a new line instead of new block" @@ -2580,15 +2581,18 @@ ^js input (state/get-input) current-pos (cursor/pos input) value (gobj/get input "value") - right (outliner-core/get-right-node (outliner-core/block current-block)) + right (outliner-core/get-right-sibling (:db/id current-block)) current-block-has-children? (db/has-children? (:block/uuid current-block)) collapsed? (util/collapsed? current-block) first-child (:data (tree/-get-down (outliner-core/block current-block))) next-block (if (or collapsed? (not current-block-has-children?)) - (:data right) + (when right (db/pull (:db/id right))) first-child)] (cond - (and collapsed? right (db/has-children? (tree/-get-id right))) + (nil? next-block) + nil + + (and collapsed? right (db/has-children? (:block/uuid right))) nil (and (not collapsed?) first-child (db/has-children? (:block/uuid first-child))) diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index e34700ad8f..368ae9ebbb 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -608,10 +608,9 @@ (plugin/open-waiting-updates-modal!)) (plugin-handler/set-auto-checking! false)))))) -(defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data tx-meta] :as payload}]] +(defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data] :as payload}]] (when-let [payload (and (seq blocks) - (merge payload {:tx-data (map #(into [] %) tx-data) - :tx-meta (dissoc tx-meta :editor-cursor)}))] + (merge payload {:tx-data (map #(into [] %) tx-data)}))] (plugin-handler/hook-plugin-db :changed payload) (plugin-handler/hook-plugin-block-changes payload))) diff --git a/src/main/frontend/modules/editor/undo_redo.cljs b/src/main/frontend/modules/editor/undo_redo.cljs index f42729091e..d0c4512e24 100644 --- a/src/main/frontend/modules/editor/undo_redo.cljs +++ b/src/main/frontend/modules/editor/undo_redo.cljs @@ -44,7 +44,7 @@ [txs] (filterv (fn [[_ a & y]] (= :block/content a)) - txs)) + txs)) (defn get-content-from-stack "For test." @@ -60,22 +60,21 @@ (when-let [stack @undo-stack] (when (seq stack) (let [removed-e (peek stack) - popped-stack (pop stack) - prev-e (peek popped-stack)] + popped-stack (pop stack)] (reset! undo-stack popped-stack) - [removed-e prev-e]))))) + removed-e))))) (defn push-redo [txs] (let [redo-stack (get-redo-stack)] - (swap! redo-stack conj txs))) + (swap! redo-stack conj txs))) (defn pop-redo [] (let [redo-stack (get-redo-stack)] - (when-let [removed-e (peek @redo-stack)] - (swap! redo-stack pop) - removed-e))) + (when-let [removed-e (peek @redo-stack)] + (swap! redo-stack pop) + removed-e))) (defn page-pop-redo [page-id] @@ -119,7 +118,7 @@ (and redo? (not add?)) :db/retract (and (not redo?) (not add?)) :db/add)] [op id attr value tx])) - txs))) + txs))) ;;;; Invokes @@ -128,7 +127,7 @@ (let [conn (conn/get-db false)] (d/transact! conn txs tx-meta))) -(defn page-pop-undo +(defn- page-pop-undo [page-id] (let [undo-stack (get-undo-stack)] (when-let [stack @undo-stack] @@ -144,7 +143,7 @@ others (vec (concat before after))] (reset! undo-stack others) (prn "[debug] undo remove: " (nth stack idx')) - [(nth stack idx') others]))))))) + (nth stack idx')))))))) (defn- smart-pop-undo [] @@ -154,56 +153,77 @@ (pop-undo)) (pop-undo))) +(defn- set-editor-content! + "Prevent block auto-save during undo/redo." + [] + (when-let [block (state/get-edit-block)] + (state/set-edit-content! (state/get-edit-input-id) + (:block/content (db/entity (:db/id block)))))) + +(defn- get-next-tx-editor-cursor + [tx-id] + (let [result (->> (sort (keys (:history/tx->editor-cursor @state/state))) + (split-with #(not= % tx-id)) + second)] + (when (> (count result) 1) + (when-let [next-tx-id (nth result 1)] + (get-in @state/state [:history/tx->editor-cursor next-tx-id]))))) + +(defn- get-previous-tx-id + [tx-id] + (let [result (->> (sort (keys (:history/tx->editor-cursor @state/state))) + (split-with #(not= % tx-id)) + first)] + (when (>= (count result) 1) + (last result)))) + +(defn- get-previous-tx-editor-cursor + [tx-id] + (when-let [prev-tx-id (get-previous-tx-id tx-id)] + (get-in @state/state [:history/tx->editor-cursor prev-tx-id]))) + (defn undo [] - (let [[e prev-e] (smart-pop-undo)] - (when e - (let [{:keys [txs tx-meta]} e - new-txs (get-txs false txs) - undo-delete-concat-block? (and (= :delete-block (:outliner-op tx-meta)) - (seq (:concat-data tx-meta))) - editor-cursor (cond - undo-delete-concat-block? - (let [data (:concat-data tx-meta)] - (assoc (:editor-cursor e) - :last-edit-block {:block/uuid (:last-edit-block data)} - :pos (if (:end? data) :max 0))) - - ;; same block - (= (get-in e [:editor-cursor :last-edit-block :block/uuid]) - (get-in prev-e [:editor-cursor :last-edit-block :block/uuid])) - (:editor-cursor prev-e) - - :else - (:editor-cursor e))] - - (push-redo e) - (transact! new-txs (merge {:undo? true} - tx-meta - (select-keys e [:pagination-blocks-range]))) - - (when undo-delete-concat-block? - (when-let [block (state/get-edit-block)] - (state/set-edit-content! (state/get-edit-input-id) - (:block/content (db/entity (:db/id block)))))) - - (when (:whiteboard/transact? tx-meta) - (state/pub-event! [:whiteboard/undo e])) - (assoc e - :txs-op new-txs - :editor-cursor editor-cursor))))) + (when-let [e (smart-pop-undo)] + (let [{:keys [txs tx-meta tx-id]} e + new-txs (get-txs false txs) + current-editor-cursor (get-in @state/state [:history/tx->editor-cursor tx-id]) + save-block? (= (:outliner-op tx-meta) :save-block) + prev-editor-cursor (get-previous-tx-editor-cursor tx-id) + editor-cursor (if (and save-block? + (= (:block/uuid (:last-edit-block prev-editor-cursor)) + (:block/uuid (state/get-edit-block)))) + prev-editor-cursor + current-editor-cursor)] + (push-redo e) + (transact! new-txs (merge {:undo? true} + tx-meta + (select-keys e [:pagination-blocks-range]))) + (set-editor-content!) + (when (:whiteboard/transact? tx-meta) + (state/pub-event! [:whiteboard/undo e])) + (assoc e + :txs-op new-txs + :editor-cursor editor-cursor)))) (defn redo [] - (when-let [{:keys [txs tx-meta] :as e} (smart-pop-redo)] - (let [new-txs (get-txs true txs)] + (when-let [{:keys [txs tx-meta tx-id] :as e} (smart-pop-redo)] + (let [new-txs (get-txs true txs) + current-editor-cursor (get-in @state/state [:history/tx->editor-cursor tx-id]) + editor-cursor (if (= (:outliner-op tx-meta) :save-block) + current-editor-cursor + (get-next-tx-editor-cursor tx-id))] (push-undo e) (transact! new-txs (merge {:redo? true} tx-meta (select-keys e [:pagination-blocks-range]))) + (set-editor-content!) (when (:whiteboard/transact? tx-meta) (state/pub-event! [:whiteboard/redo e])) - (assoc e :txs-op new-txs)))) + (assoc e + :txs-op new-txs + :editor-cursor editor-cursor)))) (defn toggle-undo-redo-mode! [] @@ -231,14 +251,14 @@ #{:block/created-at :block/updated-at}))) (reset-redo) (if (:replace? tx-meta) - (let [[removed-e _prev-e] (pop-undo) + (let [removed-e (pop-undo) entity (update removed-e :txs concat tx-data)] (push-undo entity)) (let [updated-blocks (db-report/get-blocks tx-report) - entity {:blocks updated-blocks + entity {:tx-id (get-in tx-report [:tempids :db/current-tx]) + :blocks updated-blocks :txs tx-data :tx-meta tx-meta - :editor-cursor (:editor-cursor tx-meta) :pagination-blocks-range (get-in [:ui/pagination-blocks-range (get-in tx-report [:db-after :max-tx])] @state/state) :app-state (select-keys @state/state [:route-match diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index ea4ae144b4..88f49de196 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -26,8 +26,14 @@ (defn block [m] - (assert (map? m) (util/format "block data must be map, got: %s %s" (type m) m)) - (->Block m)) + (assert (or (map? m) (de/entity? m)) (util/format "block data must be map or entity, got: %s %s" (type m) m)) + (if (de/entity? m) + (->Block {:db/id (:db/id m) + :block/uuid (:block/uuid m) + :block/page (:block/page m) + :block/left (:block/left m) + :block/parent (:block/parent m)}) + (->Block m))) (defn get-data [block] @@ -231,11 +237,6 @@ children (db-model/get-block-immediate-children (state/get-current-repo) parent-id)] (map block children)))) -(defn get-right-node - [node] - {:pre [(tree/satisfied-inode? node)]} - (tree/-get-right node)) - (defn get-right-sibling [db-id] (when db-id @@ -407,7 +408,7 @@ (let [level-blocks (blocks-with-level blocks)] (filter (fn [b] (= 1 (:block/level b))) level-blocks))) -(defn get-right-siblings +(defn- get-right-siblings "Get `node`'s right siblings." [node] {:pre [(tree/satisfied-inode? node)]} @@ -477,7 +478,7 @@ (:db/id target-block)) get-new-id (fn [block lookup] (cond - (or (map? lookup) (vector? lookup)) + (or (map? lookup) (vector? lookup) (de/entity? lookup)) (when-let [uuid (if (and (vector? lookup) (= (first lookup) :block/uuid)) (get uuids (last lookup)) (get id->new-uuid (:db/id lookup)))] diff --git a/src/main/frontend/modules/outliner/datascript.cljc b/src/main/frontend/modules/outliner/datascript.cljc index e058ffd15c..6fad8bb1e6 100644 --- a/src/main/frontend/modules/outliner/datascript.cljc +++ b/src/main/frontend/modules/outliner/datascript.cljc @@ -45,9 +45,14 @@ v))) x)))))) +#?(:cljs + (defn get-tx-id + [tx-report] + (get-in tx-report [:tempids :db/current-tx]))) + #?(:cljs (defn transact! - [txs opts] + [txs opts before-editor-cursor] (let [txs (remove-nil-from-transaction txs) txs (map (fn [m] (if (map? m) (dissoc m @@ -65,9 +70,9 @@ (try (let [repo (get opts :repo (state/get-current-repo)) conn (conn/get-db repo false) - editor-cursor (state/get-current-edit-block-and-position) - meta (merge opts {:editor-cursor editor-cursor}) - rs (d/transact! conn txs (assoc meta :outliner/transact? true))] + rs (d/transact! conn txs (assoc opts :outliner/transact? true)) + tx-id (get-tx-id rs)] + (swap! state/state assoc-in [:history/tx->editor-cursor tx-id] before-editor-cursor) (when true ; TODO: add debug flag (let [eids (distinct (mapv first (:tx-data rs))) left&parent-list (->> diff --git a/src/main/frontend/modules/outliner/transaction.cljc b/src/main/frontend/modules/outliner/transaction.cljc index 738486659d..5f0ad51f7b 100644 --- a/src/main/frontend/modules/outliner/transaction.cljc +++ b/src/main/frontend/modules/outliner/transaction.cljc @@ -27,7 +27,8 @@ `(let [transact-data# frontend.modules.outliner.core/*transaction-data* opts# (if transact-data# (assoc ~opts :nested-transaction? true) - ~opts)] + ~opts) + before-editor-cursor# (frontend.state/get-current-edit-block-and-position)] (if transact-data# (do ~@body) (binding [frontend.modules.outliner.core/*transaction-data* (transient [])] @@ -40,7 +41,7 @@ opts## (merge (dissoc opts# :additional-tx) tx-meta#)] (when (seq all-tx#) ;; If it's empty, do nothing (when-not (:nested-transaction? opts#) ; transact only for the whole transaction - (let [result# (frontend.modules.outliner.datascript/transact! all-tx# opts##)] + (let [result# (frontend.modules.outliner.datascript/transact! all-tx# opts## before-editor-cursor#)] {:tx-report result# :tx-data all-tx# :tx-meta tx-meta#})))))))) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 91f3ff68bb..0312b01a5f 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -277,7 +277,9 @@ :whiteboard/onboarding-tour? (or (storage/get :whiteboard-onboarding-tour?) false) :whiteboard/last-persisted-at {} :whiteboard/pending-tx-data {} - :history/page-only-mode? false}))) + :history/page-only-mode? false + ;; db tx-id -> editor cursor + :history/tx->editor-cursor {}}))) ;; Block ast state ;; =============== diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index 3c14830b53..f56a8aae13 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -688,11 +688,11 @@ block (if includeChildren ;; nested children results (first (outliner-tree/blocks->vec-tree - (db-model/get-block-and-children repo uuid) uuid)) + (db-model/get-block-and-children repo uuid) uuid)) ;; attached shallow children (assoc block :block/children - (map #(list :uuid (get-in % [:data :block/uuid])) - (db/get-block-immediate-children repo uuid))))] + (map #(list :uuid (:block/uuid %)) + (db/get-block-immediate-children repo uuid))))] (bean/->js (sdk-utils/normalize-keyword-for-json block)))))))) (def ^:export get_current_block @@ -715,8 +715,9 @@ (def ^:export get_next_sibling_block (fn [block-uuid] (when-let [block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error block-uuid))] - (when-let [right-siblings (outliner/get-right-siblings (outliner/->Block block))] - (bean/->js (sdk-utils/normalize-keyword-for-json (:data (first right-siblings)))))))) + (when-let [right-sibling (outliner/get-right-sibling (:db/id block))] + (let [block (db/pull (:id right-sibling))] + (bean/->js (sdk-utils/normalize-keyword-for-json block))))))) (def ^:export set_block_collapsed (fn [block-uuid ^js opts] diff --git a/src/test/frontend/db/model_test.cljs b/src/test/frontend/db/model_test.cljs index 7b43307e10..39b5778567 100644 --- a/src/test/frontend/db/model_test.cljs +++ b/src/test/frontend/db/model_test.cljs @@ -163,6 +163,22 @@ foo:: bar"}]) (catch :default e (ex-message e))))))) +(deftest get-block-immediate-children + (load-test-files [{:file/path "pages/page1.md" + :file/content "\n +- parent + - child 1 + - grandchild 1 + - child 2 + - grandchild 2 + - child 3"}]) + (let [parent (-> (d/q '[:find (pull ?b [*]) :where [?b :block/content "parent"]] + (conn/get-db test-helper/test-db)) + ffirst)] + (is (= ["child 1" "child 2" "child 3"] + (map :block/content + (model/get-block-immediate-children test-helper/test-db (:block/uuid parent))))))) + (deftest get-property-values (load-test-files [{:file/path "pages/Feature.md" :file/content "type:: [[Class]]"} From 5885bc86b6c2cd43bd060a2bd24978ddb24bb927 Mon Sep 17 00:00:00 2001 From: Konstantinos Date: Tue, 9 May 2023 19:38:00 +0300 Subject: [PATCH 21/81] Enhance (Whiteboards): Add prefix to default keyboard shortcuts (#9340) * enhance: keyboard shortcuts * fix: portal shortcut * fix: e2e tests * fix: e2e * enhance: keyboard shortcuts --- e2e-tests/whiteboards.spec.ts | 12 +++++----- .../frontend/modules/shortcut/config.cljs | 22 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/e2e-tests/whiteboards.spec.ts b/e2e-tests/whiteboards.spec.ts index 1789650800..c012363c11 100644 --- a/e2e-tests/whiteboards.spec.ts +++ b/e2e-tests/whiteboards.spec.ts @@ -83,7 +83,7 @@ test('draw a rectangle', async ({ page }) => { const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('r') + await page.keyboard.type('wr') await page.mouse.move(bounds.x + 5, bounds.y + 5) await page.mouse.down() @@ -130,7 +130,7 @@ test('connect rectangles with an arrow', async ({ page }) => { const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('c') + await page.keyboard.type('wc') await page.mouse.move(bounds.x + 20, bounds.y + 20) await page.mouse.down() @@ -205,7 +205,7 @@ test('create a block', async ({ page }) => { const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('s') + await page.keyboard.type('ws') await page.mouse.dblclick(bounds.x + 5, bounds.y + 5) await page.waitForTimeout(100) @@ -240,7 +240,7 @@ test('copy/paste url to create an iFrame shape', async ({ page }) => { const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('t') + await page.keyboard.type('wt') await page.mouse.move(bounds.x + 5, bounds.y + 5) await page.mouse.down() await page.waitForTimeout(100) @@ -259,7 +259,7 @@ test('copy/paste twitter status url to create a Tweet shape', async ({ page }) = const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('t') + await page.keyboard.type('wt') await page.mouse.move(bounds.x + 5, bounds.y + 5) await page.mouse.down() await page.waitForTimeout(100) @@ -278,7 +278,7 @@ test('copy/paste youtube video url to create a Youtube shape', async ({ page }) const canvas = await page.waitForSelector('.logseq-tldraw') const bounds = (await canvas.boundingBox())! - await page.keyboard.press('t') + await page.keyboard.type('wt') await page.mouse.move(bounds.x + 5, bounds.y + 5) await page.mouse.down() await page.waitForTimeout(100) diff --git a/src/main/frontend/modules/shortcut/config.cljs b/src/main/frontend/modules/shortcut/config.cljs index e4206179be..652b325d5f 100644 --- a/src/main/frontend/modules/shortcut/config.cljs +++ b/src/main/frontend/modules/shortcut/config.cljs @@ -71,34 +71,34 @@ :pdf/find {:binding "alt+f" :fn pdf-utils/open-finder} - :whiteboard/select {:binding ["1" "s"] + :whiteboard/select {:binding ["1" "w s"] :fn #(.selectTool ^js (state/active-tldraw-app) "select")} - :whiteboard/pan {:binding ["2" "p"] + :whiteboard/pan {:binding ["2" "w p"] :fn #(.selectTool ^js (state/active-tldraw-app) "move")} - :whiteboard/portal {:binding "3" + :whiteboard/portal {:binding ["3" "w b"] :fn #(.selectTool ^js (state/active-tldraw-app) "logseq-portal")} - :whiteboard/pencil {:binding ["4" "d"] + :whiteboard/pencil {:binding ["4" "w d"] :fn #(.selectTool ^js (state/active-tldraw-app) "pencil")} - :whiteboard/highlighter {:binding ["5" "h"] + :whiteboard/highlighter {:binding ["5" "w h"] :fn #(.selectTool ^js (state/active-tldraw-app) "highlighter")} - :whiteboard/eraser {:binding ["6" "e"] + :whiteboard/eraser {:binding ["6" "w e"] :fn #(.selectTool ^js (state/active-tldraw-app) "erase")} - :whiteboard/connector {:binding ["7" "c"] + :whiteboard/connector {:binding ["7" "w c"] :fn #(.selectTool ^js (state/active-tldraw-app) "line")} - :whiteboard/text {:binding ["8" "t"] + :whiteboard/text {:binding ["8" "w t"] :fn #(.selectTool ^js (state/active-tldraw-app) "text")} - :whiteboard/rectangle {:binding ["9" "r"] + :whiteboard/rectangle {:binding ["9" "w r"] :fn #(.selectTool ^js (state/active-tldraw-app) "box")} - :whiteboard/ellipse {:binding "o" + :whiteboard/ellipse {:binding ["o" "w o"] :fn #(.selectTool ^js (state/active-tldraw-app) "ellipse")} :whiteboard/reset-zoom {:binding "shift+0" @@ -140,7 +140,7 @@ :whiteboard/ungroup {:binding "mod+shift+g" :fn #(.unGroup (.-api ^js (state/active-tldraw-app)))} - :whiteboard/toggle-grid {:binding "shift+g" + :whiteboard/toggle-grid {:binding "t g" :fn #(.toggleGrid (.-api ^js (state/active-tldraw-app)))} :auto-complete/complete {:binding "enter" From fe783015d1d5b3c4e2e267184e1bd29d0f0be704 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Wed, 10 May 2023 15:34:16 +0800 Subject: [PATCH 22/81] fix(export): export table err when empty table-header (#9344) --- src/main/frontend/handler/export/text.cljs | 53 +++++++++++----------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/main/frontend/handler/export/text.cljs b/src/main/frontend/handler/export/text.cljs index 28fb94136d..a3fa16eb9e 100644 --- a/src/main/frontend/handler/export/text.cljs +++ b/src/main/frontend/handler/export/text.cljs @@ -164,33 +164,32 @@ (defn- block-table [{:keys [header groups]}] - (when (seq header) - (let [level (dec (get *state* :current-level 1)) - sep-line (raw-text "|" (string/join "|" (repeat (count header) "---")) "|") - header-line - (concatv (mapcatv - (fn [h] (concatv [space (raw-text "|") space] (mapcatv inline-ast->simple-ast h))) - header) - [space (raw-text "|")]) - group-lines - (mapcatv - (fn [group] - (mapcatv - (fn [row] - (concatv [(indent-with-2-spaces level)] - (mapcatv - (fn [col] - (concatv [(raw-text "|") space] - (mapcatv inline-ast->simple-ast col) - [space])) - row) - [(raw-text "|") (newline* 1)])) - group)) - groups)] - (concatv [(newline* 1) (indent-with-2-spaces level)] - header-line - [(newline* 1) (indent-with-2-spaces level) sep-line (newline* 1)] - group-lines)))) + (let [level (dec (get *state* :current-level 1)) + sep-line (raw-text "|" (string/join "|" (repeat (count header) "---")) "|") + header-line + (concatv (mapcatv + (fn [h] (concatv [space (raw-text "|") space] (mapcatv inline-ast->simple-ast h))) + header) + [space (raw-text "|")]) + group-lines + (mapcatv + (fn [group] + (mapcatv + (fn [row] + (concatv [(indent-with-2-spaces level)] + (mapcatv + (fn [col] + (concatv [(raw-text "|") space] + (mapcatv inline-ast->simple-ast col) + [space])) + row) + [(raw-text "|") (newline* 1)])) + group)) + groups)] + (concatv [(newline* 1) (indent-with-2-spaces level)] + (when (seq header) header-line) + (when (seq header) [(newline* 1) (indent-with-2-spaces level) sep-line (newline* 1)]) + group-lines))) (defn- block-comment [s] From 14aea4e1e4cd9453e421e7a8833457ae953ac876 Mon Sep 17 00:00:00 2001 From: Andelf Date: Sat, 6 May 2023 10:35:18 +0800 Subject: [PATCH 23/81] fix(fs): handle non-ascii graph name on mobile --- src/main/frontend/util/text.cljs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/frontend/util/text.cljs b/src/main/frontend/util/text.cljs index 090f8af624..fb2daa34d9 100644 --- a/src/main/frontend/util/text.cljs +++ b/src/main/frontend/util/text.cljs @@ -3,7 +3,8 @@ a good ns to be in yet" (:require [clojure.string :as string] [goog.string :as gstring] - [frontend.util :as util])) + [frontend.util :as util] + [logseq.common.path :as path])) (defonce between-re #"\(between ([^\)]+)\)") @@ -142,10 +143,11 @@ ;; FIXME: distinguish from get-repo-name (defn get-graph-name-from-path [path] - (when (string? path) - (let [parts (->> (string/split path #"/") - (take-last 2))] - (-> (if (not= (first parts) "0") - (util/string-join-path parts) - (last parts)) - js/decodeURIComponent)))) + (let [path (if (path/is-file-url? path) + (path/url-to-path path) + path) + parts (->> (string/split path #"/") + (take-last 2))] + (if (not= (first parts) "0") + (util/string-join-path parts) + (last parts)))) From 810e7163c5365408afa476647962f7a794bc5ee7 Mon Sep 17 00:00:00 2001 From: Andelf Date: Wed, 10 May 2023 21:42:42 +0800 Subject: [PATCH 24/81] chore(release): bump version 0.9.5 --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 8 ++++---- resources/package.json | 2 +- src/main/frontend/version.cljs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c3e288615c..0f270d1eee 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.logseq.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 57 - versionName "0.9.4" + versionCode 58 + versionName "0.9.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 7d0094b5c1..9ee75f816d 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -515,7 +515,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.4; + MARKETING_VERSION = 0.9.5; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -542,7 +542,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.4; + MARKETING_VERSION = 0.9.5; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; @@ -567,7 +567,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.9.4; + MARKETING_VERSION = 0.9.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; @@ -594,7 +594,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.9.4; + MARKETING_VERSION = 0.9.5; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/resources/package.json b/resources/package.json index 238e889c88..434b787f69 100644 --- a/resources/package.json +++ b/resources/package.json @@ -1,7 +1,7 @@ { "name": "Logseq", "productName": "Logseq", - "version": "0.9.4", + "version": "0.9.5", "main": "electron.js", "author": "Logseq", "license": "AGPL-3.0", diff --git a/src/main/frontend/version.cljs b/src/main/frontend/version.cljs index 646a7e002d..b8f5874ea8 100644 --- a/src/main/frontend/version.cljs +++ b/src/main/frontend/version.cljs @@ -1,3 +1,3 @@ (ns ^:no-doc frontend.version) -(defonce version "0.9.4") +(defonce version "0.9.5") From 04d7224ff19fc7d3302a3f20836994ef204ac7b3 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Thu, 4 May 2023 17:34:20 +0800 Subject: [PATCH 25/81] fix: reduce page-history err when page doesn't have file-id yet --- src/main/frontend/components/file_sync.cljs | 2 +- src/main/frontend/handler/file_sync.cljs | 32 ++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/frontend/components/file_sync.cljs b/src/main/frontend/components/file_sync.cljs index a161e0b713..0dfc07b122 100644 --- a/src/main/frontend/components/file_sync.cljs +++ b/src/main/frontend/components/file_sync.cljs @@ -588,7 +588,7 @@ (async/go (set-loading? true) (try - (let [files (async/> (concat version-list local-version-list) - (sort-by #(or (:CreateTime %) - (:create-time %)) - >))] - all-version-list)))))) + (go + (when-let [path (:file/path (db/entity file-id))] + (let [base-path (config/get-repo-dir (state/get-current-repo)) + base-path (if (string/starts-with? base-path "file://") + (gp-util/safe-decode-uri-component base-path) + base-path) + path* (string/replace-first (string/replace-first path base-path "") #"^/" "") + version-list (:VersionList + (> (concat version-list local-version-list) + (sort-by #(or (:CreateTime %) + (:create-time %)) + >))] + all-version-list))))) (defn init-remote-graph From 8d46b5cb23f74b3f0219db07ee30f44554635f24 Mon Sep 17 00:00:00 2001 From: Andelf Date: Thu, 11 May 2023 11:11:04 +0800 Subject: [PATCH 26/81] chore: refine #9310 - :file/path should always be relative - use path fn to convert url --- src/main/frontend/handler/file_sync.cljs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/frontend/handler/file_sync.cljs b/src/main/frontend/handler/file_sync.cljs index ab36a111bf..2f775caec8 100644 --- a/src/main/frontend/handler/file_sync.cljs +++ b/src/main/frontend/handler/file_sync.cljs @@ -16,7 +16,6 @@ [cljs-time.coerce :as tc] [cljs-time.core :as t] [frontend.storage :as storage] - [logseq.graph-parser.util :as gp-util] [lambdaisland.glogi :as log])) (def *beta-unavailable? (volatile! false)) @@ -168,13 +167,8 @@ (let [file-id (:db/id (:block/file page))] (go (when-let [path (:file/path (db/entity file-id))] - (let [base-path (config/get-repo-dir (state/get-current-repo)) - base-path (if (string/starts-with? base-path "file://") - (gp-util/safe-decode-uri-component base-path) - base-path) - path* (string/replace-first (string/replace-first path base-path "") #"^/" "") - version-list (:VersionList - (> (concat version-list local-version-list) (sort-by #(or (:CreateTime %) From adef15d07349d5199a800115e3a7e6923b540021 Mon Sep 17 00:00:00 2001 From: rcmerci Date: Fri, 12 May 2023 11:30:54 +0800 Subject: [PATCH 27/81] fix(sync): validate rsapi upload err when localtime incorrect, aws s3 return "Request is not yet valid" err --- src/main/frontend/dicts.cljc | 5 ++++- src/main/frontend/fs/sync.cljs | 11 ++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/dicts.cljc b/src/main/frontend/dicts.cljc index 5869b543b0..1a47a746f7 100644 --- a/src/main/frontend/dicts.cljc +++ b/src/main/frontend/dicts.cljc @@ -371,6 +371,8 @@ :file-sync/other-user-graph "Current local graph is bound to other user's remote graph. So can't start syncing." :file-sync/graph-deleted "The current remote graph has been deleted" + :file-sync/rsapi-cannot-upload-err "Unable to start synchronization, please check if the local time is correct." + :notification/clear-all "Clear all"} @@ -763,7 +765,7 @@ :right-side-bar/history "(Dev) Verlauf rückgängig machen / wiederherstellen" :select/default-select-multiple "Ein oder mehrere auswählen" :settings-page/auto-expand-block-refs "Automatisch beim Heranzoomen Blockreferenzen erweitern..." - + :whiteboard/link-whiteboard-or-block "Whiteboard/Seite/Block verknüpfen"} :nl { :all-files "Alle bestanden" @@ -1683,6 +1685,7 @@ :file-sync/other-user-graph "当前本地图谱绑定在其他用户的远程图谱上。因此无法启动同步。" :file-sync/graph-deleted "当前远程图谱已经删除" + :file-sync/rsapi-cannot-upload-err "无法同步,请检查本机时间是否准确" :notification/clear-all "清除全部通知"} diff --git a/src/main/frontend/fs/sync.cljs b/src/main/frontend/fs/sync.cljs index 3cd60b98a4..c332f4a576 100644 --- a/src/main/frontend/fs/sync.cljs +++ b/src/main/frontend/fs/sync.cljs @@ -1680,6 +1680,10 @@ [r] (some->> (ex-cause r) str (re-find #"graph-not-exist"))) +(defn- stop-sync-by-rsapi-response? + [r] + (some->> (ex-cause r) str (re-find #"Request is not yet valid"))) + ;; type = "change" | "add" | "unlink" (deftype FileChangeEvent [type dir path stat checksum] @@ -2594,10 +2598,15 @@ (do (println :graph-has-been-deleted r*) {:graph-has-been-deleted true}) + (stop-sync-by-rsapi-response? r*) + (do (println :stop-sync-caused-by-rsapi-err-response r*) + (notification/show! (t :file-sync/rsapi-cannot-upload-err) :warning false) + {:stop true}) + paused? {:pause true} - succ? ; succ + succ? ; succ (do (println "sync-local->remote! update txid" r*) ;; persist txid From b26d83d2fca1036e81ef7218e36e11c93c29e3b8 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 10 May 2023 21:23:43 -0400 Subject: [PATCH 28/81] Fix mailto and other links creating invalid pages Fixes #9346 and fixes #5926. Also fixes case where relative paths for unsupported paths were creating pages per directory e.g. `deps/graph-parser/yarn.lock` created deps and graph-parser pages --- .../graph-parser/src/logseq/graph_parser/block.cljs | 13 ------------- .../logseq/graph_parser/test/docs_graph_helper.cljs | 2 +- .../graph-parser/test/logseq/graph_parser_test.cljs | 12 +++++++++--- src/test/frontend/handler/repo_conversion_test.cljs | 2 +- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/deps/graph-parser/src/logseq/graph_parser/block.cljs b/deps/graph-parser/src/logseq/graph_parser/block.cljs index 530fd86575..5a8d27872f 100644 --- a/deps/graph-parser/src/logseq/graph_parser/block.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/block.cljs @@ -54,19 +54,6 @@ (page-ref/page-ref? value) (text/page-ref-un-brackets! value)) - (and - (= typ "Search") - (not (contains? #{\# \* \/ \[} (first value))) - ;; FIXME: use `gp-util/get-format` instead - (let [ext (some-> (gp-util/get-file-ext value) keyword)] - (when (and (not (string/starts-with? value "http:")) - (not (string/starts-with? value "https:")) - (not (string/starts-with? value "file:")) - (not (gp-config/local-asset? value)) - (or (#{:excalidraw :tldr} ext) - (not (contains? supported-formats ext)))) - value))) - (and (= typ "File") (second (first (:label (second block))))))) diff --git a/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs b/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs index b10e50df4e..4f0434e57d 100644 --- a/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs @@ -153,7 +153,7 @@ ;; only increase over time as the docs graph rarely has deletions (testing "Counts" (is (= 306 (count files)) "Correct file count") - (is (= 69508 (count (d/datoms db :eavt))) "Correct datoms count") + (is (= 69500 (count (d/datoms db :eavt))) "Correct datoms count") (is (= 5866 (ffirst diff --git a/deps/graph-parser/test/logseq/graph_parser_test.cljs b/deps/graph-parser/test/logseq/graph_parser_test.cljs index e5c414133c..2e899d11e4 100644 --- a/deps/graph-parser/test/logseq/graph_parser_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser_test.cljs @@ -360,15 +360,21 @@ (remove built-in-pages) set))))) - (testing "for file and web uris" + (testing "for file, mailto, web and other uris" (let [conn (ldb/start-conn) built-in-pages (set (map string/lower-case default-db/built-in-pages-names))] (graph-parser/parse-file conn "foo.md" - (str "- [Filename.txt](file:///E:/test/Filename.txt)\n" + (str "- [foo]([[bar]])\n" + ;; all of the uris below do not create pages + "- ![image.png](../assets/image_1630480711363_0.png)\n" + "- [Filename.txt](file:///E:/test/Filename.txt)\n" + "- [mail](mailto:test@test.com?subject=TestSubject)\n" + "- [onenote link](onenote:https://d.docs.live.net/b2127346582e6386a/blablabla/blablabla/blablabla%20blablabla.one#Etat%202019§ion-id={133DDF16-9A1F-4815-9A05-44303784442E6F94}&page-id={3AAB677F0B-328F-41D0-AFF5-66408819C085}&end)\n" + "- [lock file](deps/graph-parser/yarn.lock)" "- [example](https://example.com)") {}) - (is (= #{"foo"} + (is (= #{"foo" "bar"} (->> (d/q '[:find (pull ?b [*]) :in $ :where [?b :block/name]] diff --git a/src/test/frontend/handler/repo_conversion_test.cljs b/src/test/frontend/handler/repo_conversion_test.cljs index 1ac0db602f..576eb2f4ce 100644 --- a/src/test/frontend/handler/repo_conversion_test.cljs +++ b/src/test/frontend/handler/repo_conversion_test.cljs @@ -98,7 +98,7 @@ ;; only increase over time as the docs graph rarely has deletions (testing "Counts" (is (= 211 (count files)) "Correct file count") - (is (= 42312 (count (d/datoms db :eavt))) "Correct datoms count") + (is (= 42296 (count (d/datoms db :eavt))) "Correct datoms count") (is (= 3600 (ffirst From b2776bbb18497667f6d7fe8bee7335b7cb304994 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Thu, 11 May 2023 00:12:41 -0400 Subject: [PATCH 29/81] Remove supported-formats in all the places it's no longer used --- deps/graph-parser/.carve/ignore | 4 ++++ .../graph-parser/src/logseq/graph_parser.cljs | 1 - .../src/logseq/graph_parser/block.cljs | 20 +++++++++---------- .../src/logseq/graph_parser/cli.cljs | 1 - .../src/logseq/graph_parser/config.cljs | 8 +------- src/main/frontend/format/block.cljs | 2 -- src/main/frontend/handler/common/file.cljs | 2 -- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/deps/graph-parser/.carve/ignore b/deps/graph-parser/.carve/ignore index 1dd02aab9c..76e2443ea1 100644 --- a/deps/graph-parser/.carve/ignore +++ b/deps/graph-parser/.carve/ignore @@ -46,3 +46,7 @@ logseq.graph-parser.text/get-file-basename logseq.graph-parser.mldoc/mldoc-link? ;; public var logseq.graph-parser.schema.mldoc/block-ast-coll-schema +;; API +logseq.graph-parser.config/img-formats +;; API +logseq.graph-parser.config/text-formats diff --git a/deps/graph-parser/src/logseq/graph_parser.cljs b/deps/graph-parser/src/logseq/graph_parser.cljs index e861707541..8be3badff4 100644 --- a/deps/graph-parser/src/logseq/graph_parser.cljs +++ b/deps/graph-parser/src/logseq/graph_parser.cljs @@ -89,7 +89,6 @@ Options available: {:keys [tx ast]} (let [extract-options' (merge {:block-pattern (gp-config/get-block-pattern format) :date-formatter "MMM do, yyyy" - :supported-formats (gp-config/supported-formats) :uri-encoded? false :filename-format :legacy} extract-options diff --git a/deps/graph-parser/src/logseq/graph_parser/block.cljs b/deps/graph-parser/src/logseq/graph_parser/block.cljs index 5a8d27872f..f06c45265b 100644 --- a/deps/graph-parser/src/logseq/graph_parser/block.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/block.cljs @@ -35,7 +35,7 @@ (string/join)))) (defn- get-page-reference - [block supported-formats] + [block] (let [page (cond (and (vector? block) (= "Link" (first block))) (let [typ (first (:url (second block))) @@ -316,7 +316,7 @@ nil)) (defn- with-page-refs - [{:keys [title body tags refs marker priority] :as block} with-id? supported-formats db date-formatter] + [{:keys [title body tags refs marker priority] :as block} with-id? db date-formatter] (let [refs (->> (concat tags refs [marker priority]) (remove string/blank?) (distinct)) @@ -327,7 +327,7 @@ (when-not (and (vector? form) (= (first form) "Custom") (= (second form) "query")) - (when-let [page (get-page-reference form supported-formats)] + (when-let [page (get-page-reference form)] (swap! *refs conj page)) (when-let [tag (get-tag form)] (let [tag (text/page-ref-un-brackets! tag)] @@ -418,9 +418,9 @@ (map (fn [page] (page-name->map page true db true date-formatter)) page-refs))) (defn- with-page-block-refs - [block with-id? supported-formats db date-formatter] + [block with-id? db date-formatter] (some-> block - (with-page-refs with-id? supported-formats db date-formatter) + (with-page-refs with-id? db date-formatter) with-block-refs block-tags->pages (update :refs (fn [col] (remove nil? col))))) @@ -494,7 +494,7 @@ (mapv macro->block @*result))) (defn with-pre-block-if-exists - [blocks body pre-block-properties encoded-content {:keys [supported-formats db date-formatter user-config]}] + [blocks body pre-block-properties encoded-content {:keys [db date-formatter user-config]}] (let [first-block (first blocks) first-block-start-pos (get-in first-block [:block/meta :start_pos]) @@ -526,7 +526,7 @@ :block/macros (extract-macros-from-ast body) :block/body body} {:keys [tags refs]} - (with-page-block-refs {:body body :refs property-refs} false supported-formats db date-formatter)] + (with-page-block-refs {:body body :refs property-refs} false db date-formatter)] (cond-> block tags (assoc :block/tags tags) @@ -544,7 +544,7 @@ properties)) (defn- construct-block - [block properties timestamps body encoded-content format pos-meta with-id? {:keys [block-pattern supported-formats db date-formatter]}] + [block properties timestamps body encoded-content format pos-meta with-id? {:keys [block-pattern db date-formatter]}] (let [id (get-custom-id-or-new-id properties) ref-pages-in-properties (->> (:page-refs properties) (remove string/blank?)) @@ -581,7 +581,7 @@ (merge block (timestamps->scheduled-and-deadline timestamps)) block) block (assoc block :body body) - block (with-page-block-refs block with-id? supported-formats db date-formatter) + block (with-page-block-refs block with-id? db date-formatter) block (update block :refs concat (:block-refs properties)) {:keys [created-at updated-at]} (:properties properties) block (cond-> block @@ -635,7 +635,7 @@ `content`: markdown or org-mode text. `with-id?`: If `with-id?` equals to true, all the referenced pages will have new db ids. `format`: content's format, it could be either :markdown or :org-mode. - `options`: Options supported are :user-config, :block-pattern :supported-formats, + `options`: Options supported are :user-config, :block-pattern, :extract-macros, :date-formatter, :page-name and :db" [blocks content with-id? format {:keys [user-config] :as options}] {:pre [(seq blocks) (string? content) (boolean? with-id?) (contains? #{:markdown :org} format)]} diff --git a/deps/graph-parser/src/logseq/graph_parser/cli.cljs b/deps/graph-parser/src/logseq/graph_parser/cli.cljs index 60e9f70d0c..79b9aec838 100644 --- a/deps/graph-parser/src/logseq/graph_parser/cli.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/cli.cljs @@ -48,7 +48,6 @@ TODO: Fail fast when process exits 1" [conn files {:keys [config] :as options}] (let [extract-options (merge {:date-formatter (gp-config/get-date-formatter config) :user-config config - :supported-formats (gp-config/supported-formats) :filename-format (or (:file/name-format config) :legacy) :extracted-block-ids (atom #{})} (select-keys options [:verbose]))] diff --git a/deps/graph-parser/src/logseq/graph_parser/config.cljs b/deps/graph-parser/src/logseq/graph_parser/config.cljs index 5198eb1f04..a110956671 100644 --- a/deps/graph-parser/src/logseq/graph_parser/config.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/config.cljs @@ -1,7 +1,6 @@ (ns logseq.graph-parser.config "App config that is shared between graph-parser and rest of app" - (:require [clojure.set :as set] - [clojure.string :as string] + (:require [clojure.string :as string] [goog.object :as gobj])) (def app-name @@ -68,11 +67,6 @@ [] #{:gif :svg :jpeg :ico :png :jpg :bmp :webp}) -(defn supported-formats - [] - (set/union (text-formats) - (img-formats))) - (defn get-date-formatter [config] (or diff --git a/src/main/frontend/format/block.cljs b/src/main/frontend/format/block.cljs index ca341b0e17..2c4e4a4230 100644 --- a/src/main/frontend/format/block.cljs +++ b/src/main/frontend/format/block.cljs @@ -9,7 +9,6 @@ [frontend.handler.notification :as notification] [frontend.state :as state] [logseq.graph-parser.block :as gp-block] - [logseq.graph-parser.config :as gp-config] [logseq.graph-parser.property :as gp-property] [logseq.graph-parser.mldoc :as gp-mldoc] [lambdaisland.glogi :as log])) @@ -23,7 +22,6 @@ and handles unexpected failure." (gp-block/extract-blocks blocks content with-id? format {:user-config (state/get-config) :block-pattern (config/get-block-pattern format) - :supported-formats (gp-config/supported-formats) :db (db/get-db (state/get-current-repo)) :date-formatter (state/get-date-formatter) :page-name page-name}) diff --git a/src/main/frontend/handler/common/file.cljs b/src/main/frontend/handler/common/file.cljs index c374ab4ba7..b8f58f7198 100644 --- a/src/main/frontend/handler/common/file.cljs +++ b/src/main/frontend/handler/common/file.cljs @@ -5,7 +5,6 @@ [frontend.db :as db] [logseq.graph-parser :as graph-parser] [logseq.graph-parser.util :as gp-util] - [logseq.graph-parser.config :as gp-config] [frontend.fs.diff-merge :as diff-merge] [frontend.fs :as fs] [frontend.context.i18n :refer [t]] @@ -107,7 +106,6 @@ {:user-config (state/get-config) :date-formatter (state/get-date-formatter) :block-pattern (config/get-block-pattern (gp-util/get-format file-path)) - :supported-formats (gp-config/supported-formats) :filename-format (state/get-filename-format repo-url)} ;; To avoid skipping the `:or` bounds for keyword destructuring (when (some? extracted-block-ids) {:extracted-block-ids extracted-block-ids}) From ded76644e653c033b1b768c339fab173400a84a4 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 11 May 2023 15:34:17 +0800 Subject: [PATCH 30/81] fix: refresh the page after deleting blocks in a long page --- src/main/frontend/db/model.cljs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index 42da9a1cbb..1ea8f8a13c 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -770,7 +770,11 @@ independent of format as format specific heading characters are stripped" :include-start? true :scoped-block-id scoped-block-id})) - (contains? #{:save-block :delete-blocks} outliner-op) + (and (= :delete-blocks outliner-op) + (<= (count @result) initial-blocks-length)) ; load more blocks + nil + + (= :save-block outliner-op) @result (contains? #{:insert-blocks :collapse-expand-blocks :move-blocks} outliner-op) @@ -845,6 +849,7 @@ independent of format as format specific heading characters are stripped" (db-utils/pull repo-url pull-keys id))) block-eids) (db-utils/pull-many repo-url pull-keys block-eids)) blocks (remove (fn [b] (nil? (:block/content b))) blocks)] + (map (fn [b] (assoc b :block/page bare-page-map)) blocks)))} nil) react))))) From 2a81e634a506aac9a2f10c53c47c3568690e4eb2 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 11 May 2023 14:53:38 +0800 Subject: [PATCH 31/81] fix: can't insert template --- src/main/frontend/modules/outliner/core.cljs | 16 ++++++++++++---- .../frontend/modules/outliner/datascript.cljc | 7 +++++++ src/main/logseq/api.cljs | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index 88f49de196..2fbb9d5fd9 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -16,8 +16,7 @@ [logseq.graph-parser.util :as gp-util] [cljs.spec.alpha :as s])) -(s/def ::block-map (s/keys :req [:db/id] - :opt [:block/page :block/left :block/parent])) +(s/def ::block-map (s/keys :opt [:db/id :block/uuid :block/page :block/left :block/parent])) (s/def ::block-map-or-entity (s/or :entity de/entity? :map ::block-map)) @@ -511,6 +510,13 @@ (dissoc :db/id))))) blocks))) +(defn- get-target-block + [target-block] + (if (:db/id target-block) + (db/pull (:db/id target-block)) + (when (:block/uuid target-block) + (db/pull [:block/uuid (:block/uuid target-block)])))) + (defn insert-blocks "Insert blocks as children (or siblings) of target-node. Args: @@ -528,7 +534,7 @@ [blocks target-block {:keys [sibling? keep-uuid? outliner-op replace-empty-target?] :as opts}] {:pre [(seq blocks) (s/valid? ::block-map-or-entity target-block)]} - (let [target-block' (db/pull (:db/id target-block)) + (let [target-block' (get-target-block target-block) _ (assert (some? target-block') (str "Invalid target: " target-block)) sibling? (if (page-block? target-block') false sibling?) move? (contains? #{:move-blocks :move-blocks-up-down :indent-outdent-blocks} outliner-op) @@ -714,7 +720,9 @@ [blocks target-block {:keys [sibling? outliner-op]}] [:pre [(seq blocks) (s/valid? ::block-map-or-entity target-block)]] - (let [non-consecutive-blocks? (seq (db-model/get-non-consecutive-blocks blocks)) + (let [target-block (get-target-block target-block) + _ (assert (some? target-block) (str "Invalid target: " target-block)) + non-consecutive-blocks? (seq (db-model/get-non-consecutive-blocks blocks)) original-position? (move-to-original-position? blocks target-block sibling? non-consecutive-blocks?)] (when (and (not (contains? (set (map :db/id blocks)) (:db/id target-block))) (not original-position?)) diff --git a/src/main/frontend/modules/outliner/datascript.cljc b/src/main/frontend/modules/outliner/datascript.cljc index 6fad8bb1e6..5a5928775a 100644 --- a/src/main/frontend/modules/outliner/datascript.cljc +++ b/src/main/frontend/modules/outliner/datascript.cljc @@ -3,6 +3,7 @@ #?(:cljs (:require-macros [frontend.modules.outliner.datascript])) #?(:cljs (:require [datascript.core :as d] [frontend.db.conn :as conn] + [frontend.db :as db] [frontend.modules.outliner.pipeline :as pipelines] [frontend.modules.editor.undo-redo :as undo-redo] [frontend.state :as state] @@ -73,6 +74,12 @@ rs (d/transact! conn txs (assoc opts :outliner/transact? true)) tx-id (get-tx-id rs)] (swap! state/state assoc-in [:history/tx->editor-cursor tx-id] before-editor-cursor) + + ;; update the current edit block to include full information + (when-let [block (state/get-edit-block)] + (when (and (:block/uuid block) (not (:db/id block))) + (state/set-state! :editor/block (db/pull [:block/uuid (:block/uuid block)])))) + (when true ; TODO: add debug flag (let [eids (distinct (mapv first (:tx-data rs))) left&parent-list (->> diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index f56a8aae13..cd9813a05b 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -703,7 +703,7 @@ (gdom/getElement (state/get-editing-block-dom-id))) (.getAttribute "blockid") (db-model/get-block-by-uuid)))] - (get_block (:db/id block) opts)))) + (get_block (:block/uuid block) opts)))) (def ^:export get_previous_sibling_block (fn [block-uuid] From 862bbd7513b4e21c97c7fb11f9e0bdac9248e91b Mon Sep 17 00:00:00 2001 From: Andelf Date: Thu, 11 May 2023 16:16:16 +0800 Subject: [PATCH 32/81] test(e2e): refine test for template expansion --- e2e-tests/basic.spec.ts | 17 +++++++++++++++-- e2e-tests/fixtures.ts | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/e2e-tests/basic.spec.ts b/e2e-tests/basic.spec.ts index 0d2f581dda..6d835a0e0d 100644 --- a/e2e-tests/basic.spec.ts +++ b/e2e-tests/basic.spec.ts @@ -141,8 +141,8 @@ test('template', async ({ page, block }) => { await block.waitForBlocks(5) - // NOTE: use delay to type slower, to trigger auto-completion UI. - await block.clickNext() + // See-also: #9354 + await block.enterNext() await block.mustType('/template') await page.click('[title="Insert a created template here"]') @@ -154,6 +154,19 @@ test('template', async ({ page, block }) => { await popupMenuItem.click() await block.waitForBlocks(9) + + + await block.clickNext() + await block.mustType('/template') + + await page.click('[title="Insert a created template here"]') + // type to search template name + await page.keyboard.type(randomTemplate.substring(0, 3), { delay: 100 }) + + await popupMenuItem.waitFor({ timeout: 2000 }) // wait for template search + await popupMenuItem.click() + + await block.waitForBlocks(13) // 9 + 4 }) test('auto completion square brackets', async ({ page, block }) => { diff --git a/e2e-tests/fixtures.ts b/e2e-tests/fixtures.ts index 394f818809..79e923537a 100644 --- a/e2e-tests/fixtures.ts +++ b/e2e-tests/fixtures.ts @@ -27,7 +27,7 @@ const consoleLogWatcher = (msg: ConsoleMessage) => { const text = msg.text() logs += text + '\n' - expect(text, logs).not.toMatch(/^(Failed to|Uncaught)/) + expect(text, logs).not.toMatch(/^(Failed to|Uncaught|Assert failed)/) // youtube video // Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'ch-ua-reduced'. From 68709661e31807432ea6ebbbd10a841b6d1cb43e Mon Sep 17 00:00:00 2001 From: Billy Pinheiro Date: Thu, 11 May 2023 10:56:38 -0300 Subject: [PATCH 33/81] chore: added missing translations for pt-BR --- src/main/frontend/dicts.cljc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/frontend/dicts.cljc b/src/main/frontend/dicts.cljc index 1a47a746f7..c20e202897 100644 --- a/src/main/frontend/dicts.cljc +++ b/src/main/frontend/dicts.cljc @@ -2922,6 +2922,7 @@ :settings-page/spell-checker "Verificador ortográfico" :settings-page/disable-sentry "Enviar dados de utilização e diagnósticos para Logseq" :settings-page/preferred-outdenting "Ativar dedentação lógica" + :settings-page/auto-expand-block-refs "Expandir as referências de bloco automaticamente ao aumentar o zoom" :settings-page/custom-date-format "Formato de data preferido" :settings-page/preferred-file-format "Formato de Arquivo preferido" :settings-page/preferred-workflow "Fluxo de trabalho preferido" @@ -3249,6 +3250,10 @@ :left-side-bar/new-whiteboard "Novo quadro branco" :left-side-bar/nav-favorites "Favoritos" :left-side-bar/nav-recent-pages "Recente" + :page/something-went-wrong "Algo deu errado" + :page/logseq-is-having-a-problem "Logseq está tendo um problema. Para tentar colocá-lo de volta em um estado de funcionamento, por favor tente os seguintes passos seguros em ordem:" + :page/step "Passo {1}" + :page/try "Tentar" :page/presentation-mode "Modo de apresentação" :page/delete-confirmation "Tem a certeza de que quer apagar esta página e o respetivo ficheiro?" :page/open-in-finder "Abrir em pasta" @@ -3317,8 +3322,12 @@ :color/pink "Rosa" :editor/copy "Copiar" :editor/cut "Cortar" + :content/copy-export-as "Copiar / Exportar como.." + :content/copy-block-url "Copiar URL do bloco" :content/copy-block-ref "Copiar referência do bloco" :content/copy-block-emebed "Copiar bloco para incorporar" + :content/copy-ref "Copiar esta referência" + :content/delete-ref "Apagar esta referência" :content/open-in-sidebar "Abrir na barra lateral" :content/click-to-edit "Clicar para editar" :settings-page/git-confirm "É necessário reiniciar a aplicação após atualizar as definições do Git." @@ -3502,12 +3511,14 @@ :command-palette/prompt "Introduza um comando" :select/default-prompt "Selecione um" + :select/default-select-multiple "Selecione um ou vários" :select.graph/prompt "Selecione um grafo" :select.graph/empty-placeholder-description "Sem grafos correspondentes. Quer adicionar outro?" :select.graph/add-graph "Sim, adicionar outro grafo" :file-sync/other-user-graph "O grafo local atual está ligado ao grafo remoto de outro utilizador. Portanto, a sincronização não pode ser iniciada." :file-sync/graph-deleted "O grafo remoto atual foi apagado" + :file-sync/rsapi-cannot-upload-err "Não foi possível iniciar a sincronização, verifique se a hora local está correta." :notification/clear-all "Limpar tudo"} From d4cde54510903aa10340a95f1845f9f9d5907ea6 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Fri, 12 May 2023 15:13:16 +0800 Subject: [PATCH 34/81] fix: api get current block (#9372) --- src/main/logseq/api.cljs | 22 ++-------- src/main/logseq/api/block.cljs | 28 +++++++++++++ src/test/frontend/fs_test.cljs | 5 ++- .../frontend/handler/plugin_config_test.cljs | 3 +- src/test/frontend/test/helper.cljs | 17 +------- src/test/frontend/test/node_helper.cljs | 17 ++++++++ src/test/logseq/api_test.cljs | 40 +++++++++++++++++++ 7 files changed, 94 insertions(+), 38 deletions(-) create mode 100644 src/main/logseq/api/block.cljs create mode 100644 src/test/frontend/test/node_helper.cljs create mode 100644 src/test/logseq/api_test.cljs diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index cd9813a05b..9f49d9255f 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -43,7 +43,8 @@ [frontend.handler.shell :as shell] [frontend.modules.layout.core] [frontend.handler.code :as code-handler] - [frontend.handler.search :as search-handler])) + [frontend.handler.search :as search-handler] + [logseq.api.block :as api-block])) ;; Alert: this namespace shouldn't invoke any reactive queries @@ -676,24 +677,7 @@ target-block (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error target-block-uuid))] (editor-dnd-handler/move-blocks nil [src-block] target-block move-to) nil))) -(def ^:export get_block - (fn [id-or-uuid ^js opts] - (when-let [block (cond - (number? id-or-uuid) (db-utils/pull id-or-uuid) - (string? id-or-uuid) (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error id-or-uuid)))] - (when-not (contains? block :block/name) - (when-let [uuid (:block/uuid block)] - (let [{:keys [includeChildren]} (bean/->clj opts) - repo (state/get-current-repo) - block (if includeChildren - ;; nested children results - (first (outliner-tree/blocks->vec-tree - (db-model/get-block-and-children repo uuid) uuid)) - ;; attached shallow children - (assoc block :block/children - (map #(list :uuid (:block/uuid %)) - (db/get-block-immediate-children repo uuid))))] - (bean/->js (sdk-utils/normalize-keyword-for-json block)))))))) +(def ^:export get_block api-block/get_block) (def ^:export get_current_block (fn [^js opts] diff --git a/src/main/logseq/api/block.cljs b/src/main/logseq/api/block.cljs new file mode 100644 index 0000000000..d2eeed6881 --- /dev/null +++ b/src/main/logseq/api/block.cljs @@ -0,0 +1,28 @@ +(ns logseq.api.block + "Block related apis" + (:require [frontend.db.model :as db-model] + [frontend.db.utils :as db-utils] + [cljs-bean.core :as bean] + [frontend.state :as state] + [frontend.modules.outliner.tree :as outliner-tree] + [frontend.db :as db] + [logseq.sdk.utils :as sdk-utils])) + +(defn get_block + [id-or-uuid ^js opts] + (when-let [block (if (number? id-or-uuid) + (db-utils/pull id-or-uuid) + (db-model/query-block-by-uuid (sdk-utils/uuid-or-throw-error id-or-uuid)))] + (when-not (contains? block :block/name) + (when-let [uuid (:block/uuid block)] + (let [{:keys [includeChildren]} (bean/->clj opts) + repo (state/get-current-repo) + block (if includeChildren + ;; nested children results + (first (outliner-tree/blocks->vec-tree + (db-model/get-block-and-children repo uuid) uuid)) + ;; attached shallow children + (assoc block :block/children + (map #(list :uuid (:block/uuid %)) + (db/get-block-immediate-children repo uuid))))] + (bean/->js (sdk-utils/normalize-keyword-for-json block))))))) diff --git a/src/test/frontend/fs_test.cljs b/src/test/frontend/fs_test.cljs index 879b90e135..c4204d81f5 100644 --- a/src/test/frontend/fs_test.cljs +++ b/src/test/frontend/fs_test.cljs @@ -2,6 +2,7 @@ (:require [clojure.test :refer [is use-fixtures]] [frontend.test.fixtures :as fixtures] [frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]] + [frontend.test.node-helper :as test-node-helper] [frontend.fs :as fs] [promesa.core :as p] ["fs" :as fs-node] @@ -11,7 +12,7 @@ (deftest-async create-if-not-exists-creates-correctly ;; dir needs to be an absolute path for fn to work correctly - (let [dir (node-path/resolve (test-helper/create-tmp-dir)) + (let [dir (node-path/resolve (test-node-helper/create-tmp-dir)) some-file (node-path/join dir "something.txt")] (-> @@ -29,7 +30,7 @@ (fs-node/rmdirSync dir)))))) (deftest-async create-if-not-exists-does-not-create-correctly - (let [dir (node-path/resolve (test-helper/create-tmp-dir)) + (let [dir (node-path/resolve (test-node-helper/create-tmp-dir)) some-file (node-path/join dir "something.txt")] (fs-node/writeFileSync some-file "OLD") diff --git a/src/test/frontend/handler/plugin_config_test.cljs b/src/test/frontend/handler/plugin_config_test.cljs index c01f6790d4..0bcdae4178 100644 --- a/src/test/frontend/handler/plugin_config_test.cljs +++ b/src/test/frontend/handler/plugin_config_test.cljs @@ -1,6 +1,7 @@ (ns frontend.handler.plugin-config-test (:require [clojure.test :refer [is use-fixtures testing deftest]] [frontend.test.helper :as test-helper :include-macros true :refer [deftest-async]] + [frontend.test.node-helper :as test-node-helper] [frontend.test.fixtures :as fixtures] [frontend.handler.plugin-config :as plugin-config-handler] [frontend.handler.global-config :as global-config-handler] @@ -17,7 +18,7 @@ (defn- create-global-config-dir [] - (let [dir (test-helper/create-tmp-dir "config") + (let [dir (test-node-helper/create-tmp-dir "config") root-dir (node-path/dirname dir)] (reset! global-config-handler/root-dir root-dir) dir)) diff --git a/src/test/frontend/test/helper.cljs b/src/test/frontend/test/helper.cljs index 437a754e6e..97849ab18d 100644 --- a/src/test/frontend/test/helper.cljs +++ b/src/test/frontend/test/helper.cljs @@ -1,9 +1,7 @@ (ns frontend.test.helper "Common helper fns for tests" (:require [frontend.handler.repo :as repo-handler] - [frontend.db.conn :as conn] - ["path" :as node-path] - ["fs" :as fs-node])) + [frontend.db.conn :as conn])) (defonce test-db "test-db") @@ -24,16 +22,3 @@ This can be called in synchronous contexts as no async fns should be invoked" files ;; Set :refresh? to avoid creating default files in after-parse {:re-render? false :verbose false :refresh? true})) - -(defn create-tmp-dir - "Creates a temporary directory under tmp/. If a subdir is given, creates an - additional subdirectory under the newly created temp directory." - ([] (create-tmp-dir nil)) - ([subdir] - (when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp")) - (let [dir (fs-node/mkdtempSync (node-path/join "tmp" "unit-test-"))] - (if subdir - (do - (fs-node/mkdirSync (node-path/join dir subdir)) - (node-path/join dir subdir)) - dir)))) diff --git a/src/test/frontend/test/node_helper.cljs b/src/test/frontend/test/node_helper.cljs new file mode 100644 index 0000000000..bade47d95e --- /dev/null +++ b/src/test/frontend/test/node_helper.cljs @@ -0,0 +1,17 @@ +(ns frontend.test.node-helper + "Common helper fns for node tests" + (:require ["path" :as node-path] + ["fs" :as fs-node])) + +(defn create-tmp-dir + "Creates a temporary directory under tmp/. If a subdir is given, creates an + additional subdirectory under the newly created temp directory." + ([] (create-tmp-dir nil)) + ([subdir] + (when-not (fs-node/existsSync "tmp") (fs-node/mkdirSync "tmp")) + (let [dir (fs-node/mkdtempSync (node-path/join "tmp" "unit-test-"))] + (if subdir + (do + (fs-node/mkdirSync (node-path/join dir subdir)) + (node-path/join dir subdir)) + dir)))) diff --git a/src/test/logseq/api_test.cljs b/src/test/logseq/api_test.cljs new file mode 100644 index 0000000000..18211b3a31 --- /dev/null +++ b/src/test/logseq/api_test.cljs @@ -0,0 +1,40 @@ +(ns logseq.api-test + (:require [cljs.test :refer [use-fixtures deftest is]] + [frontend.test.helper :as test-helper] + [frontend.db :as db] + [logseq.api.block :as api-block] + [frontend.state :as state] + [cljs-bean.core :as bean])) + +(use-fixtures :each {:before test-helper/start-test-db! + :after test-helper/destroy-test-db!}) + +(deftest get-block + (with-redefs [state/get-current-repo (constantly test-helper/test-db)] + (db/transact! test-helper/test-db + [{:db/id 10000 + :block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0" + :block/content "1"} + {:db/id 10001 + :block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" + :block/content "2"} + {:db/id 10002 + :block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556" + :block/parent 10001 + :block/left 10001 + :block/content "3"} + {:db/id 10003 + :block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d" + :block/parent 10002 + :block/left 10002 + :block/content "4"}]) + + (is (= (:content (bean/->clj (api-block/get_block 10000 #js {}))) "1")) + (is (= (:content (bean/->clj (api-block/get_block "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2")) + (is (= (:content (bean/->clj (api-block/get_block #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2")) + (is (= {:id 10001, :content "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :children [["uuid" "adae3006-f03e-4814-a1f5-f17f15b86556"]]} + (bean/->clj (api-block/get_block 10001 #js {:includeChildren false})))) + (is (= {:content "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :id 10001, :children [{:content "3", :left {:id 10001}, :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :id 10002, :level 1, :children [{:content "4", :left {:id 10002}, :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :id 10003, :level 2, :children []}]}]} + (bean/->clj (api-block/get_block 10001 #js {:includeChildren true})))))) + +#_(cljs.test/run-tests) From 1a9563478ebac208267655e3821d9db8a986178f Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 12 May 2023 17:32:15 +0800 Subject: [PATCH 35/81] fix(ui): incorrect arrangement of ui items from pagebar --- src/main/frontend/components/plugins.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/frontend/components/plugins.css b/src/main/frontend/components/plugins.css index 871ac7f303..342e664807 100644 --- a/src/main/frontend/components/plugins.css +++ b/src/main/frontend/components/plugins.css @@ -836,6 +836,16 @@ > .injected-ui-item-pagebar { @apply pr-3 opacity-30 hover:opacity-100 transition-opacity; } + + > .list-wrap { + @apply flex items-center flex-nowrap overflow-x-hidden pt-[14px]; + } + + a.button { + @apply flex items-center; + + color: var(--ls-primary-text-color); + } } .toolbar-plugins-manager { From 3936b752a81a46af9291ed92911a980482d948e7 Mon Sep 17 00:00:00 2001 From: Andelf Date: Fri, 12 May 2023 13:12:38 +0800 Subject: [PATCH 36/81] fix(ui): renaming input edit on-click See-also: 6b94181116dbaec8d72a2fc6dae5dd424f3a5bd1 Related: #9368 --- src/main/frontend/components/page.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index a0bbc5df8a..43ff0d6f57 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -276,7 +276,7 @@ a.page-title { } > .title { - @apply w-full overflow-hidden overflow-ellipsis; + @apply w-full pointer-events-none overflow-hidden overflow-ellipsis; } .edit-input { From 4a42fe9f321cb8515706d4392057208876a60d1e Mon Sep 17 00:00:00 2001 From: Andelf Date: Fri, 12 May 2023 14:14:30 +0800 Subject: [PATCH 37/81] refactor(ui): refine page renaming ui --- src/main/frontend/components/page.cljs | 51 +++++++++++++------------- src/main/frontend/components/page.css | 2 +- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 5e09a8e44d..f4b0ac5bab 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -262,7 +262,7 @@ :else (state/set-modal! (confirm-fn))) (util/stop e))] - [:span.absolute.inset-0.edit-input-wrapper + [:span.inset-0.edit-input-wrapper {:class (util/classnames [{:editing @*edit?}])} [:input.edit-input {:type "text" @@ -317,19 +317,20 @@ (when (util/right-click? e) (state/set-state! :page-title/context {:page page-name}))) :on-click (fn [e] - (.preventDefault e) - (if (gobj/get e "shiftKey") - (when-let [page (db/pull repo '[*] [:block/name page-name])] - (state/sidebar-add-block! - repo - (:db/id page) - :page)) - (when (and (not hls-page?) (not fmt-journal?) (not config/publishing?)) - (reset! *input-value (if untitled? "" old-name)) - (reset! *edit? true))))} + (when-not (= (.-nodeName (.-target e)) "INPUT") + (.preventDefault e) + (if (gobj/get e "shiftKey") + (when-let [page (db/pull repo '[*] [:block/name page-name])] + (state/sidebar-add-block! + repo + (:db/id page) + :page)) + (when (and (not hls-page?) (not fmt-journal?) (not config/publishing?)) + (reset! *input-value (if untitled? "" old-name)) + (reset! *edit? true)))))} (when (not= icon "") [:span.page-icon icon]) - [:div.page-title-sizer-wrapper.relative - (when @*edit? + [:div.page-title-sizer-wrapper + (if @*edit? (page-title-editor {:*title-value *title-value :*edit? *edit? :*input-value *input-value @@ -337,18 +338,18 @@ :page-name page-name :old-name old-name :untitled? untitled? - :whiteboard-page? whiteboard-page?})) - [:span.title.block - {:data-value @*input-value - :data-ref page-name - :style {:opacity (when @*edit? 0)}} - (let [nested? (and (string/includes? title page-ref/left-brackets) - (string/includes? title page-ref/right-brackets))] - (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] - untitled? [:span.opacity-50 (t :untitled)] - nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config - (:block/format page)))) - :else title))]]]))) + :whiteboard-page? whiteboard-page?}) + [:span.title.block + {:data-value @*input-value + :data-ref page-name + :style {:opacity (when @*edit? 0)}} + (let [nested? (and (string/includes? title page-ref/left-brackets) + (string/includes? title page-ref/right-brackets))] + (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] + untitled? [:span.opacity-50 (t :untitled)] + nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config + (:block/format page)))) + :else title))])]]))) (defn- page-mouse-over [e *control-show? *all-collapsed?] diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index 43ff0d6f57..a0bbc5df8a 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -276,7 +276,7 @@ a.page-title { } > .title { - @apply w-full pointer-events-none overflow-hidden overflow-ellipsis; + @apply w-full overflow-hidden overflow-ellipsis; } .edit-input { From f08ec9d0deeb4b6765a9675fbe1ab0211365f699 Mon Sep 17 00:00:00 2001 From: Andelf Date: Fri, 12 May 2023 14:36:13 +0800 Subject: [PATCH 38/81] refactor(ui): refine page renaming ui using z-index --- src/main/frontend/components/page.cljs | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index f4b0ac5bab..93409b3d5f 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -262,7 +262,7 @@ :else (state/set-modal! (confirm-fn))) (util/stop e))] - [:span.inset-0.edit-input-wrapper + [:span.absolute.inset-0.edit-input-wrapper.z-10 {:class (util/classnames [{:editing @*edit?}])} [:input.edit-input {:type "text" @@ -329,8 +329,8 @@ (reset! *input-value (if untitled? "" old-name)) (reset! *edit? true)))))} (when (not= icon "") [:span.page-icon icon]) - [:div.page-title-sizer-wrapper - (if @*edit? + [:div.page-title-sizer-wrapper.relative + (when @*edit? (page-title-editor {:*title-value *title-value :*edit? *edit? :*input-value *input-value @@ -338,18 +338,18 @@ :page-name page-name :old-name old-name :untitled? untitled? - :whiteboard-page? whiteboard-page?}) - [:span.title.block - {:data-value @*input-value - :data-ref page-name - :style {:opacity (when @*edit? 0)}} - (let [nested? (and (string/includes? title page-ref/left-brackets) - (string/includes? title page-ref/right-brackets))] - (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] - untitled? [:span.opacity-50 (t :untitled)] - nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config - (:block/format page)))) - :else title))])]]))) + :whiteboard-page? whiteboard-page?})) + [:span.title.block + {:data-value @*input-value + :data-ref page-name + :style {:opacity (when @*edit? 0)}} + (let [nested? (and (string/includes? title page-ref/left-brackets) + (string/includes? title page-ref/right-brackets))] + (cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)] + untitled? [:span.opacity-50 (t :untitled)] + nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config + (:block/format page)))) + :else title))]]]))) (defn- page-mouse-over [e *control-show? *all-collapsed?] From 3c7d9615786b199c506f58bb9cf39992f28401ce Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 12 May 2023 14:58:12 +0800 Subject: [PATCH 39/81] fix(ui): vertical shake when editing page name --- src/main/frontend/components/page.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index a0bbc5df8a..ad93a8ecd4 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -249,6 +249,7 @@ box-shadow: none; padding-left: 5px; padding-top: 5px; + padding-bottom: 4px; &-wrapper { @apply rounded; From 3fd595ad2ce7617c4da3cfe2745281f4a2e546ed Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 12 May 2023 11:25:22 +0800 Subject: [PATCH 40/81] fix(ui): vertical alignment for ordered list marker with bullet marker --- src/main/frontend/components/block.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index da835e1d00..d44ee043ae 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -531,7 +531,7 @@ } &.as-order-list { - @apply w-[28px] whitespace-nowrap justify-start; + @apply w-[28px] whitespace-nowrap justify-start pl-[4px]; } .bullet { From 6689d886d7571dea820b7345e425812a9dc08e27 Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 12 May 2023 11:27:23 +0800 Subject: [PATCH 41/81] fix(ux): automatic block number list for semantic input --- src/main/frontend/handler/editor.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index cab9e2f908..6cffe63c7b 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1832,8 +1832,9 @@ (and (= content "1. ") (= last-input-char " ") input-id edit-block (not (own-order-number-list? edit-block))) (do - (state/pub-event! [:editor/toggle-own-number-list edit-block]) - (state/set-edit-content! input-id "")) + (state/set-edit-content! input-id "") + (-> (p/delay 10) + (p/then #(state/pub-event! [:editor/toggle-own-number-list edit-block])))) (and (= last-input-char (state/get-editor-command-trigger)) (or (re-find #"(?m)^/" (str (.-value input))) (start-of-new-word? input pos))) From a842b7de726982fc316a90621f23ddf156a1538a Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Fri, 12 May 2023 18:47:21 +0800 Subject: [PATCH 42/81] fix: align block content for ordered items and unordered items --- src/main/frontend/components/block.cljs | 2 +- src/main/frontend/components/block.css | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index f17b75ae1b..fe9e851f28 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -1738,7 +1738,7 @@ order-list? (boolean own-number-list?) order-list-idx (:own-order-list-index config) collapsable? (editor-handler/collapsable? uuid {:semantic? true})] - [:div.block-control-wrap.mr-1.flex.flex-row.items-center.sm:mr-2 + [:div.block-control-wrap.flex.flex-row.items-center {:class (util/classnames [{:is-order-list order-list? :bullet-closed collapsed?}])} (when (or (not fold-button-right?) collapsable?) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index d44ee043ae..63634aaf14 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -202,6 +202,7 @@ .block-control-wrap { height: 24px; + min-width: 50px; margin-top: 0; &.is-order-list { @@ -531,7 +532,7 @@ } &.as-order-list { - @apply w-[28px] whitespace-nowrap justify-start pl-[4px]; + @apply w-[28px] whitespace-nowrap justify-start pl-[3px]; } .bullet { From 2bc8691c23b17fe7ac4588069f6bab42b93481ee Mon Sep 17 00:00:00 2001 From: charlie Date: Sun, 7 May 2023 10:42:40 +0800 Subject: [PATCH 43/81] enhance(ui): support tabler extensions icons to the react components --- public/index.html | 1 + resources/electron.html | 1 + resources/index.html | 1 + resources/js/tabler.ext.js | 797 +++++++++++++++++++++ src/main/frontend/components/settings.cljs | 2 +- 5 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 resources/js/tabler.ext.js diff --git a/public/index.html b/public/index.html index 651bbcf265..1021107a83 100644 --- a/public/index.html +++ b/public/index.html @@ -55,6 +55,7 @@ + diff --git a/resources/electron.html b/resources/electron.html index e7ebedef83..0eb9662f76 100644 --- a/resources/electron.html +++ b/resources/electron.html @@ -56,6 +56,7 @@ const portal = new MagicPortal(worker); + diff --git a/resources/index.html b/resources/index.html index 074b2d252e..892095b5b0 100644 --- a/resources/index.html +++ b/resources/index.html @@ -55,6 +55,7 @@ const portal = new MagicPortal(worker); + diff --git a/resources/js/tabler.ext.js b/resources/js/tabler.ext.js new file mode 100644 index 0000000000..d44fef9166 --- /dev/null +++ b/resources/js/tabler.ext.js @@ -0,0 +1,797 @@ +const $9c08ab62231cd969$export$34b9dba7ce09269b = React.createElement; +const $9c08ab62231cd969$export$25062201e9e25d76 = React.createElement; + + +var $cdf24df9d8a2d360$exports = {}; +$cdf24df9d8a2d360$exports = React; + + +function $2f2bddd7db8296ac$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtAddLink", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M12.2933 4.29278C13.1438 3.4422 14.2975 2.96436 15.5004 2.96436C16.7033 2.96436 17.8569 3.4422 18.7075 4.29278C19.5581 5.14336 20.0359 6.29699 20.0359 7.49989C20.0359 8.70279 19.5581 9.85642 18.7075 10.707L14.7109 14.7036C14.2927 15.1294 13.7939 15.4678 13.2436 15.699C12.6917 15.9309 12.099 16.0504 11.5004 16.0504C10.9017 16.0504 10.309 15.9309 9.7571 15.699C9.20517 15.4671 8.70507 15.1274 8.28608 14.6997C7.89956 14.3053 7.90602 13.6721 8.30051 13.2856C8.695 12.8991 9.32813 12.9055 9.71465 13.3C9.94742 13.5376 10.2253 13.7263 10.5319 13.8552C10.8385 13.984 11.1678 14.0504 11.5004 14.0504C11.833 14.0504 12.1622 13.984 12.4688 13.8552C12.7755 13.7263 13.0533 13.5376 13.2861 13.3L13.2932 13.2927L13.2933 13.2928L17.2933 9.29278C17.7688 8.81728 18.0359 8.17235 18.0359 7.49989C18.0359 6.82742 17.7688 6.1825 17.2933 5.707C16.8178 5.23149 16.1728 4.96436 15.5004 4.96436C14.8279 4.96436 14.183 5.23149 13.7075 5.707L13.2075 6.207C12.8169 6.59752 12.1838 6.59752 11.7933 6.207C11.4027 5.81647 11.4027 5.18331 11.7933 4.79278L12.2933 4.29278ZM8.75711 8.30085C9.30904 8.06892 9.9017 7.94946 10.5004 7.94946C11.0991 7.94946 11.6917 8.06892 12.2436 8.30085C12.7956 8.53277 13.2957 8.87249 13.7147 9.30012C14.1012 9.69461 14.0947 10.3277 13.7002 10.7143C13.3057 11.1008 12.6726 11.0943 12.2861 10.6998C12.0533 10.4623 11.7755 10.2735 11.4689 10.1447C11.1622 10.0158 10.833 9.94946 10.5004 9.94946C10.1678 9.94946 9.83853 10.0158 9.5319 10.1447C9.22527 10.2735 8.94743 10.4623 8.71466 10.6998L8.70752 10.7071L8.70748 10.7071L4.70748 14.7071C4.23198 15.1826 3.96484 15.8275 3.96484 16.5C3.96484 17.1724 4.23198 17.8174 4.70748 18.2929C5.18299 18.7684 5.82791 19.0355 6.50038 19.0355C7.17284 19.0355 7.81777 18.7684 8.29327 18.2929L8.79327 17.7929C9.18379 17.4023 9.81696 17.4023 10.2075 17.7929C10.598 18.1834 10.598 18.8166 10.2075 19.2071L9.70748 19.7071C8.85691 20.5577 7.70328 21.0355 6.50038 21.0355C5.29748 21.0355 4.14385 20.5577 3.29327 19.7071C2.44269 18.8565 1.96484 17.7029 1.96484 16.5C1.96484 15.2971 2.44269 14.1434 3.29327 13.2929L7.28985 9.29629C7.70807 8.87046 8.20683 8.53208 8.75711 8.30085ZM19.0005 14C19.5528 14 20.0005 14.4477 20.0005 15V17H22.0005C22.5528 17 23.0005 17.4477 23.0005 18C23.0005 18.5523 22.5528 19 22.0005 19H20.0005V21C20.0005 21.5523 19.5528 22 19.0005 22C18.4482 22 18.0005 21.5523 18.0005 21V19H16.0005C15.4482 19 15.0005 18.5523 15.0005 18C15.0005 17.4477 15.4482 17 16.0005 17H18.0005V15C18.0005 14.4477 18.4482 14 19.0005 14Z", + fill: color + }) + }); +} + + + + +function $2ed6e80f53bbb577$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$25062201e9e25d76)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtAppFeature", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: [ + /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M2 7C2 5.34315 3.34315 4 5 4H19C20.6569 4 22 5.34315 22 7V17C22 18.6569 20.6569 20 19 20H15.0209C15.0064 20.0003 14.992 20.0003 14.9776 20H9.02243C9.00802 20.0003 8.99357 20.0003 8.97908 20H5C3.34315 20 2 18.6569 2 17V7ZM13.7192 18L13.5299 17.2425C13.4447 16.9018 13.5445 16.5413 13.7929 16.2929L14.8787 15.2071L13.3586 14.9899C13.0337 14.9435 12.7523 14.7407 12.6056 14.4472L12 13.2361L11.3944 14.4472C11.2477 14.7407 10.9663 14.9435 10.6414 14.9899L9.12132 15.2071L10.2071 16.2929C10.4555 16.5413 10.5553 16.9018 10.4701 17.2425L10.2808 18H13.7192ZM15.7808 18H19C19.5523 18 20 17.5523 20 17V7C20 6.44772 19.5523 6 19 6H5C4.44772 6 4 6.44772 4 7V17C4 17.5523 4.44772 18 5 18H8.21922L8.39254 17.3067L6.29289 15.2071C6.02506 14.9393 5.93154 14.5431 6.05132 14.1838C6.17109 13.8244 6.48361 13.5636 6.85858 13.5101L9.83989 13.0841L11.1056 10.5528C11.275 10.214 11.6212 10 12 10C12.3788 10 12.725 10.214 12.8944 10.5528L14.1601 13.0841L17.1414 13.5101C17.5164 13.5636 17.8289 13.8244 17.9487 14.1838C18.0685 14.5431 17.9749 14.9393 17.7071 15.2071L15.6075 17.3067L15.7808 18Z", + fill: color + }), + /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + d: "M6 6.99C6.55228 6.99 7 7.43771 7 7.99V8C7 8.55229 6.55228 9 6 9C5.44772 9 5 8.55229 5 8V7.99C5 7.43771 5.44772 6.99 6 6.99Z", + fill: color + }), + /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + d: "M9 6.99C9.55228 6.99 10 7.43771 10 7.99V8C10 8.55228 9.55228 9 9 9C8.44772 9 8 8.55228 8 8V7.99C8 7.43771 8.44772 6.99 9 6.99Z", + fill: color + }) + ] + }); +} + + + + +function $e77db804f0d51e68$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtBlockSearch", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H14C14.5523 12 15 12.4477 15 13C15 13.5523 14.5523 14 14 14H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z", + fill: color + }) + }); +} + + + + +function $fb0444e266164f77$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtBlock", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M9 10C9 9.44772 9.44772 9 10 9H22C22.5523 9 23 9.44772 23 10V14C23 14.5523 22.5523 15 22 15H10C9.44772 15 9 14.5523 9 14V10ZM11 11V13H21V11H11ZM1 12C1 10.8954 1.89543 10 3 10C4.10457 10 5 10.8954 5 12C5 13.1046 4.10457 14 3 14C1.89543 14 1 13.1046 1 12Z", + fill: color + }) + }); +} + + + + +function $08a8988d553c61f7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtCloudExclamation", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M13.4366 6.03387C12.8308 5.92373 12.2062 5.92205 11.5997 6.02894C10.9931 6.13582 10.4204 6.34848 9.91384 6.65116C8.89016 7.26279 8.20994 8.19494 7.98007 9.21902C7.87759 9.67556 7.47225 10 7.00435 10C6.00786 10 5.06063 10.3791 4.36896 11.0407C3.6788 11.7008 3.2998 12.5864 3.2998 13.5C3.2998 14.4136 3.6788 15.2992 4.36896 15.9593C5.06063 16.6209 6.00786 17 7.00435 17H8C8.55228 17 9 17.4477 9 18C9 18.5523 8.55228 19 8 19H7.00435C5.5054 19 4.05939 18.4308 2.98651 17.4046C1.91213 16.3769 1.2998 14.9734 1.2998 13.5C1.2998 12.0266 1.91213 10.6231 2.98651 9.59538C3.87696 8.74365 5.02444 8.20677 6.24589 8.04882C6.72397 6.76252 7.65926 5.66843 8.88803 4.93427C9.60923 4.50337 10.4128 4.20727 11.2526 4.05929C12.0923 3.91131 12.9556 3.91362 13.7943 4.06613C14.6332 4.21864 15.4349 4.5191 16.1534 4.95398C16.8721 5.38893 17.4955 5.95128 17.9839 6.61332C18.4724 7.27568 18.8155 8.02416 18.988 8.817C19.0731 9.20796 19.1156 9.60469 19.1155 10.0014C20.2687 10.0298 21.3686 10.5003 22.1863 11.318C23.0302 12.1619 23.5044 13.3065 23.5044 14.5C23.5044 15.6935 23.0302 16.8381 22.1863 17.682C21.3424 18.5259 20.1978 19 19.0044 19H16C15.4477 19 15 18.5523 15 18C15 17.4477 15.4477 17 16 17H19.0044C19.6674 17 20.3033 16.7366 20.7721 16.2678C21.241 15.7989 21.5044 15.163 21.5044 14.5C21.5044 13.837 21.241 13.2011 20.7721 12.7322C20.3033 12.2634 19.6674 12 19.0044 12H18.0044C17.7007 12 17.4134 11.862 17.2236 11.6249C17.0339 11.3878 16.9621 11.0773 17.0286 10.781C17.1427 10.273 17.1444 9.75071 17.0337 9.24219C16.9231 8.7334 16.7009 8.24319 16.3744 7.80054C16.0476 7.35756 15.6221 6.9702 15.1178 6.66498C14.6134 6.35969 14.0423 6.144 13.4366 6.03387ZM12 14C12.5523 14 13 14.4477 13 15V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V15C11 14.4477 11.4477 14 12 14ZM12 21C12.5523 21 13 21.4477 13 22V22.01C13 22.5623 12.5523 23.01 12 23.01C11.4477 23.01 11 22.5623 11 22.01V22C11 21.4477 11.4477 21 12 21Z", + fill: color + }) + }); +} + + + + +function $49e69b962236d70e$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtConnector", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M11 5C11 4.44772 11.4477 4 12 4H19C19.5523 4 20 4.44772 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V7.41421L5.70711 19.7071C5.31658 20.0976 4.68342 20.0976 4.29289 19.7071C3.90237 19.3166 3.90237 18.6834 4.29289 18.2929L16.5858 6H12C11.4477 6 11 5.55228 11 5Z", + fill: color + }) + }); +} + + + + +function $e30e0c04983a7679$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtGroup", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M1 2C1 1.44772 1.44772 1 2 1H4C4.55228 1 5 1.44772 5 2H19C19 1.44772 19.4477 1 20 1H22C22.5523 1 23 1.44772 23 2V4C23 4.55228 22.5523 5 22 5V19C22.5523 19 23 19.4477 23 20V22C23 22.5523 22.5523 23 22 23H20C19.4477 23 19 22.5523 19 22H5C5 22.5523 4.55228 23 4 23H2C1.44772 23 1 22.5523 1 22V20C1 19.4477 1.44772 19 2 19V5C1.44772 5 1 4.55228 1 4V2ZM4 5V19C4.55228 19 5 19.4477 5 20H19C19 19.4477 19.4477 19 20 19V5C19.4477 5 19 4.55228 19 4H5C5 4.55228 4.55228 5 4 5ZM6 7C6 6.44772 6.44772 6 7 6H13C13.5523 6 14 6.44772 14 7V9H17C17.5523 9 18 9.44772 18 10V17C18 17.5523 17.5523 18 17 18H10C9.44772 18 9 17.5523 9 17V14H7C6.44772 14 6 13.5523 6 13V7ZM11 14V16H16V11H14V13C14 13.5523 13.5523 14 13 14H11ZM12 8H8V12H12V8Z", + fill: color + }) + }); +} + + + + +function $1f8342347736f9c2$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtH-auto", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M2 6C2 5.44772 2.44772 5 3 5H5C5.55228 5 6 5.44772 6 6C6 6.55228 5.55228 7 5 7V11H11V7C10.4477 7 10 6.55228 10 6C10 5.44772 10.4477 5 11 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7V17C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H11C10.4477 19 10 18.5523 10 18C10 17.4477 10.4477 17 11 17V13H5V17C5.55228 17 6 17.4477 6 18C6 18.5523 5.55228 19 5 19H3C2.44772 19 2 18.5523 2 18C2 17.4477 2.44772 17 3 17V7C2.44772 7 2 6.55228 2 6ZM19 11C18.7348 11 18.4804 11.1054 18.2929 11.2929C18.1054 11.4804 18 11.7348 18 12V14H20V12C20 11.7348 19.8946 11.4804 19.7071 11.2929C19.5196 11.1054 19.2652 11 19 11ZM22 12C22 11.2043 21.6839 10.4413 21.1213 9.87868C20.5587 9.31607 19.7957 9 19 9C18.2043 9 17.4413 9.31607 16.8787 9.87868C16.3161 10.4413 16 11.2043 16 12V18C16 18.5523 16.4477 19 17 19C17.5523 19 18 18.5523 18 18V16H20V18C20 18.5523 20.4477 19 21 19C21.5523 19 22 18.5523 22 18V12Z", + fill: color + }) + }); +} + + + + +function $9e73d5ea1cb39667$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtHeadingOff", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M2.29289 2.29289C2.68342 1.90237 3.31658 1.90237 3.70711 2.29289L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L18.5858 20H15C14.4477 20 14 19.5523 14 19C14 18.4477 14.4477 18 15 18H16V17.4142L11.5858 13H8V18H9C9.55228 18 10 18.4477 10 19C10 19.5523 9.55228 20 9 20H5C4.44772 20 4 19.5523 4 19C4 18.4477 4.44772 18 5 18H6V7.41421L2.29289 3.70711C1.90237 3.31658 1.90237 2.68342 2.29289 2.29289ZM8 9.41421V11H9.58579L8 9.41421ZM8 5C8 4.44772 8.44772 4 9 4H10C10.5523 4 11 4.44772 11 5C11 5.55228 10.5523 6 10 6H9C8.44772 6 8 5.55228 8 5ZM14 5C14 4.44772 14.4477 4 15 4H19C19.5523 4 20 4.44772 20 5C20 5.55228 19.5523 6 19 6H18V12C18 12.5523 17.5523 13 17 13C16.4477 13 16 12.5523 16 12V6H15C14.4477 6 14 5.55228 14 5Z", + fill: color + }) + }); +} + + + + +function $269f902706cc17cf$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtInternalLink", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4 6C4 4.34315 5.34315 3 7 3H18C19.6569 3 21 4.34315 21 6V17C21 18.6569 19.6569 20 18 20H11C10.4477 20 10 19.5523 10 19C10 18.4477 10.4477 18 11 18H18C18.5523 18 19 17.5523 19 17V6C19 5.44772 18.5523 5 18 5H7C6.44772 5 6 5.44772 6 6V13C6 13.5523 5.55228 14 5 14C4.44772 14 4 13.5523 4 13V6ZM8 10C8 9.44772 8.44772 9 9 9H14C14.5523 9 15 9.44772 15 10V15C15 15.5523 14.5523 16 14 16C13.4477 16 13 15.5523 13 15V12.4142L4.70711 20.7071C4.31658 21.0976 3.68342 21.0976 3.29289 20.7071C2.90237 20.3166 2.90237 19.6834 3.29289 19.2929L11.5858 11H9C8.44772 11 8 10.5523 8 10Z", + fill: color + }) + }); +} + + + + +function $08c0c826d7adcea7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtLinkToBlock", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M9 8C9 7.44772 9.44772 7 10 7H22C22.5523 7 23 7.44772 23 8V12C23 12.5523 22.5523 13 22 13C21.4477 13 21 12.5523 21 12V9H11V12C11 12.5523 10.5523 13 10 13C9.44772 13 9 12.5523 9 12V8ZM1 10C1 8.89543 1.89543 8 3 8C4.10457 8 5 8.89543 5 10C5 11.1046 4.10457 12 3 12C1.89543 12 1 11.1046 1 10ZM15.2929 11.2929C15.6834 10.9024 16.3166 10.9024 16.7071 11.2929L19.7071 14.2929C20.0976 14.6834 20.0976 15.3166 19.7071 15.7071C19.3166 16.0976 18.6834 16.0976 18.2929 15.7071L17 14.4142V17C17 18.1046 17.8954 19 19 19H23C23.5523 19 24 19.4477 24 20C24 20.5523 23.5523 21 23 21H19C16.7909 21 15 19.2091 15 17V14.4142L13.7071 15.7071C13.3166 16.0976 12.6834 16.0976 12.2929 15.7071C11.9024 15.3166 11.9024 14.6834 12.2929 14.2929L15.2929 11.2929Z", + fill: color + }) + }); +} + + + + +function $473249f66f6ec7ca$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtLinkToPage", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4 4C4 2.34315 5.34315 1 7 1H17C18.6569 1 20 2.34315 20 4V18C20 18.5523 19.5523 19 19 19C18.4477 19 18 18.5523 18 18V4C18 3.44772 17.5523 3 17 3H7C6.44772 3 6 3.44772 6 4V18C6 18.5523 5.55228 19 5 19C4.44772 19 4 18.5523 4 18V4ZM8 6C8 5.44772 8.44772 5 9 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7H9C8.44772 7 8 6.55228 8 6ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L15.7071 16.2929C16.0976 16.6834 16.0976 17.3166 15.7071 17.7071C15.3166 18.0976 14.6834 18.0976 14.2929 17.7071L13 16.4142V19C13 20.1046 13.8954 21 15 21H19C19.5523 21 20 21.4477 20 22C20 22.5523 19.5523 23 19 23H15C12.7909 23 11 21.2091 11 19L11 16.4142L9.70711 17.7071C9.31658 18.0976 8.68342 18.0976 8.29289 17.7071C7.90237 17.3166 7.90237 16.6834 8.29289 16.2929L11.2929 13.2929Z", + fill: color + }) + }); +} + + + + +function $80b1e4efac5516b7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtLinkToWhiteboard", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M2 5C2 3.34315 3.34315 2 5 2H19C20.6569 2 22 3.34315 22 5V15C22 16.6569 20.6569 18 19 18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19C19.5523 16 20 15.5523 20 15V5C20 4.44772 19.5523 4 19 4H14V7C14 7.55228 13.5523 8 13 8H7C6.44772 8 6 7.55228 6 7V4H5C4.44772 4 4 4.44772 4 5V17C4 17.5523 3.55228 18 3 18C2.44772 18 2 17.5523 2 17V5ZM8 4V6H12V4H8ZM17 6C17.5523 6 18 6.44772 18 7V13C18 13.5523 17.5523 14 17 14C16.4477 14 16 13.5523 16 13V7C16 6.44772 16.4477 6 17 6ZM9.29289 12.2929C9.68342 11.9024 10.3166 11.9024 10.7071 12.2929L13.7071 15.2929C14.0976 15.6834 14.0976 16.3166 13.7071 16.7071C13.3166 17.0976 12.6834 17.0976 12.2929 16.7071L11 15.4142V18C11 19.1046 11.8954 20 13 20H17C17.5523 20 18 20.4477 18 21C18 21.5523 17.5523 22 17 22H13C10.7909 22 9 20.2091 9 18L9 15.4142L7.70711 16.7071C7.31658 17.0976 6.68342 17.0976 6.29289 16.7071C5.90237 16.3166 5.90237 15.6834 6.29289 15.2929L9.29289 12.2929Z", + fill: color + }) + }); +} + + + + +function $b5433be7bd57c127$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtNewBlock", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H16C16.5523 12 17 12.4477 17 13C17 13.5523 16.5523 14 16 14H13V16C13.5523 16 14 16.4477 14 17C14 17.5523 13.5523 18 13 18H12C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM20 13C20.5523 13 21 13.4477 21 14V16H23C23.5523 16 24 16.4477 24 17C24 17.5523 23.5523 18 23 18H21V20C21 20.5523 20.5523 21 20 21C19.4477 21 19 20.5523 19 20V18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19V14C19 13.4477 19.4477 13 20 13Z", + fill: color + }) + }); +} + + + + +function $628d33d496321a10$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtNewPage", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V5C18 4.44772 17.5523 4 17 4H7C6.44772 4 6 4.44772 6 5V17C6 17.5523 6.44772 18 7 18H12C12.5523 18 13 18.4477 13 19C13 19.5523 12.5523 20 12 20H7C5.34315 20 4 18.6569 4 17V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7ZM19 15C19.5523 15 20 15.4477 20 16V18H22C22.5523 18 23 18.4477 23 19C23 19.5523 22.5523 20 22 20H20V22C20 22.5523 19.5523 23 19 23C18.4477 23 18 22.5523 18 22V20H16C15.4477 20 15 19.5523 15 19C15 18.4477 15.4477 18 16 18H18V16C18 15.4477 18.4477 15 19 15Z", + fill: color + }) + }); +} + + + + +function $b2e1c3914295adcd$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtNewWhiteboardElement", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M6 4C5.44772 4 5 4.44772 5 5V6C5 6.55228 4.55228 7 4 7C3.44772 7 3 6.55228 3 6V5C3 3.34315 4.34315 2 6 2H8C8.55228 2 9 2.44772 9 3C9 3.55228 8.55228 4 8 4H6ZM15 3C15 2.44772 15.4477 2 16 2H18C19.6569 2 21 3.34315 21 5V6C21 6.55228 20.5523 7 20 7C19.4477 7 19 6.55228 19 6V5C19 4.44772 18.5523 4 18 4H16C15.4477 4 15 3.55228 15 3ZM7 9C7 8.44772 7.44772 8 8 8H16C16.5523 8 17 8.44772 17 9V13C17 13.5523 16.5523 14 16 14H8C7.44772 14 7 13.5523 7 13V9ZM9 10V12H15V10H9ZM4 15C4.55228 15 5 15.4477 5 16V17C5 17.5523 5.44772 18 6 18H8C8.55228 18 9 18.4477 9 19C9 19.5523 8.55228 20 8 20H6C4.34315 20 3 18.6569 3 17V16C3 15.4477 3.44772 15 4 15ZM20 15C20.5523 15 21 15.4477 21 16V18H23C23.5523 18 24 18.4477 24 19C24 19.5523 23.5523 20 23 20H21V22C21 22.5523 20.5523 23 20 23C19.4477 23 19 22.5523 19 22V20H17C16.4477 20 16 19.5523 16 19C16 18.4477 16.4477 18 17 18H19V16C19 15.4477 19.4477 15 20 15Z", + fill: color + }) + }); +} + + + + +function $fae0c08bf03a03bd$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtNewWhiteboard", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H13C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM20 14C20.5523 14 21 14.4477 21 15V17H23C23.5523 17 24 17.4477 24 18C24 18.5523 23.5523 19 23 19H21V21C21 21.5523 20.5523 22 20 22C19.4477 22 19 21.5523 19 21V19H17C16.4477 19 16 18.5523 16 18C16 17.4477 16.4477 17 17 17H19V15C19 14.4477 19.4477 14 20 14Z", + fill: color + }) + }); +} + + + + +function $2c448c2675ac8a8d$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtObjectCompact", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V9C21 9.55228 20.5523 10 20 10H18C17.4477 10 17 9.55228 17 9C17 8.44772 17.4477 8 18 8H19V4H5V8H6C6.55228 8 7 8.44772 7 9C7 9.55228 6.55228 10 6 10H4C3.44772 10 3 9.55228 3 9V3ZM11.2929 7.29289C11.6834 6.90237 12.3166 6.90237 12.7071 7.29289L16.7071 11.2929C17.0976 11.6834 17.0976 12.3166 16.7071 12.7071C16.3166 13.0976 15.6834 13.0976 15.2929 12.7071L13 10.4142V19C13 19.5523 12.5523 20 12 20C11.4477 20 11 19.5523 11 19V10.4142L8.70711 12.7071C8.31658 13.0976 7.68342 13.0976 7.29289 12.7071C6.90237 12.3166 6.90237 11.6834 7.29289 11.2929L11.2929 7.29289Z", + fill: color + }) + }); +} + + + + +function $16f3c278b0e156ce$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtObjectExpanded", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V3ZM5 4V8H8C8.55228 8 9 8.44772 9 9C9 9.55228 8.55228 10 8 10H5V20H19V10H16C15.4477 10 15 9.55228 15 9C15 8.44772 15.4477 8 16 8H19V4H5ZM12 6C12.5523 6 13 6.44772 13 7V14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071C12.3166 18.0976 11.6834 18.0976 11.2929 17.7071L7.29289 13.7071C6.90237 13.3166 6.90237 12.6834 7.29289 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858V7C11 6.44772 11.4477 6 12 6Z", + fill: color + }) + }); +} + + + + +function $cc6b6f913b94a64c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtOpenAsPage", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V18C20 19.6569 18.6569 21 17 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H17C17.5523 19 18 18.5523 18 18V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L14.7071 15.2929C15.0976 15.6834 15.0976 16.3166 14.7071 16.7071C14.3166 17.0976 13.6834 17.0976 13.2929 16.7071L13 16.4142V23C13 23.5523 12.5523 24 12 24C11.4477 24 11 23.5523 11 23L11 16.4142L10.7071 16.7071C10.3166 17.0976 9.68342 17.0976 9.29289 16.7071C8.90237 16.3166 8.90237 15.6834 9.29289 15.2929L11.2929 13.2929Z", + fill: color + }) + }); +} + + + + +function $824147aa23832e9d$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtPageSearch", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V11C20 11.5523 19.5523 12 19 12C18.4477 12 18 11.5523 18 11V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H10C10.5523 19 11 19.4477 11 20C11 20.5523 10.5523 21 10 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM16.5 16C15.6716 16 15 16.6716 15 17.5C15 18.3284 15.6716 19 16.5 19C17.3284 19 18 18.3284 18 17.5C18 16.6716 17.3284 16 16.5 16ZM13 17.5C13 15.567 14.567 14 16.5 14C18.433 14 20 15.567 20 17.5C20 18.1028 19.8476 18.6699 19.5793 19.1651L21.7071 21.2929C22.0976 21.6834 22.0976 22.3166 21.7071 22.7071C21.3166 23.0976 20.6834 23.0976 20.2929 22.7071L18.1651 20.5793C17.6699 20.8476 17.1028 21 16.5 21C14.567 21 13 19.433 13 17.5Z", + fill: color + }) + }); +} + + + + +function $f4f952ef4eef055c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtPage", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M7 4C6.44772 4 6 4.44772 6 5V19C6 19.5523 6.44771 20 7 20H17C17.5523 20 18 19.5523 18 19V5C18 4.44772 17.5523 4 17 4H7ZM4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V19C20 20.6569 18.6569 22 17 22H7C5.34315 22 4 20.6569 4 19V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7Z", + fill: color + }) + }); +} + + + + +function $8ce7267a82eb191c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtReferencesHide", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M11.2929 2.29289C11.6834 1.90237 12.3166 1.90237 12.7071 2.29289L14.7071 4.29289C15.0976 4.68342 15.0976 5.31658 14.7071 5.70711C14.3166 6.09763 13.6834 6.09763 13.2929 5.70711L12 4.41421L10.7071 5.70711C10.3166 6.09763 9.68342 6.09763 9.29289 5.70711C8.90237 5.31658 8.90237 4.68342 9.29289 4.29289L11.2929 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z", + fill: color + }) + }); +} + + + + +function $4742a6ccb1487a9b$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtReferencesShow", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M9.29289 2.29289C9.68342 1.90237 10.3166 1.90237 10.7071 2.29289L12 3.58579L13.2929 2.29289C13.6834 1.90237 14.3166 1.90237 14.7071 2.29289C15.0976 2.68342 15.0976 3.31658 14.7071 3.70711L12.7071 5.70711C12.3166 6.09763 11.6834 6.09763 11.2929 5.70711L9.29289 3.70711C8.90237 3.31658 8.90237 2.68342 9.29289 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z", + fill: color + }) + }); +} + + + + +function $65dd8c350aa54786$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtSelectCursor", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M4.29292 4.29289C4.56075 4.02506 4.95692 3.93154 5.31625 4.05132L19.3163 8.71798C19.7 8.84589 19.9688 9.19233 19.9975 9.59578C20.0262 9.99922 19.809 10.3802 19.4472 10.5611L16.6659 11.9518L19.4483 14.7343C19.8389 15.1248 19.8389 15.758 19.4483 16.1485L16.1485 19.4483C15.758 19.8388 15.1248 19.8388 14.7343 19.4483L11.9518 16.6658L10.5611 19.4472C10.3802 19.809 9.99925 20.0262 9.5958 19.9975C9.19236 19.9688 8.84591 19.6999 8.71801 19.3162L4.05134 5.31623C3.93157 4.95689 4.02509 4.56073 4.29292 4.29289ZM6.58117 6.58114L9.85194 16.3934L10.7834 14.5305C10.9272 14.2429 11.2004 14.0421 11.5177 13.9906C11.835 13.9391 12.1577 14.0433 12.385 14.2706L15.4414 17.327L17.327 15.4414L14.2706 12.3849C14.0433 12.1576 13.9391 11.8349 13.9906 11.5177C14.0421 11.2004 14.243 10.9272 14.5305 10.7834L16.3935 9.85191L6.58117 6.58114Z", + fill: color + }) + }); +} + + + + +function $d012c8b184d736e2$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtText", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V7C19 7.55228 18.5523 8 18 8C17.4477 8 17 7.55228 17 7V6H13V18H14C14.5523 18 15 18.4477 15 19C15 19.5523 14.5523 20 14 20H10C9.44772 20 9 19.5523 9 19C9 18.4477 9.44772 18 10 18H11V6H7V7C7 7.55228 6.55228 8 6 8C5.44772 8 5 7.55228 5 7V5Z", + fill: color + }) + }); +} + + + + +function $a0a0d0752878ab4c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtUngroup", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M2 3C2 2.44772 2.44772 2 3 2H5C5.55228 2 6 2.44772 6 3H12C12 2.44772 12.4477 2 13 2H15C15.5523 2 16 2.44772 16 3V5C16 5.55228 15.5523 6 15 6V8H18C18 7.44772 18.4477 7 19 7H21C21.5523 7 22 7.44772 22 8V10C22 10.5523 21.5523 11 21 11V18C21.5523 18 22 18.4477 22 19V21C22 21.5523 21.5523 22 21 22H19C18.4477 22 18 21.5523 18 21H11C11 21.5523 10.5523 22 10 22H8C7.44772 22 7 21.5523 7 21V19C7 18.4477 7.44772 18 8 18V15H6C6 15.5523 5.55228 16 5 16H3C2.44772 16 2 15.5523 2 15V13C2 12.4477 2.44772 12 3 12V6C2.44772 6 2 5.55228 2 5V3ZM5 6V12C5.55228 12 6 12.4477 6 13H12C12 12.4477 12.4477 12 13 12V6C12.4477 6 12 5.55228 12 5H6C6 5.55228 5.55228 6 5 6ZM15 12V10H18C18 10.5523 18.4477 11 19 11V18C18.4477 18 18 18.4477 18 19H11C11 18.4477 10.5523 18 10 18V15H12C12 15.5523 12.4477 16 13 16H15C15.5523 16 16 15.5523 16 15V13C16 12.4477 15.5523 12 15 12Z", + fill: color + }) + }); +} + + + + +function $6b53ec262a2764f5$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtWhiteboardElement", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M6 5C5.44772 5 5 5.44772 5 6V7C5 7.55228 4.55228 8 4 8C3.44772 8 3 7.55228 3 7V6C3 4.34315 4.34315 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6ZM15 4C15 3.44772 15.4477 3 16 3H18C19.6569 3 21 4.34315 21 6V7C21 7.55228 20.5523 8 20 8C19.4477 8 19 7.55228 19 7V6C19 5.44772 18.5523 5 18 5H16C15.4477 5 15 4.55228 15 4ZM7 10C7 9.44772 7.44772 9 8 9H16C16.5523 9 17 9.44772 17 10V14C17 14.5523 16.5523 15 16 15H8C7.44772 15 7 14.5523 7 14V10ZM9 11V13H15V11H9ZM4 16C4.55228 16 5 16.4477 5 17V18C5 18.5523 5.44772 19 6 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H6C4.34315 21 3 19.6569 3 18V17C3 16.4477 3.44772 16 4 16ZM20 16C20.5523 16 21 16.4477 21 17V18C21 19.6569 19.6569 21 18 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H18C18.5523 19 19 18.5523 19 18V17C19 16.4477 19.4477 16 20 16Z", + fill: color + }) + }); +} + + + + +function $6a588b38b4591064$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtWhiteboardSearch", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + fillRule: "evenodd", + clipRule: "evenodd", + d: "M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H12C12.5523 17 13 17.4477 13 18C13 18.5523 12.5523 19 12 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z", + fill: color + }) + }); +} + + + + +function $fb98c9f3ef9a367b$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { + return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + strokeWidth: stroke, + stroke: color, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "icon iconTabler iconTablerExtWhiteboard", + ...rest, + xmlns: "http://www.w3.org/2000/svg", + children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { + d: "M18 9C18 8.44772 17.5523 8 17 8C16.4477 8 16 8.44772 16 9H18ZM16 15C16 15.5523 16.4477 16 17 16C17.5523 16 18 15.5523 18 15H16ZM3 14C2.44772 14 2 14.4477 2 15C2 15.5523 2.44772 16 3 16V14ZM11 15H12C12 14.4477 11.5523 14 11 14V15ZM10 19C10 19.5523 10.4477 20 11 20C11.5523 20 12 19.5523 12 19H10ZM14 5C14 4.44772 13.5523 4 13 4C12.4477 4 12 4.44772 12 5H14ZM13 9V10C13.5523 10 14 9.55228 14 9H13ZM7 9H6C6 9.55228 6.44772 10 7 10V9ZM8 5C8 4.44772 7.55228 4 7 4C6.44772 4 6 4.44772 6 5H8ZM5 6H19V4H5V6ZM20 7V17H22V7H20ZM19 18H5V20H19V18ZM4 17V7H2V17H4ZM5 18C4.44772 18 4 17.5523 4 17H2C2 18.6569 3.34315 20 5 20V18ZM20 17C20 17.5523 19.5523 18 19 18V20C20.6569 20 22 18.6569 22 17H20ZM19 6C19.5523 6 20 6.44772 20 7H22C22 5.34315 20.6569 4 19 4V6ZM5 4C3.34315 4 2 5.34315 2 7H4C4 6.44772 4.44772 6 5 6V4ZM16 9V15H18V9H16ZM3 16H11V14H3V16ZM10 15V19H12V15H10ZM12 5V9H14V5H12ZM13 8H7V10H13V8ZM8 9V5H6V9H8Z", + fill: color + }) + }); +} + + +window.tablerIcons = window.tablerIcons || {}; +window.tablerIcons.IconAddLink = (0, $2f2bddd7db8296ac$export$2e2bcd8739ae039); +window.tablerIcons.IconAppFeature = (0, $2ed6e80f53bbb577$export$2e2bcd8739ae039); +window.tablerIcons.IconBlockSearch = (0, $e77db804f0d51e68$export$2e2bcd8739ae039); +window.tablerIcons.IconBlock = (0, $fb0444e266164f77$export$2e2bcd8739ae039); +window.tablerIcons.IconCloudExclamation = (0, $08a8988d553c61f7$export$2e2bcd8739ae039); +window.tablerIcons.IconConnector = (0, $49e69b962236d70e$export$2e2bcd8739ae039); +window.tablerIcons.IconGroup = (0, $e30e0c04983a7679$export$2e2bcd8739ae039); +window.tablerIcons.IconHAuto = (0, $1f8342347736f9c2$export$2e2bcd8739ae039); +window.tablerIcons.IconHeadingOff = (0, $9e73d5ea1cb39667$export$2e2bcd8739ae039); +window.tablerIcons.IconInternalLink = (0, $269f902706cc17cf$export$2e2bcd8739ae039); +window.tablerIcons.IconLinkToBlock = (0, $08c0c826d7adcea7$export$2e2bcd8739ae039); +window.tablerIcons.IconLinkToPage = (0, $473249f66f6ec7ca$export$2e2bcd8739ae039); +window.tablerIcons.IconLinkToWhiteboard = (0, $80b1e4efac5516b7$export$2e2bcd8739ae039); +window.tablerIcons.IconNewBlock = (0, $b5433be7bd57c127$export$2e2bcd8739ae039); +window.tablerIcons.IconNewPage = (0, $628d33d496321a10$export$2e2bcd8739ae039); +window.tablerIcons.IconNewWhiteboardElement = (0, $b2e1c3914295adcd$export$2e2bcd8739ae039); +window.tablerIcons.IconNewWhiteboard = (0, $fae0c08bf03a03bd$export$2e2bcd8739ae039); +window.tablerIcons.IconObjectCompact = (0, $2c448c2675ac8a8d$export$2e2bcd8739ae039); +window.tablerIcons.IconObjectExpanded = (0, $16f3c278b0e156ce$export$2e2bcd8739ae039); +window.tablerIcons.IconOpenAsPage = (0, $cc6b6f913b94a64c$export$2e2bcd8739ae039); +window.tablerIcons.IconPageSearch = (0, $824147aa23832e9d$export$2e2bcd8739ae039); +window.tablerIcons.IconPage = (0, $f4f952ef4eef055c$export$2e2bcd8739ae039); +window.tablerIcons.IconReferencesHide = (0, $8ce7267a82eb191c$export$2e2bcd8739ae039); +window.tablerIcons.IconReferencesShow = (0, $4742a6ccb1487a9b$export$2e2bcd8739ae039); +window.tablerIcons.IconSelectCursor = (0, $65dd8c350aa54786$export$2e2bcd8739ae039); +window.tablerIcons.IconText = (0, $d012c8b184d736e2$export$2e2bcd8739ae039); +window.tablerIcons.IconUngroup = (0, $a0a0d0752878ab4c$export$2e2bcd8739ae039); +window.tablerIcons.IconWhiteboardElement = (0, $6b53ec262a2764f5$export$2e2bcd8739ae039); +window.tablerIcons.IconWhiteboardSearch = (0, $6a588b38b4591064$export$2e2bcd8739ae039); +window.tablerIcons.IconWhiteboard = (0, $fb98c9f3ef9a367b$export$2e2bcd8739ae039); + + diff --git a/src/main/frontend/components/settings.cljs b/src/main/frontend/components/settings.cljs index cddfd1b6f5..294947e25f 100644 --- a/src/main/frontend/components/settings.cljs +++ b/src/main/frontend/components/settings.cljs @@ -836,7 +836,7 @@ ;; [:assets "assets" (t :settings-page/tab-assets) (ui/icon "box")]) [:advanced "advanced" (t :settings-page/tab-advanced) (ui/icon "bulb")] - [:features "features" (t :settings-page/tab-features) (ui/icon "square-asterisk")] + [:features "features" (t :settings-page/tab-features) (ui/icon "app-feature")] (when plugins-of-settings [:plugins-setting "plugins" (t :settings-of-plugins) (ui/icon "puzzle")])]] From c6c58a025dd8bcc39fab1640571cd47c1f2b2da3 Mon Sep 17 00:00:00 2001 From: charlie Date: Sun, 7 May 2023 11:13:57 +0800 Subject: [PATCH 44/81] refactor: react components of the tabler extension icons --- resources/js/tabler.ext.js | 808 +------------------------------------ 1 file changed, 11 insertions(+), 797 deletions(-) diff --git a/resources/js/tabler.ext.js b/resources/js/tabler.ext.js index d44fef9166..a6f092299d 100644 --- a/resources/js/tabler.ext.js +++ b/resources/js/tabler.ext.js @@ -1,797 +1,11 @@ -const $9c08ab62231cd969$export$34b9dba7ce09269b = React.createElement; -const $9c08ab62231cd969$export$25062201e9e25d76 = React.createElement; - - -var $cdf24df9d8a2d360$exports = {}; -$cdf24df9d8a2d360$exports = React; - - -function $2f2bddd7db8296ac$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtAddLink", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M12.2933 4.29278C13.1438 3.4422 14.2975 2.96436 15.5004 2.96436C16.7033 2.96436 17.8569 3.4422 18.7075 4.29278C19.5581 5.14336 20.0359 6.29699 20.0359 7.49989C20.0359 8.70279 19.5581 9.85642 18.7075 10.707L14.7109 14.7036C14.2927 15.1294 13.7939 15.4678 13.2436 15.699C12.6917 15.9309 12.099 16.0504 11.5004 16.0504C10.9017 16.0504 10.309 15.9309 9.7571 15.699C9.20517 15.4671 8.70507 15.1274 8.28608 14.6997C7.89956 14.3053 7.90602 13.6721 8.30051 13.2856C8.695 12.8991 9.32813 12.9055 9.71465 13.3C9.94742 13.5376 10.2253 13.7263 10.5319 13.8552C10.8385 13.984 11.1678 14.0504 11.5004 14.0504C11.833 14.0504 12.1622 13.984 12.4688 13.8552C12.7755 13.7263 13.0533 13.5376 13.2861 13.3L13.2932 13.2927L13.2933 13.2928L17.2933 9.29278C17.7688 8.81728 18.0359 8.17235 18.0359 7.49989C18.0359 6.82742 17.7688 6.1825 17.2933 5.707C16.8178 5.23149 16.1728 4.96436 15.5004 4.96436C14.8279 4.96436 14.183 5.23149 13.7075 5.707L13.2075 6.207C12.8169 6.59752 12.1838 6.59752 11.7933 6.207C11.4027 5.81647 11.4027 5.18331 11.7933 4.79278L12.2933 4.29278ZM8.75711 8.30085C9.30904 8.06892 9.9017 7.94946 10.5004 7.94946C11.0991 7.94946 11.6917 8.06892 12.2436 8.30085C12.7956 8.53277 13.2957 8.87249 13.7147 9.30012C14.1012 9.69461 14.0947 10.3277 13.7002 10.7143C13.3057 11.1008 12.6726 11.0943 12.2861 10.6998C12.0533 10.4623 11.7755 10.2735 11.4689 10.1447C11.1622 10.0158 10.833 9.94946 10.5004 9.94946C10.1678 9.94946 9.83853 10.0158 9.5319 10.1447C9.22527 10.2735 8.94743 10.4623 8.71466 10.6998L8.70752 10.7071L8.70748 10.7071L4.70748 14.7071C4.23198 15.1826 3.96484 15.8275 3.96484 16.5C3.96484 17.1724 4.23198 17.8174 4.70748 18.2929C5.18299 18.7684 5.82791 19.0355 6.50038 19.0355C7.17284 19.0355 7.81777 18.7684 8.29327 18.2929L8.79327 17.7929C9.18379 17.4023 9.81696 17.4023 10.2075 17.7929C10.598 18.1834 10.598 18.8166 10.2075 19.2071L9.70748 19.7071C8.85691 20.5577 7.70328 21.0355 6.50038 21.0355C5.29748 21.0355 4.14385 20.5577 3.29327 19.7071C2.44269 18.8565 1.96484 17.7029 1.96484 16.5C1.96484 15.2971 2.44269 14.1434 3.29327 13.2929L7.28985 9.29629C7.70807 8.87046 8.20683 8.53208 8.75711 8.30085ZM19.0005 14C19.5528 14 20.0005 14.4477 20.0005 15V17H22.0005C22.5528 17 23.0005 17.4477 23.0005 18C23.0005 18.5523 22.5528 19 22.0005 19H20.0005V21C20.0005 21.5523 19.5528 22 19.0005 22C18.4482 22 18.0005 21.5523 18.0005 21V19H16.0005C15.4482 19 15.0005 18.5523 15.0005 18C15.0005 17.4477 15.4482 17 16.0005 17H18.0005V15C18.0005 14.4477 18.4482 14 19.0005 14Z", - fill: color - }) - }); -} - - - - -function $2ed6e80f53bbb577$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$25062201e9e25d76)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtAppFeature", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: [ - /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M2 7C2 5.34315 3.34315 4 5 4H19C20.6569 4 22 5.34315 22 7V17C22 18.6569 20.6569 20 19 20H15.0209C15.0064 20.0003 14.992 20.0003 14.9776 20H9.02243C9.00802 20.0003 8.99357 20.0003 8.97908 20H5C3.34315 20 2 18.6569 2 17V7ZM13.7192 18L13.5299 17.2425C13.4447 16.9018 13.5445 16.5413 13.7929 16.2929L14.8787 15.2071L13.3586 14.9899C13.0337 14.9435 12.7523 14.7407 12.6056 14.4472L12 13.2361L11.3944 14.4472C11.2477 14.7407 10.9663 14.9435 10.6414 14.9899L9.12132 15.2071L10.2071 16.2929C10.4555 16.5413 10.5553 16.9018 10.4701 17.2425L10.2808 18H13.7192ZM15.7808 18H19C19.5523 18 20 17.5523 20 17V7C20 6.44772 19.5523 6 19 6H5C4.44772 6 4 6.44772 4 7V17C4 17.5523 4.44772 18 5 18H8.21922L8.39254 17.3067L6.29289 15.2071C6.02506 14.9393 5.93154 14.5431 6.05132 14.1838C6.17109 13.8244 6.48361 13.5636 6.85858 13.5101L9.83989 13.0841L11.1056 10.5528C11.275 10.214 11.6212 10 12 10C12.3788 10 12.725 10.214 12.8944 10.5528L14.1601 13.0841L17.1414 13.5101C17.5164 13.5636 17.8289 13.8244 17.9487 14.1838C18.0685 14.5431 17.9749 14.9393 17.7071 15.2071L15.6075 17.3067L15.7808 18Z", - fill: color - }), - /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - d: "M6 6.99C6.55228 6.99 7 7.43771 7 7.99V8C7 8.55229 6.55228 9 6 9C5.44772 9 5 8.55229 5 8V7.99C5 7.43771 5.44772 6.99 6 6.99Z", - fill: color - }), - /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - d: "M9 6.99C9.55228 6.99 10 7.43771 10 7.99V8C10 8.55228 9.55228 9 9 9C8.44772 9 8 8.55228 8 8V7.99C8 7.43771 8.44772 6.99 9 6.99Z", - fill: color - }) - ] - }); -} - - - - -function $e77db804f0d51e68$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtBlockSearch", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H14C14.5523 12 15 12.4477 15 13C15 13.5523 14.5523 14 14 14H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z", - fill: color - }) - }); -} - - - - -function $fb0444e266164f77$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtBlock", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M9 10C9 9.44772 9.44772 9 10 9H22C22.5523 9 23 9.44772 23 10V14C23 14.5523 22.5523 15 22 15H10C9.44772 15 9 14.5523 9 14V10ZM11 11V13H21V11H11ZM1 12C1 10.8954 1.89543 10 3 10C4.10457 10 5 10.8954 5 12C5 13.1046 4.10457 14 3 14C1.89543 14 1 13.1046 1 12Z", - fill: color - }) - }); -} - - - - -function $08a8988d553c61f7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtCloudExclamation", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M13.4366 6.03387C12.8308 5.92373 12.2062 5.92205 11.5997 6.02894C10.9931 6.13582 10.4204 6.34848 9.91384 6.65116C8.89016 7.26279 8.20994 8.19494 7.98007 9.21902C7.87759 9.67556 7.47225 10 7.00435 10C6.00786 10 5.06063 10.3791 4.36896 11.0407C3.6788 11.7008 3.2998 12.5864 3.2998 13.5C3.2998 14.4136 3.6788 15.2992 4.36896 15.9593C5.06063 16.6209 6.00786 17 7.00435 17H8C8.55228 17 9 17.4477 9 18C9 18.5523 8.55228 19 8 19H7.00435C5.5054 19 4.05939 18.4308 2.98651 17.4046C1.91213 16.3769 1.2998 14.9734 1.2998 13.5C1.2998 12.0266 1.91213 10.6231 2.98651 9.59538C3.87696 8.74365 5.02444 8.20677 6.24589 8.04882C6.72397 6.76252 7.65926 5.66843 8.88803 4.93427C9.60923 4.50337 10.4128 4.20727 11.2526 4.05929C12.0923 3.91131 12.9556 3.91362 13.7943 4.06613C14.6332 4.21864 15.4349 4.5191 16.1534 4.95398C16.8721 5.38893 17.4955 5.95128 17.9839 6.61332C18.4724 7.27568 18.8155 8.02416 18.988 8.817C19.0731 9.20796 19.1156 9.60469 19.1155 10.0014C20.2687 10.0298 21.3686 10.5003 22.1863 11.318C23.0302 12.1619 23.5044 13.3065 23.5044 14.5C23.5044 15.6935 23.0302 16.8381 22.1863 17.682C21.3424 18.5259 20.1978 19 19.0044 19H16C15.4477 19 15 18.5523 15 18C15 17.4477 15.4477 17 16 17H19.0044C19.6674 17 20.3033 16.7366 20.7721 16.2678C21.241 15.7989 21.5044 15.163 21.5044 14.5C21.5044 13.837 21.241 13.2011 20.7721 12.7322C20.3033 12.2634 19.6674 12 19.0044 12H18.0044C17.7007 12 17.4134 11.862 17.2236 11.6249C17.0339 11.3878 16.9621 11.0773 17.0286 10.781C17.1427 10.273 17.1444 9.75071 17.0337 9.24219C16.9231 8.7334 16.7009 8.24319 16.3744 7.80054C16.0476 7.35756 15.6221 6.9702 15.1178 6.66498C14.6134 6.35969 14.0423 6.144 13.4366 6.03387ZM12 14C12.5523 14 13 14.4477 13 15V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V15C11 14.4477 11.4477 14 12 14ZM12 21C12.5523 21 13 21.4477 13 22V22.01C13 22.5623 12.5523 23.01 12 23.01C11.4477 23.01 11 22.5623 11 22.01V22C11 21.4477 11.4477 21 12 21Z", - fill: color - }) - }); -} - - - - -function $49e69b962236d70e$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtConnector", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M11 5C11 4.44772 11.4477 4 12 4H19C19.5523 4 20 4.44772 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V7.41421L5.70711 19.7071C5.31658 20.0976 4.68342 20.0976 4.29289 19.7071C3.90237 19.3166 3.90237 18.6834 4.29289 18.2929L16.5858 6H12C11.4477 6 11 5.55228 11 5Z", - fill: color - }) - }); -} - - - - -function $e30e0c04983a7679$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtGroup", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M1 2C1 1.44772 1.44772 1 2 1H4C4.55228 1 5 1.44772 5 2H19C19 1.44772 19.4477 1 20 1H22C22.5523 1 23 1.44772 23 2V4C23 4.55228 22.5523 5 22 5V19C22.5523 19 23 19.4477 23 20V22C23 22.5523 22.5523 23 22 23H20C19.4477 23 19 22.5523 19 22H5C5 22.5523 4.55228 23 4 23H2C1.44772 23 1 22.5523 1 22V20C1 19.4477 1.44772 19 2 19V5C1.44772 5 1 4.55228 1 4V2ZM4 5V19C4.55228 19 5 19.4477 5 20H19C19 19.4477 19.4477 19 20 19V5C19.4477 5 19 4.55228 19 4H5C5 4.55228 4.55228 5 4 5ZM6 7C6 6.44772 6.44772 6 7 6H13C13.5523 6 14 6.44772 14 7V9H17C17.5523 9 18 9.44772 18 10V17C18 17.5523 17.5523 18 17 18H10C9.44772 18 9 17.5523 9 17V14H7C6.44772 14 6 13.5523 6 13V7ZM11 14V16H16V11H14V13C14 13.5523 13.5523 14 13 14H11ZM12 8H8V12H12V8Z", - fill: color - }) - }); -} - - - - -function $1f8342347736f9c2$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtH-auto", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M2 6C2 5.44772 2.44772 5 3 5H5C5.55228 5 6 5.44772 6 6C6 6.55228 5.55228 7 5 7V11H11V7C10.4477 7 10 6.55228 10 6C10 5.44772 10.4477 5 11 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7V17C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H11C10.4477 19 10 18.5523 10 18C10 17.4477 10.4477 17 11 17V13H5V17C5.55228 17 6 17.4477 6 18C6 18.5523 5.55228 19 5 19H3C2.44772 19 2 18.5523 2 18C2 17.4477 2.44772 17 3 17V7C2.44772 7 2 6.55228 2 6ZM19 11C18.7348 11 18.4804 11.1054 18.2929 11.2929C18.1054 11.4804 18 11.7348 18 12V14H20V12C20 11.7348 19.8946 11.4804 19.7071 11.2929C19.5196 11.1054 19.2652 11 19 11ZM22 12C22 11.2043 21.6839 10.4413 21.1213 9.87868C20.5587 9.31607 19.7957 9 19 9C18.2043 9 17.4413 9.31607 16.8787 9.87868C16.3161 10.4413 16 11.2043 16 12V18C16 18.5523 16.4477 19 17 19C17.5523 19 18 18.5523 18 18V16H20V18C20 18.5523 20.4477 19 21 19C21.5523 19 22 18.5523 22 18V12Z", - fill: color - }) - }); -} - - - - -function $9e73d5ea1cb39667$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtHeadingOff", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M2.29289 2.29289C2.68342 1.90237 3.31658 1.90237 3.70711 2.29289L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L18.5858 20H15C14.4477 20 14 19.5523 14 19C14 18.4477 14.4477 18 15 18H16V17.4142L11.5858 13H8V18H9C9.55228 18 10 18.4477 10 19C10 19.5523 9.55228 20 9 20H5C4.44772 20 4 19.5523 4 19C4 18.4477 4.44772 18 5 18H6V7.41421L2.29289 3.70711C1.90237 3.31658 1.90237 2.68342 2.29289 2.29289ZM8 9.41421V11H9.58579L8 9.41421ZM8 5C8 4.44772 8.44772 4 9 4H10C10.5523 4 11 4.44772 11 5C11 5.55228 10.5523 6 10 6H9C8.44772 6 8 5.55228 8 5ZM14 5C14 4.44772 14.4477 4 15 4H19C19.5523 4 20 4.44772 20 5C20 5.55228 19.5523 6 19 6H18V12C18 12.5523 17.5523 13 17 13C16.4477 13 16 12.5523 16 12V6H15C14.4477 6 14 5.55228 14 5Z", - fill: color - }) - }); -} - - - - -function $269f902706cc17cf$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtInternalLink", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4 6C4 4.34315 5.34315 3 7 3H18C19.6569 3 21 4.34315 21 6V17C21 18.6569 19.6569 20 18 20H11C10.4477 20 10 19.5523 10 19C10 18.4477 10.4477 18 11 18H18C18.5523 18 19 17.5523 19 17V6C19 5.44772 18.5523 5 18 5H7C6.44772 5 6 5.44772 6 6V13C6 13.5523 5.55228 14 5 14C4.44772 14 4 13.5523 4 13V6ZM8 10C8 9.44772 8.44772 9 9 9H14C14.5523 9 15 9.44772 15 10V15C15 15.5523 14.5523 16 14 16C13.4477 16 13 15.5523 13 15V12.4142L4.70711 20.7071C4.31658 21.0976 3.68342 21.0976 3.29289 20.7071C2.90237 20.3166 2.90237 19.6834 3.29289 19.2929L11.5858 11H9C8.44772 11 8 10.5523 8 10Z", - fill: color - }) - }); -} - - - - -function $08c0c826d7adcea7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtLinkToBlock", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M9 8C9 7.44772 9.44772 7 10 7H22C22.5523 7 23 7.44772 23 8V12C23 12.5523 22.5523 13 22 13C21.4477 13 21 12.5523 21 12V9H11V12C11 12.5523 10.5523 13 10 13C9.44772 13 9 12.5523 9 12V8ZM1 10C1 8.89543 1.89543 8 3 8C4.10457 8 5 8.89543 5 10C5 11.1046 4.10457 12 3 12C1.89543 12 1 11.1046 1 10ZM15.2929 11.2929C15.6834 10.9024 16.3166 10.9024 16.7071 11.2929L19.7071 14.2929C20.0976 14.6834 20.0976 15.3166 19.7071 15.7071C19.3166 16.0976 18.6834 16.0976 18.2929 15.7071L17 14.4142V17C17 18.1046 17.8954 19 19 19H23C23.5523 19 24 19.4477 24 20C24 20.5523 23.5523 21 23 21H19C16.7909 21 15 19.2091 15 17V14.4142L13.7071 15.7071C13.3166 16.0976 12.6834 16.0976 12.2929 15.7071C11.9024 15.3166 11.9024 14.6834 12.2929 14.2929L15.2929 11.2929Z", - fill: color - }) - }); -} - - - - -function $473249f66f6ec7ca$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtLinkToPage", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4 4C4 2.34315 5.34315 1 7 1H17C18.6569 1 20 2.34315 20 4V18C20 18.5523 19.5523 19 19 19C18.4477 19 18 18.5523 18 18V4C18 3.44772 17.5523 3 17 3H7C6.44772 3 6 3.44772 6 4V18C6 18.5523 5.55228 19 5 19C4.44772 19 4 18.5523 4 18V4ZM8 6C8 5.44772 8.44772 5 9 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7H9C8.44772 7 8 6.55228 8 6ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L15.7071 16.2929C16.0976 16.6834 16.0976 17.3166 15.7071 17.7071C15.3166 18.0976 14.6834 18.0976 14.2929 17.7071L13 16.4142V19C13 20.1046 13.8954 21 15 21H19C19.5523 21 20 21.4477 20 22C20 22.5523 19.5523 23 19 23H15C12.7909 23 11 21.2091 11 19L11 16.4142L9.70711 17.7071C9.31658 18.0976 8.68342 18.0976 8.29289 17.7071C7.90237 17.3166 7.90237 16.6834 8.29289 16.2929L11.2929 13.2929Z", - fill: color - }) - }); -} - - - - -function $80b1e4efac5516b7$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtLinkToWhiteboard", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M2 5C2 3.34315 3.34315 2 5 2H19C20.6569 2 22 3.34315 22 5V15C22 16.6569 20.6569 18 19 18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19C19.5523 16 20 15.5523 20 15V5C20 4.44772 19.5523 4 19 4H14V7C14 7.55228 13.5523 8 13 8H7C6.44772 8 6 7.55228 6 7V4H5C4.44772 4 4 4.44772 4 5V17C4 17.5523 3.55228 18 3 18C2.44772 18 2 17.5523 2 17V5ZM8 4V6H12V4H8ZM17 6C17.5523 6 18 6.44772 18 7V13C18 13.5523 17.5523 14 17 14C16.4477 14 16 13.5523 16 13V7C16 6.44772 16.4477 6 17 6ZM9.29289 12.2929C9.68342 11.9024 10.3166 11.9024 10.7071 12.2929L13.7071 15.2929C14.0976 15.6834 14.0976 16.3166 13.7071 16.7071C13.3166 17.0976 12.6834 17.0976 12.2929 16.7071L11 15.4142V18C11 19.1046 11.8954 20 13 20H17C17.5523 20 18 20.4477 18 21C18 21.5523 17.5523 22 17 22H13C10.7909 22 9 20.2091 9 18L9 15.4142L7.70711 16.7071C7.31658 17.0976 6.68342 17.0976 6.29289 16.7071C5.90237 16.3166 5.90237 15.6834 6.29289 15.2929L9.29289 12.2929Z", - fill: color - }) - }); -} - - - - -function $b5433be7bd57c127$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtNewBlock", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H16C16.5523 12 17 12.4477 17 13C17 13.5523 16.5523 14 16 14H13V16C13.5523 16 14 16.4477 14 17C14 17.5523 13.5523 18 13 18H12C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM20 13C20.5523 13 21 13.4477 21 14V16H23C23.5523 16 24 16.4477 24 17C24 17.5523 23.5523 18 23 18H21V20C21 20.5523 20.5523 21 20 21C19.4477 21 19 20.5523 19 20V18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19V14C19 13.4477 19.4477 13 20 13Z", - fill: color - }) - }); -} - - - - -function $628d33d496321a10$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtNewPage", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V5C18 4.44772 17.5523 4 17 4H7C6.44772 4 6 4.44772 6 5V17C6 17.5523 6.44772 18 7 18H12C12.5523 18 13 18.4477 13 19C13 19.5523 12.5523 20 12 20H7C5.34315 20 4 18.6569 4 17V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7ZM19 15C19.5523 15 20 15.4477 20 16V18H22C22.5523 18 23 18.4477 23 19C23 19.5523 22.5523 20 22 20H20V22C20 22.5523 19.5523 23 19 23C18.4477 23 18 22.5523 18 22V20H16C15.4477 20 15 19.5523 15 19C15 18.4477 15.4477 18 16 18H18V16C18 15.4477 18.4477 15 19 15Z", - fill: color - }) - }); -} - - - - -function $b2e1c3914295adcd$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtNewWhiteboardElement", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M6 4C5.44772 4 5 4.44772 5 5V6C5 6.55228 4.55228 7 4 7C3.44772 7 3 6.55228 3 6V5C3 3.34315 4.34315 2 6 2H8C8.55228 2 9 2.44772 9 3C9 3.55228 8.55228 4 8 4H6ZM15 3C15 2.44772 15.4477 2 16 2H18C19.6569 2 21 3.34315 21 5V6C21 6.55228 20.5523 7 20 7C19.4477 7 19 6.55228 19 6V5C19 4.44772 18.5523 4 18 4H16C15.4477 4 15 3.55228 15 3ZM7 9C7 8.44772 7.44772 8 8 8H16C16.5523 8 17 8.44772 17 9V13C17 13.5523 16.5523 14 16 14H8C7.44772 14 7 13.5523 7 13V9ZM9 10V12H15V10H9ZM4 15C4.55228 15 5 15.4477 5 16V17C5 17.5523 5.44772 18 6 18H8C8.55228 18 9 18.4477 9 19C9 19.5523 8.55228 20 8 20H6C4.34315 20 3 18.6569 3 17V16C3 15.4477 3.44772 15 4 15ZM20 15C20.5523 15 21 15.4477 21 16V18H23C23.5523 18 24 18.4477 24 19C24 19.5523 23.5523 20 23 20H21V22C21 22.5523 20.5523 23 20 23C19.4477 23 19 22.5523 19 22V20H17C16.4477 20 16 19.5523 16 19C16 18.4477 16.4477 18 17 18H19V16C19 15.4477 19.4477 15 20 15Z", - fill: color - }) - }); -} - - - - -function $fae0c08bf03a03bd$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtNewWhiteboard", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H13C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM20 14C20.5523 14 21 14.4477 21 15V17H23C23.5523 17 24 17.4477 24 18C24 18.5523 23.5523 19 23 19H21V21C21 21.5523 20.5523 22 20 22C19.4477 22 19 21.5523 19 21V19H17C16.4477 19 16 18.5523 16 18C16 17.4477 16.4477 17 17 17H19V15C19 14.4477 19.4477 14 20 14Z", - fill: color - }) - }); -} - - - - -function $2c448c2675ac8a8d$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtObjectCompact", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V9C21 9.55228 20.5523 10 20 10H18C17.4477 10 17 9.55228 17 9C17 8.44772 17.4477 8 18 8H19V4H5V8H6C6.55228 8 7 8.44772 7 9C7 9.55228 6.55228 10 6 10H4C3.44772 10 3 9.55228 3 9V3ZM11.2929 7.29289C11.6834 6.90237 12.3166 6.90237 12.7071 7.29289L16.7071 11.2929C17.0976 11.6834 17.0976 12.3166 16.7071 12.7071C16.3166 13.0976 15.6834 13.0976 15.2929 12.7071L13 10.4142V19C13 19.5523 12.5523 20 12 20C11.4477 20 11 19.5523 11 19V10.4142L8.70711 12.7071C8.31658 13.0976 7.68342 13.0976 7.29289 12.7071C6.90237 12.3166 6.90237 11.6834 7.29289 11.2929L11.2929 7.29289Z", - fill: color - }) - }); -} - - - - -function $16f3c278b0e156ce$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtObjectExpanded", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V3ZM5 4V8H8C8.55228 8 9 8.44772 9 9C9 9.55228 8.55228 10 8 10H5V20H19V10H16C15.4477 10 15 9.55228 15 9C15 8.44772 15.4477 8 16 8H19V4H5ZM12 6C12.5523 6 13 6.44772 13 7V14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071C12.3166 18.0976 11.6834 18.0976 11.2929 17.7071L7.29289 13.7071C6.90237 13.3166 6.90237 12.6834 7.29289 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858V7C11 6.44772 11.4477 6 12 6Z", - fill: color - }) - }); -} - - - - -function $cc6b6f913b94a64c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtOpenAsPage", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V18C20 19.6569 18.6569 21 17 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H17C17.5523 19 18 18.5523 18 18V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L14.7071 15.2929C15.0976 15.6834 15.0976 16.3166 14.7071 16.7071C14.3166 17.0976 13.6834 17.0976 13.2929 16.7071L13 16.4142V23C13 23.5523 12.5523 24 12 24C11.4477 24 11 23.5523 11 23L11 16.4142L10.7071 16.7071C10.3166 17.0976 9.68342 17.0976 9.29289 16.7071C8.90237 16.3166 8.90237 15.6834 9.29289 15.2929L11.2929 13.2929Z", - fill: color - }) - }); -} - - - - -function $824147aa23832e9d$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtPageSearch", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V11C20 11.5523 19.5523 12 19 12C18.4477 12 18 11.5523 18 11V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H10C10.5523 19 11 19.4477 11 20C11 20.5523 10.5523 21 10 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM16.5 16C15.6716 16 15 16.6716 15 17.5C15 18.3284 15.6716 19 16.5 19C17.3284 19 18 18.3284 18 17.5C18 16.6716 17.3284 16 16.5 16ZM13 17.5C13 15.567 14.567 14 16.5 14C18.433 14 20 15.567 20 17.5C20 18.1028 19.8476 18.6699 19.5793 19.1651L21.7071 21.2929C22.0976 21.6834 22.0976 22.3166 21.7071 22.7071C21.3166 23.0976 20.6834 23.0976 20.2929 22.7071L18.1651 20.5793C17.6699 20.8476 17.1028 21 16.5 21C14.567 21 13 19.433 13 17.5Z", - fill: color - }) - }); -} - - - - -function $f4f952ef4eef055c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtPage", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M7 4C6.44772 4 6 4.44772 6 5V19C6 19.5523 6.44771 20 7 20H17C17.5523 20 18 19.5523 18 19V5C18 4.44772 17.5523 4 17 4H7ZM4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V19C20 20.6569 18.6569 22 17 22H7C5.34315 22 4 20.6569 4 19V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7Z", - fill: color - }) - }); -} - - - - -function $8ce7267a82eb191c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtReferencesHide", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M11.2929 2.29289C11.6834 1.90237 12.3166 1.90237 12.7071 2.29289L14.7071 4.29289C15.0976 4.68342 15.0976 5.31658 14.7071 5.70711C14.3166 6.09763 13.6834 6.09763 13.2929 5.70711L12 4.41421L10.7071 5.70711C10.3166 6.09763 9.68342 6.09763 9.29289 5.70711C8.90237 5.31658 8.90237 4.68342 9.29289 4.29289L11.2929 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z", - fill: color - }) - }); -} - - - - -function $4742a6ccb1487a9b$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtReferencesShow", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M9.29289 2.29289C9.68342 1.90237 10.3166 1.90237 10.7071 2.29289L12 3.58579L13.2929 2.29289C13.6834 1.90237 14.3166 1.90237 14.7071 2.29289C15.0976 2.68342 15.0976 3.31658 14.7071 3.70711L12.7071 5.70711C12.3166 6.09763 11.6834 6.09763 11.2929 5.70711L9.29289 3.70711C8.90237 3.31658 8.90237 2.68342 9.29289 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z", - fill: color - }) - }); -} - - - - -function $65dd8c350aa54786$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtSelectCursor", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M4.29292 4.29289C4.56075 4.02506 4.95692 3.93154 5.31625 4.05132L19.3163 8.71798C19.7 8.84589 19.9688 9.19233 19.9975 9.59578C20.0262 9.99922 19.809 10.3802 19.4472 10.5611L16.6659 11.9518L19.4483 14.7343C19.8389 15.1248 19.8389 15.758 19.4483 16.1485L16.1485 19.4483C15.758 19.8388 15.1248 19.8388 14.7343 19.4483L11.9518 16.6658L10.5611 19.4472C10.3802 19.809 9.99925 20.0262 9.5958 19.9975C9.19236 19.9688 8.84591 19.6999 8.71801 19.3162L4.05134 5.31623C3.93157 4.95689 4.02509 4.56073 4.29292 4.29289ZM6.58117 6.58114L9.85194 16.3934L10.7834 14.5305C10.9272 14.2429 11.2004 14.0421 11.5177 13.9906C11.835 13.9391 12.1577 14.0433 12.385 14.2706L15.4414 17.327L17.327 15.4414L14.2706 12.3849C14.0433 12.1576 13.9391 11.8349 13.9906 11.5177C14.0421 11.2004 14.243 10.9272 14.5305 10.7834L16.3935 9.85191L6.58117 6.58114Z", - fill: color - }) - }); -} - - - - -function $d012c8b184d736e2$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtText", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V7C19 7.55228 18.5523 8 18 8C17.4477 8 17 7.55228 17 7V6H13V18H14C14.5523 18 15 18.4477 15 19C15 19.5523 14.5523 20 14 20H10C9.44772 20 9 19.5523 9 19C9 18.4477 9.44772 18 10 18H11V6H7V7C7 7.55228 6.55228 8 6 8C5.44772 8 5 7.55228 5 7V5Z", - fill: color - }) - }); -} - - - - -function $a0a0d0752878ab4c$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtUngroup", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M2 3C2 2.44772 2.44772 2 3 2H5C5.55228 2 6 2.44772 6 3H12C12 2.44772 12.4477 2 13 2H15C15.5523 2 16 2.44772 16 3V5C16 5.55228 15.5523 6 15 6V8H18C18 7.44772 18.4477 7 19 7H21C21.5523 7 22 7.44772 22 8V10C22 10.5523 21.5523 11 21 11V18C21.5523 18 22 18.4477 22 19V21C22 21.5523 21.5523 22 21 22H19C18.4477 22 18 21.5523 18 21H11C11 21.5523 10.5523 22 10 22H8C7.44772 22 7 21.5523 7 21V19C7 18.4477 7.44772 18 8 18V15H6C6 15.5523 5.55228 16 5 16H3C2.44772 16 2 15.5523 2 15V13C2 12.4477 2.44772 12 3 12V6C2.44772 6 2 5.55228 2 5V3ZM5 6V12C5.55228 12 6 12.4477 6 13H12C12 12.4477 12.4477 12 13 12V6C12.4477 6 12 5.55228 12 5H6C6 5.55228 5.55228 6 5 6ZM15 12V10H18C18 10.5523 18.4477 11 19 11V18C18.4477 18 18 18.4477 18 19H11C11 18.4477 10.5523 18 10 18V15H12C12 15.5523 12.4477 16 13 16H15C15.5523 16 16 15.5523 16 15V13C16 12.4477 15.5523 12 15 12Z", - fill: color - }) - }); -} - - - - -function $6b53ec262a2764f5$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtWhiteboardElement", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M6 5C5.44772 5 5 5.44772 5 6V7C5 7.55228 4.55228 8 4 8C3.44772 8 3 7.55228 3 7V6C3 4.34315 4.34315 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6ZM15 4C15 3.44772 15.4477 3 16 3H18C19.6569 3 21 4.34315 21 6V7C21 7.55228 20.5523 8 20 8C19.4477 8 19 7.55228 19 7V6C19 5.44772 18.5523 5 18 5H16C15.4477 5 15 4.55228 15 4ZM7 10C7 9.44772 7.44772 9 8 9H16C16.5523 9 17 9.44772 17 10V14C17 14.5523 16.5523 15 16 15H8C7.44772 15 7 14.5523 7 14V10ZM9 11V13H15V11H9ZM4 16C4.55228 16 5 16.4477 5 17V18C5 18.5523 5.44772 19 6 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H6C4.34315 21 3 19.6569 3 18V17C3 16.4477 3.44772 16 4 16ZM20 16C20.5523 16 21 16.4477 21 17V18C21 19.6569 19.6569 21 18 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H18C18.5523 19 19 18.5523 19 18V17C19 16.4477 19.4477 16 20 16Z", - fill: color - }) - }); -} - - - - -function $6a588b38b4591064$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtWhiteboardSearch", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - fillRule: "evenodd", - clipRule: "evenodd", - d: "M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H12C12.5523 17 13 17.4477 13 18C13 18.5523 12.5523 19 12 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z", - fill: color - }) - }); -} - - - - -function $fb98c9f3ef9a367b$export$2e2bcd8739ae039({ size: size = 24 , color: color = "currentColor" , stroke: stroke = 0 , ...rest }) { - return /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("svg", { - width: size, - height: size, - viewBox: "0 0 24 24", - fill: "none", - strokeWidth: stroke, - stroke: color, - strokeLinecap: "round", - strokeLinejoin: "round", - class: "icon iconTabler iconTablerExtWhiteboard", - ...rest, - xmlns: "http://www.w3.org/2000/svg", - children: /*#__PURE__*/ (0, $9c08ab62231cd969$export$34b9dba7ce09269b)("path", { - d: "M18 9C18 8.44772 17.5523 8 17 8C16.4477 8 16 8.44772 16 9H18ZM16 15C16 15.5523 16.4477 16 17 16C17.5523 16 18 15.5523 18 15H16ZM3 14C2.44772 14 2 14.4477 2 15C2 15.5523 2.44772 16 3 16V14ZM11 15H12C12 14.4477 11.5523 14 11 14V15ZM10 19C10 19.5523 10.4477 20 11 20C11.5523 20 12 19.5523 12 19H10ZM14 5C14 4.44772 13.5523 4 13 4C12.4477 4 12 4.44772 12 5H14ZM13 9V10C13.5523 10 14 9.55228 14 9H13ZM7 9H6C6 9.55228 6.44772 10 7 10V9ZM8 5C8 4.44772 7.55228 4 7 4C6.44772 4 6 4.44772 6 5H8ZM5 6H19V4H5V6ZM20 7V17H22V7H20ZM19 18H5V20H19V18ZM4 17V7H2V17H4ZM5 18C4.44772 18 4 17.5523 4 17H2C2 18.6569 3.34315 20 5 20V18ZM20 17C20 17.5523 19.5523 18 19 18V20C20.6569 20 22 18.6569 22 17H20ZM19 6C19.5523 6 20 6.44772 20 7H22C22 5.34315 20.6569 4 19 4V6ZM5 4C3.34315 4 2 5.34315 2 7H4C4 6.44772 4.44772 6 5 6V4ZM16 9V15H18V9H16ZM3 16H11V14H3V16ZM10 15V19H12V15H10ZM12 5V9H14V5H12ZM13 8H7V10H13V8ZM8 9V5H6V9H8Z", - fill: color - }) - }); -} - - -window.tablerIcons = window.tablerIcons || {}; -window.tablerIcons.IconAddLink = (0, $2f2bddd7db8296ac$export$2e2bcd8739ae039); -window.tablerIcons.IconAppFeature = (0, $2ed6e80f53bbb577$export$2e2bcd8739ae039); -window.tablerIcons.IconBlockSearch = (0, $e77db804f0d51e68$export$2e2bcd8739ae039); -window.tablerIcons.IconBlock = (0, $fb0444e266164f77$export$2e2bcd8739ae039); -window.tablerIcons.IconCloudExclamation = (0, $08a8988d553c61f7$export$2e2bcd8739ae039); -window.tablerIcons.IconConnector = (0, $49e69b962236d70e$export$2e2bcd8739ae039); -window.tablerIcons.IconGroup = (0, $e30e0c04983a7679$export$2e2bcd8739ae039); -window.tablerIcons.IconHAuto = (0, $1f8342347736f9c2$export$2e2bcd8739ae039); -window.tablerIcons.IconHeadingOff = (0, $9e73d5ea1cb39667$export$2e2bcd8739ae039); -window.tablerIcons.IconInternalLink = (0, $269f902706cc17cf$export$2e2bcd8739ae039); -window.tablerIcons.IconLinkToBlock = (0, $08c0c826d7adcea7$export$2e2bcd8739ae039); -window.tablerIcons.IconLinkToPage = (0, $473249f66f6ec7ca$export$2e2bcd8739ae039); -window.tablerIcons.IconLinkToWhiteboard = (0, $80b1e4efac5516b7$export$2e2bcd8739ae039); -window.tablerIcons.IconNewBlock = (0, $b5433be7bd57c127$export$2e2bcd8739ae039); -window.tablerIcons.IconNewPage = (0, $628d33d496321a10$export$2e2bcd8739ae039); -window.tablerIcons.IconNewWhiteboardElement = (0, $b2e1c3914295adcd$export$2e2bcd8739ae039); -window.tablerIcons.IconNewWhiteboard = (0, $fae0c08bf03a03bd$export$2e2bcd8739ae039); -window.tablerIcons.IconObjectCompact = (0, $2c448c2675ac8a8d$export$2e2bcd8739ae039); -window.tablerIcons.IconObjectExpanded = (0, $16f3c278b0e156ce$export$2e2bcd8739ae039); -window.tablerIcons.IconOpenAsPage = (0, $cc6b6f913b94a64c$export$2e2bcd8739ae039); -window.tablerIcons.IconPageSearch = (0, $824147aa23832e9d$export$2e2bcd8739ae039); -window.tablerIcons.IconPage = (0, $f4f952ef4eef055c$export$2e2bcd8739ae039); -window.tablerIcons.IconReferencesHide = (0, $8ce7267a82eb191c$export$2e2bcd8739ae039); -window.tablerIcons.IconReferencesShow = (0, $4742a6ccb1487a9b$export$2e2bcd8739ae039); -window.tablerIcons.IconSelectCursor = (0, $65dd8c350aa54786$export$2e2bcd8739ae039); -window.tablerIcons.IconText = (0, $d012c8b184d736e2$export$2e2bcd8739ae039); -window.tablerIcons.IconUngroup = (0, $a0a0d0752878ab4c$export$2e2bcd8739ae039); -window.tablerIcons.IconWhiteboardElement = (0, $6b53ec262a2764f5$export$2e2bcd8739ae039); -window.tablerIcons.IconWhiteboardSearch = (0, $6a588b38b4591064$export$2e2bcd8739ae039); -window.tablerIcons.IconWhiteboard = (0, $fb98c9f3ef9a367b$export$2e2bcd8739ae039); - - +(()=>{function e(e,o,n,C){Object.defineProperty(e,o,{get:n,set:C,enumerable:!0,configurable:!0})}var o="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},n={},C={},r=o.parcelRequiree92c;null==r&&((r=function(e){if(e in n)return n[e].exports;if(e in C){var o=C[e];delete C[e];var r={id:e,exports:{}};return n[e]=r,o.call(r.exports,r,r.exports),r.exports}var i=new Error("Cannot find module '"+e+"'");throw i.code="MODULE_NOT_FOUND",i}).register=function(e,o){C[e]=o},o.parcelRequiree92c=r),r.register("9Hk4c",(function(o,n){ + /** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + var C,i,t;e(o.exports,"Fragment",(()=>C),(e=>C=e)),e(o.exports,"jsx",(()=>i),(e=>i=e)),e(o.exports,"jsxs",(()=>t),(e=>t=e));var l=r("6yBNn"),s=Symbol.for("react.element"),c=Symbol.for("react.fragment"),d=Object.prototype.hasOwnProperty,a=l.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,H={key:!0,ref:!0,__self:!0,__source:!0};function w(e,o,n){var C,r={},i=null,t=null;for(C in void 0!==n&&(i=""+n),void 0!==o.key&&(i=""+o.key),void 0!==o.ref&&(t=o.ref),o)d.call(o,C)&&!H.hasOwnProperty(C)&&(r[C]=o[C]);if(e&&e.defaultProps)for(C in o=e.defaultProps)void 0===r[C]&&(r[C]=o[C]);return{$$typeof:s,type:e,key:i,ref:t,props:r,_owner:a.current}}C=c,i=w,t=w})),r.register("6yBNn",(function(e,o){e.exports=React}));var i;i=r("9Hk4c"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),r("6yBNn"),window.tablerIcons=window.tablerIcons||{},window.tablerIcons.IconAddLink=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtAddLink",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M12.2933 4.29278C13.1438 3.4422 14.2975 2.96436 15.5004 2.96436C16.7033 2.96436 17.8569 3.4422 18.7075 4.29278C19.5581 5.14336 20.0359 6.29699 20.0359 7.49989C20.0359 8.70279 19.5581 9.85642 18.7075 10.707L14.7109 14.7036C14.2927 15.1294 13.7939 15.4678 13.2436 15.699C12.6917 15.9309 12.099 16.0504 11.5004 16.0504C10.9017 16.0504 10.309 15.9309 9.7571 15.699C9.20517 15.4671 8.70507 15.1274 8.28608 14.6997C7.89956 14.3053 7.90602 13.6721 8.30051 13.2856C8.695 12.8991 9.32813 12.9055 9.71465 13.3C9.94742 13.5376 10.2253 13.7263 10.5319 13.8552C10.8385 13.984 11.1678 14.0504 11.5004 14.0504C11.833 14.0504 12.1622 13.984 12.4688 13.8552C12.7755 13.7263 13.0533 13.5376 13.2861 13.3L13.2932 13.2927L13.2933 13.2928L17.2933 9.29278C17.7688 8.81728 18.0359 8.17235 18.0359 7.49989C18.0359 6.82742 17.7688 6.1825 17.2933 5.707C16.8178 5.23149 16.1728 4.96436 15.5004 4.96436C14.8279 4.96436 14.183 5.23149 13.7075 5.707L13.2075 6.207C12.8169 6.59752 12.1838 6.59752 11.7933 6.207C11.4027 5.81647 11.4027 5.18331 11.7933 4.79278L12.2933 4.29278ZM8.75711 8.30085C9.30904 8.06892 9.9017 7.94946 10.5004 7.94946C11.0991 7.94946 11.6917 8.06892 12.2436 8.30085C12.7956 8.53277 13.2957 8.87249 13.7147 9.30012C14.1012 9.69461 14.0947 10.3277 13.7002 10.7143C13.3057 11.1008 12.6726 11.0943 12.2861 10.6998C12.0533 10.4623 11.7755 10.2735 11.4689 10.1447C11.1622 10.0158 10.833 9.94946 10.5004 9.94946C10.1678 9.94946 9.83853 10.0158 9.5319 10.1447C9.22527 10.2735 8.94743 10.4623 8.71466 10.6998L8.70752 10.7071L8.70748 10.7071L4.70748 14.7071C4.23198 15.1826 3.96484 15.8275 3.96484 16.5C3.96484 17.1724 4.23198 17.8174 4.70748 18.2929C5.18299 18.7684 5.82791 19.0355 6.50038 19.0355C7.17284 19.0355 7.81777 18.7684 8.29327 18.2929L8.79327 17.7929C9.18379 17.4023 9.81696 17.4023 10.2075 17.7929C10.598 18.1834 10.598 18.8166 10.2075 19.2071L9.70748 19.7071C8.85691 20.5577 7.70328 21.0355 6.50038 21.0355C5.29748 21.0355 4.14385 20.5577 3.29327 19.7071C2.44269 18.8565 1.96484 17.7029 1.96484 16.5C1.96484 15.2971 2.44269 14.1434 3.29327 13.2929L7.28985 9.29629C7.70807 8.87046 8.20683 8.53208 8.75711 8.30085ZM19.0005 14C19.5528 14 20.0005 14.4477 20.0005 15V17H22.0005C22.5528 17 23.0005 17.4477 23.0005 18C23.0005 18.5523 22.5528 19 22.0005 19H20.0005V21C20.0005 21.5523 19.5528 22 19.0005 22C18.4482 22 18.0005 21.5523 18.0005 21V19H16.0005C15.4482 19 15.0005 18.5523 15.0005 18C15.0005 17.4477 15.4482 17 16.0005 17H18.0005V15C18.0005 14.4477 18.4482 14 19.0005 14Z",fill:o})})},window.tablerIcons.IconAppFeature=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsxs)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtAppFeature",...C,xmlns:"http://www.w3.org/2000/svg",children:[(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2 7C2 5.34315 3.34315 4 5 4H19C20.6569 4 22 5.34315 22 7V17C22 18.6569 20.6569 20 19 20H15.0209C15.0064 20.0003 14.992 20.0003 14.9776 20H9.02243C9.00802 20.0003 8.99357 20.0003 8.97908 20H5C3.34315 20 2 18.6569 2 17V7ZM13.7192 18L13.5299 17.2425C13.4447 16.9018 13.5445 16.5413 13.7929 16.2929L14.8787 15.2071L13.3586 14.9899C13.0337 14.9435 12.7523 14.7407 12.6056 14.4472L12 13.2361L11.3944 14.4472C11.2477 14.7407 10.9663 14.9435 10.6414 14.9899L9.12132 15.2071L10.2071 16.2929C10.4555 16.5413 10.5553 16.9018 10.4701 17.2425L10.2808 18H13.7192ZM15.7808 18H19C19.5523 18 20 17.5523 20 17V7C20 6.44772 19.5523 6 19 6H5C4.44772 6 4 6.44772 4 7V17C4 17.5523 4.44772 18 5 18H8.21922L8.39254 17.3067L6.29289 15.2071C6.02506 14.9393 5.93154 14.5431 6.05132 14.1838C6.17109 13.8244 6.48361 13.5636 6.85858 13.5101L9.83989 13.0841L11.1056 10.5528C11.275 10.214 11.6212 10 12 10C12.3788 10 12.725 10.214 12.8944 10.5528L14.1601 13.0841L17.1414 13.5101C17.5164 13.5636 17.8289 13.8244 17.9487 14.1838C18.0685 14.5431 17.9749 14.9393 17.7071 15.2071L15.6075 17.3067L15.7808 18Z",fill:o}),(0,i.jsx)("path",{d:"M6 6.99C6.55228 6.99 7 7.43771 7 7.99V8C7 8.55229 6.55228 9 6 9C5.44772 9 5 8.55229 5 8V7.99C5 7.43771 5.44772 6.99 6 6.99Z",fill:o}),(0,i.jsx)("path",{d:"M9 6.99C9.55228 6.99 10 7.43771 10 7.99V8C10 8.55228 9.55228 9 9 9C8.44772 9 8 8.55228 8 8V7.99C8 7.43771 8.44772 6.99 9 6.99Z",fill:o})]})},window.tablerIcons.IconBlockSearch=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtBlockSearch",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H14C14.5523 12 15 12.4477 15 13C15 13.5523 14.5523 14 14 14H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z",fill:o})})},window.tablerIcons.IconBlock=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtBlock",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M9 10C9 9.44772 9.44772 9 10 9H22C22.5523 9 23 9.44772 23 10V14C23 14.5523 22.5523 15 22 15H10C9.44772 15 9 14.5523 9 14V10ZM11 11V13H21V11H11ZM1 12C1 10.8954 1.89543 10 3 10C4.10457 10 5 10.8954 5 12C5 13.1046 4.10457 14 3 14C1.89543 14 1 13.1046 1 12Z",fill:o})})},window.tablerIcons.IconCloudExclamation=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtCloudExclamation",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M13.4366 6.03387C12.8308 5.92373 12.2062 5.92205 11.5997 6.02894C10.9931 6.13582 10.4204 6.34848 9.91384 6.65116C8.89016 7.26279 8.20994 8.19494 7.98007 9.21902C7.87759 9.67556 7.47225 10 7.00435 10C6.00786 10 5.06063 10.3791 4.36896 11.0407C3.6788 11.7008 3.2998 12.5864 3.2998 13.5C3.2998 14.4136 3.6788 15.2992 4.36896 15.9593C5.06063 16.6209 6.00786 17 7.00435 17H8C8.55228 17 9 17.4477 9 18C9 18.5523 8.55228 19 8 19H7.00435C5.5054 19 4.05939 18.4308 2.98651 17.4046C1.91213 16.3769 1.2998 14.9734 1.2998 13.5C1.2998 12.0266 1.91213 10.6231 2.98651 9.59538C3.87696 8.74365 5.02444 8.20677 6.24589 8.04882C6.72397 6.76252 7.65926 5.66843 8.88803 4.93427C9.60923 4.50337 10.4128 4.20727 11.2526 4.05929C12.0923 3.91131 12.9556 3.91362 13.7943 4.06613C14.6332 4.21864 15.4349 4.5191 16.1534 4.95398C16.8721 5.38893 17.4955 5.95128 17.9839 6.61332C18.4724 7.27568 18.8155 8.02416 18.988 8.817C19.0731 9.20796 19.1156 9.60469 19.1155 10.0014C20.2687 10.0298 21.3686 10.5003 22.1863 11.318C23.0302 12.1619 23.5044 13.3065 23.5044 14.5C23.5044 15.6935 23.0302 16.8381 22.1863 17.682C21.3424 18.5259 20.1978 19 19.0044 19H16C15.4477 19 15 18.5523 15 18C15 17.4477 15.4477 17 16 17H19.0044C19.6674 17 20.3033 16.7366 20.7721 16.2678C21.241 15.7989 21.5044 15.163 21.5044 14.5C21.5044 13.837 21.241 13.2011 20.7721 12.7322C20.3033 12.2634 19.6674 12 19.0044 12H18.0044C17.7007 12 17.4134 11.862 17.2236 11.6249C17.0339 11.3878 16.9621 11.0773 17.0286 10.781C17.1427 10.273 17.1444 9.75071 17.0337 9.24219C16.9231 8.7334 16.7009 8.24319 16.3744 7.80054C16.0476 7.35756 15.6221 6.9702 15.1178 6.66498C14.6134 6.35969 14.0423 6.144 13.4366 6.03387ZM12 14C12.5523 14 13 14.4477 13 15V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V15C11 14.4477 11.4477 14 12 14ZM12 21C12.5523 21 13 21.4477 13 22V22.01C13 22.5623 12.5523 23.01 12 23.01C11.4477 23.01 11 22.5623 11 22.01V22C11 21.4477 11.4477 21 12 21Z",fill:o})})},window.tablerIcons.IconConnector=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtConnector",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M11 5C11 4.44772 11.4477 4 12 4H19C19.5523 4 20 4.44772 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V7.41421L5.70711 19.7071C5.31658 20.0976 4.68342 20.0976 4.29289 19.7071C3.90237 19.3166 3.90237 18.6834 4.29289 18.2929L16.5858 6H12C11.4477 6 11 5.55228 11 5Z",fill:o})})},window.tablerIcons.IconGroup=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtGroup",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M1 2C1 1.44772 1.44772 1 2 1H4C4.55228 1 5 1.44772 5 2H19C19 1.44772 19.4477 1 20 1H22C22.5523 1 23 1.44772 23 2V4C23 4.55228 22.5523 5 22 5V19C22.5523 19 23 19.4477 23 20V22C23 22.5523 22.5523 23 22 23H20C19.4477 23 19 22.5523 19 22H5C5 22.5523 4.55228 23 4 23H2C1.44772 23 1 22.5523 1 22V20C1 19.4477 1.44772 19 2 19V5C1.44772 5 1 4.55228 1 4V2ZM4 5V19C4.55228 19 5 19.4477 5 20H19C19 19.4477 19.4477 19 20 19V5C19.4477 5 19 4.55228 19 4H5C5 4.55228 4.55228 5 4 5ZM6 7C6 6.44772 6.44772 6 7 6H13C13.5523 6 14 6.44772 14 7V9H17C17.5523 9 18 9.44772 18 10V17C18 17.5523 17.5523 18 17 18H10C9.44772 18 9 17.5523 9 17V14H7C6.44772 14 6 13.5523 6 13V7ZM11 14V16H16V11H14V13C14 13.5523 13.5523 14 13 14H11ZM12 8H8V12H12V8Z",fill:o})})},window.tablerIcons.IconHAuto=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtH-auto",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2 6C2 5.44772 2.44772 5 3 5H5C5.55228 5 6 5.44772 6 6C6 6.55228 5.55228 7 5 7V11H11V7C10.4477 7 10 6.55228 10 6C10 5.44772 10.4477 5 11 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7V17C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H11C10.4477 19 10 18.5523 10 18C10 17.4477 10.4477 17 11 17V13H5V17C5.55228 17 6 17.4477 6 18C6 18.5523 5.55228 19 5 19H3C2.44772 19 2 18.5523 2 18C2 17.4477 2.44772 17 3 17V7C2.44772 7 2 6.55228 2 6ZM19 11C18.7348 11 18.4804 11.1054 18.2929 11.2929C18.1054 11.4804 18 11.7348 18 12V14H20V12C20 11.7348 19.8946 11.4804 19.7071 11.2929C19.5196 11.1054 19.2652 11 19 11ZM22 12C22 11.2043 21.6839 10.4413 21.1213 9.87868C20.5587 9.31607 19.7957 9 19 9C18.2043 9 17.4413 9.31607 16.8787 9.87868C16.3161 10.4413 16 11.2043 16 12V18C16 18.5523 16.4477 19 17 19C17.5523 19 18 18.5523 18 18V16H20V18C20 18.5523 20.4477 19 21 19C21.5523 19 22 18.5523 22 18V12Z",fill:o})})},window.tablerIcons.IconHeadingOff=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtHeadingOff",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2.29289 2.29289C2.68342 1.90237 3.31658 1.90237 3.70711 2.29289L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L18.5858 20H15C14.4477 20 14 19.5523 14 19C14 18.4477 14.4477 18 15 18H16V17.4142L11.5858 13H8V18H9C9.55228 18 10 18.4477 10 19C10 19.5523 9.55228 20 9 20H5C4.44772 20 4 19.5523 4 19C4 18.4477 4.44772 18 5 18H6V7.41421L2.29289 3.70711C1.90237 3.31658 1.90237 2.68342 2.29289 2.29289ZM8 9.41421V11H9.58579L8 9.41421ZM8 5C8 4.44772 8.44772 4 9 4H10C10.5523 4 11 4.44772 11 5C11 5.55228 10.5523 6 10 6H9C8.44772 6 8 5.55228 8 5ZM14 5C14 4.44772 14.4477 4 15 4H19C19.5523 4 20 4.44772 20 5C20 5.55228 19.5523 6 19 6H18V12C18 12.5523 17.5523 13 17 13C16.4477 13 16 12.5523 16 12V6H15C14.4477 6 14 5.55228 14 5Z",fill:o})})},window.tablerIcons.IconInternalLink=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtInternalLink",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4 6C4 4.34315 5.34315 3 7 3H18C19.6569 3 21 4.34315 21 6V17C21 18.6569 19.6569 20 18 20H11C10.4477 20 10 19.5523 10 19C10 18.4477 10.4477 18 11 18H18C18.5523 18 19 17.5523 19 17V6C19 5.44772 18.5523 5 18 5H7C6.44772 5 6 5.44772 6 6V13C6 13.5523 5.55228 14 5 14C4.44772 14 4 13.5523 4 13V6ZM8 10C8 9.44772 8.44772 9 9 9H14C14.5523 9 15 9.44772 15 10V15C15 15.5523 14.5523 16 14 16C13.4477 16 13 15.5523 13 15V12.4142L4.70711 20.7071C4.31658 21.0976 3.68342 21.0976 3.29289 20.7071C2.90237 20.3166 2.90237 19.6834 3.29289 19.2929L11.5858 11H9C8.44772 11 8 10.5523 8 10Z",fill:o})})},window.tablerIcons.IconLinkToBlock=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtLinkToBlock",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M9 8C9 7.44772 9.44772 7 10 7H22C22.5523 7 23 7.44772 23 8V12C23 12.5523 22.5523 13 22 13C21.4477 13 21 12.5523 21 12V9H11V12C11 12.5523 10.5523 13 10 13C9.44772 13 9 12.5523 9 12V8ZM1 10C1 8.89543 1.89543 8 3 8C4.10457 8 5 8.89543 5 10C5 11.1046 4.10457 12 3 12C1.89543 12 1 11.1046 1 10ZM15.2929 11.2929C15.6834 10.9024 16.3166 10.9024 16.7071 11.2929L19.7071 14.2929C20.0976 14.6834 20.0976 15.3166 19.7071 15.7071C19.3166 16.0976 18.6834 16.0976 18.2929 15.7071L17 14.4142V17C17 18.1046 17.8954 19 19 19H23C23.5523 19 24 19.4477 24 20C24 20.5523 23.5523 21 23 21H19C16.7909 21 15 19.2091 15 17V14.4142L13.7071 15.7071C13.3166 16.0976 12.6834 16.0976 12.2929 15.7071C11.9024 15.3166 11.9024 14.6834 12.2929 14.2929L15.2929 11.2929Z",fill:o})})},window.tablerIcons.IconLinkToPage=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtLinkToPage",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4 4C4 2.34315 5.34315 1 7 1H17C18.6569 1 20 2.34315 20 4V18C20 18.5523 19.5523 19 19 19C18.4477 19 18 18.5523 18 18V4C18 3.44772 17.5523 3 17 3H7C6.44772 3 6 3.44772 6 4V18C6 18.5523 5.55228 19 5 19C4.44772 19 4 18.5523 4 18V4ZM8 6C8 5.44772 8.44772 5 9 5H13C13.5523 5 14 5.44772 14 6C14 6.55228 13.5523 7 13 7H9C8.44772 7 8 6.55228 8 6ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L15.7071 16.2929C16.0976 16.6834 16.0976 17.3166 15.7071 17.7071C15.3166 18.0976 14.6834 18.0976 14.2929 17.7071L13 16.4142V19C13 20.1046 13.8954 21 15 21H19C19.5523 21 20 21.4477 20 22C20 22.5523 19.5523 23 19 23H15C12.7909 23 11 21.2091 11 19L11 16.4142L9.70711 17.7071C9.31658 18.0976 8.68342 18.0976 8.29289 17.7071C7.90237 17.3166 7.90237 16.6834 8.29289 16.2929L11.2929 13.2929Z",fill:o})})},window.tablerIcons.IconLinkToWhiteboard=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtLinkToWhiteboard",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2 5C2 3.34315 3.34315 2 5 2H19C20.6569 2 22 3.34315 22 5V15C22 16.6569 20.6569 18 19 18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19C19.5523 16 20 15.5523 20 15V5C20 4.44772 19.5523 4 19 4H14V7C14 7.55228 13.5523 8 13 8H7C6.44772 8 6 7.55228 6 7V4H5C4.44772 4 4 4.44772 4 5V17C4 17.5523 3.55228 18 3 18C2.44772 18 2 17.5523 2 17V5ZM8 4V6H12V4H8ZM17 6C17.5523 6 18 6.44772 18 7V13C18 13.5523 17.5523 14 17 14C16.4477 14 16 13.5523 16 13V7C16 6.44772 16.4477 6 17 6ZM9.29289 12.2929C9.68342 11.9024 10.3166 11.9024 10.7071 12.2929L13.7071 15.2929C14.0976 15.6834 14.0976 16.3166 13.7071 16.7071C13.3166 17.0976 12.6834 17.0976 12.2929 16.7071L11 15.4142V18C11 19.1046 11.8954 20 13 20H17C17.5523 20 18 20.4477 18 21C18 21.5523 17.5523 22 17 22H13C10.7909 22 9 20.2091 9 18L9 15.4142L7.70711 16.7071C7.31658 17.0976 6.68342 17.0976 6.29289 16.7071C5.90237 16.3166 5.90237 15.6834 6.29289 15.2929L9.29289 12.2929Z",fill:o})})},window.tablerIcons.IconNewBlock=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtNewBlock",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8 5C8 4.44772 8.44772 4 9 4H20C20.5523 4 21 4.44772 21 5V9C21 9.55228 20.5523 10 20 10H9C8.44772 10 8 9.55228 8 9V5ZM10 6V8H19V6H10ZM0 7C0 5.89543 0.89543 5 2 5C3.10457 5 4 5.89543 4 7C4 8.10457 3.10457 9 2 9C0.89543 9 0 8.10457 0 7ZM11 13C11 12.4477 11.4477 12 12 12H16C16.5523 12 17 12.4477 17 13C17 13.5523 16.5523 14 16 14H13V16C13.5523 16 14 16.4477 14 17C14 17.5523 13.5523 18 13 18H12C11.4477 18 11 17.5523 11 17V13ZM3 15C3 13.8954 3.89543 13 5 13C6.10457 13 7 13.8954 7 15C7 16.1046 6.10457 17 5 17C3.89543 17 3 16.1046 3 15ZM20 13C20.5523 13 21 13.4477 21 14V16H23C23.5523 16 24 16.4477 24 17C24 17.5523 23.5523 18 23 18H21V20C21 20.5523 20.5523 21 20 21C19.4477 21 19 20.5523 19 20V18H17C16.4477 18 16 17.5523 16 17C16 16.4477 16.4477 16 17 16H19V14C19 13.4477 19.4477 13 20 13Z",fill:o})})},window.tablerIcons.IconNewPage=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtNewPage",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V12C20 12.5523 19.5523 13 19 13C18.4477 13 18 12.5523 18 12V5C18 4.44772 17.5523 4 17 4H7C6.44772 4 6 4.44772 6 5V17C6 17.5523 6.44772 18 7 18H12C12.5523 18 13 18.4477 13 19C13 19.5523 12.5523 20 12 20H7C5.34315 20 4 18.6569 4 17V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7ZM19 15C19.5523 15 20 15.4477 20 16V18H22C22.5523 18 23 18.4477 23 19C23 19.5523 22.5523 20 22 20H20V22C20 22.5523 19.5523 23 19 23C18.4477 23 18 22.5523 18 22V20H16C15.4477 20 15 19.5523 15 19C15 18.4477 15.4477 18 16 18H18V16C18 15.4477 18.4477 15 19 15Z",fill:o})})},window.tablerIcons.IconNewWhiteboardElement=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtNewWhiteboardElement",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M6 4C5.44772 4 5 4.44772 5 5V6C5 6.55228 4.55228 7 4 7C3.44772 7 3 6.55228 3 6V5C3 3.34315 4.34315 2 6 2H8C8.55228 2 9 2.44772 9 3C9 3.55228 8.55228 4 8 4H6ZM15 3C15 2.44772 15.4477 2 16 2H18C19.6569 2 21 3.34315 21 5V6C21 6.55228 20.5523 7 20 7C19.4477 7 19 6.55228 19 6V5C19 4.44772 18.5523 4 18 4H16C15.4477 4 15 3.55228 15 3ZM7 9C7 8.44772 7.44772 8 8 8H16C16.5523 8 17 8.44772 17 9V13C17 13.5523 16.5523 14 16 14H8C7.44772 14 7 13.5523 7 13V9ZM9 10V12H15V10H9ZM4 15C4.55228 15 5 15.4477 5 16V17C5 17.5523 5.44772 18 6 18H8C8.55228 18 9 18.4477 9 19C9 19.5523 8.55228 20 8 20H6C4.34315 20 3 18.6569 3 17V16C3 15.4477 3.44772 15 4 15ZM20 15C20.5523 15 21 15.4477 21 16V18H23C23.5523 18 24 18.4477 24 19C24 19.5523 23.5523 20 23 20H21V22C21 22.5523 20.5523 23 20 23C19.4477 23 19 22.5523 19 22V20H17C16.4477 20 16 19.5523 16 19C16 18.4477 16.4477 18 17 18H19V16C19 15.4477 19.4477 15 20 15Z",fill:o})})},window.tablerIcons.IconNewWhiteboard=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtNewWhiteboard",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H13C13.5523 17 14 17.4477 14 18C14 18.5523 13.5523 19 13 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM20 14C20.5523 14 21 14.4477 21 15V17H23C23.5523 17 24 17.4477 24 18C24 18.5523 23.5523 19 23 19H21V21C21 21.5523 20.5523 22 20 22C19.4477 22 19 21.5523 19 21V19H17C16.4477 19 16 18.5523 16 18C16 17.4477 16.4477 17 17 17H19V15C19 14.4477 19.4477 14 20 14Z",fill:o})})},window.tablerIcons.IconObjectCompact=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtObjectCompact",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V9C21 9.55228 20.5523 10 20 10H18C17.4477 10 17 9.55228 17 9C17 8.44772 17.4477 8 18 8H19V4H5V8H6C6.55228 8 7 8.44772 7 9C7 9.55228 6.55228 10 6 10H4C3.44772 10 3 9.55228 3 9V3ZM11.2929 7.29289C11.6834 6.90237 12.3166 6.90237 12.7071 7.29289L16.7071 11.2929C17.0976 11.6834 17.0976 12.3166 16.7071 12.7071C16.3166 13.0976 15.6834 13.0976 15.2929 12.7071L13 10.4142V19C13 19.5523 12.5523 20 12 20C11.4477 20 11 19.5523 11 19V10.4142L8.70711 12.7071C8.31658 13.0976 7.68342 13.0976 7.29289 12.7071C6.90237 12.3166 6.90237 11.6834 7.29289 11.2929L11.2929 7.29289Z",fill:o})})},window.tablerIcons.IconObjectExpanded=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtObjectExpanded",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M3 3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V3ZM5 4V8H8C8.55228 8 9 8.44772 9 9C9 9.55228 8.55228 10 8 10H5V20H19V10H16C15.4477 10 15 9.55228 15 9C15 8.44772 15.4477 8 16 8H19V4H5ZM12 6C12.5523 6 13 6.44772 13 7V14.5858L15.2929 12.2929C15.6834 11.9024 16.3166 11.9024 16.7071 12.2929C17.0976 12.6834 17.0976 13.3166 16.7071 13.7071L12.7071 17.7071C12.3166 18.0976 11.6834 18.0976 11.2929 17.7071L7.29289 13.7071C6.90237 13.3166 6.90237 12.6834 7.29289 12.2929C7.68342 11.9024 8.31658 11.9024 8.70711 12.2929L11 14.5858V7C11 6.44772 11.4477 6 12 6Z",fill:o})})},window.tablerIcons.IconOpenAsPage=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtOpenAsPage",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V18C20 19.6569 18.6569 21 17 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H17C17.5523 19 18 18.5523 18 18V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM11.2929 13.2929C11.6834 12.9024 12.3166 12.9024 12.7071 13.2929L14.7071 15.2929C15.0976 15.6834 15.0976 16.3166 14.7071 16.7071C14.3166 17.0976 13.6834 17.0976 13.2929 16.7071L13 16.4142V23C13 23.5523 12.5523 24 12 24C11.4477 24 11 23.5523 11 23L11 16.4142L10.7071 16.7071C10.3166 17.0976 9.68342 17.0976 9.29289 16.7071C8.90237 16.3166 8.90237 15.6834 9.29289 15.2929L11.2929 13.2929Z",fill:o})})},window.tablerIcons.IconPageSearch=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtPageSearch",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4 6C4 4.34315 5.34315 3 7 3H17C18.6569 3 20 4.34315 20 6V11C20 11.5523 19.5523 12 19 12C18.4477 12 18 11.5523 18 11V6C18 5.44772 17.5523 5 17 5H7C6.44772 5 6 5.44772 6 6V18C6 18.5523 6.44772 19 7 19H10C10.5523 19 11 19.4477 11 20C11 20.5523 10.5523 21 10 21H7C5.34315 21 4 19.6569 4 18V6ZM8 8C8 7.44772 8.44772 7 9 7H13C13.5523 7 14 7.44772 14 8C14 8.55228 13.5523 9 13 9H9C8.44772 9 8 8.55228 8 8ZM16.5 16C15.6716 16 15 16.6716 15 17.5C15 18.3284 15.6716 19 16.5 19C17.3284 19 18 18.3284 18 17.5C18 16.6716 17.3284 16 16.5 16ZM13 17.5C13 15.567 14.567 14 16.5 14C18.433 14 20 15.567 20 17.5C20 18.1028 19.8476 18.6699 19.5793 19.1651L21.7071 21.2929C22.0976 21.6834 22.0976 22.3166 21.7071 22.7071C21.3166 23.0976 20.6834 23.0976 20.2929 22.7071L18.1651 20.5793C17.6699 20.8476 17.1028 21 16.5 21C14.567 21 13 19.433 13 17.5Z",fill:o})})},window.tablerIcons.IconPage=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtPage",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M7 4C6.44772 4 6 4.44772 6 5V19C6 19.5523 6.44771 20 7 20H17C17.5523 20 18 19.5523 18 19V5C18 4.44772 17.5523 4 17 4H7ZM4 5C4 3.34315 5.34315 2 7 2H17C18.6569 2 20 3.34315 20 5V19C20 20.6569 18.6569 22 17 22H7C5.34315 22 4 20.6569 4 19V5ZM8 7C8 6.44772 8.44772 6 9 6H13C13.5523 6 14 6.44772 14 7C14 7.55228 13.5523 8 13 8H9C8.44772 8 8 7.55228 8 7Z",fill:o})})},window.tablerIcons.IconReferencesHide=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtReferencesHide",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M11.2929 2.29289C11.6834 1.90237 12.3166 1.90237 12.7071 2.29289L14.7071 4.29289C15.0976 4.68342 15.0976 5.31658 14.7071 5.70711C14.3166 6.09763 13.6834 6.09763 13.2929 5.70711L12 4.41421L10.7071 5.70711C10.3166 6.09763 9.68342 6.09763 9.29289 5.70711C8.90237 5.31658 8.90237 4.68342 9.29289 4.29289L11.2929 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z",fill:o})})},window.tablerIcons.IconReferencesShow=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtReferencesShow",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M9.29289 2.29289C9.68342 1.90237 10.3166 1.90237 10.7071 2.29289L12 3.58579L13.2929 2.29289C13.6834 1.90237 14.3166 1.90237 14.7071 2.29289C15.0976 2.68342 15.0976 3.31658 14.7071 3.70711L12.7071 5.70711C12.3166 6.09763 11.6834 6.09763 11.2929 5.70711L9.29289 3.70711C8.90237 3.31658 8.90237 2.68342 9.29289 2.29289ZM1 11C1 9.34315 2.34315 8 4 8H20C21.6569 8 23 9.34315 23 11V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V11ZM4 10C3.44772 10 3 10.4477 3 11V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V11C21 10.4477 20.5523 10 20 10H4ZM5 13C5 12.4477 5.44772 12 6 12H10C10.5523 12 11 12.4477 11 13C11 13.5523 10.5523 14 10 14H6C5.44772 14 5 13.5523 5 13ZM8 16C8.55228 16 9 16.4477 9 17V17.01C9 17.5623 8.55228 18.01 8 18.01C7.44772 18.01 7 17.5623 7 17.01V17C7 16.4477 7.44772 16 8 16ZM18 18H12C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16H18C18.5523 16 19 16.4477 19 17C19 17.5523 18.5523 18 18 18Z",fill:o})})},window.tablerIcons.IconSelectCursor=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtSelectCursor",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M4.29292 4.29289C4.56075 4.02506 4.95692 3.93154 5.31625 4.05132L19.3163 8.71798C19.7 8.84589 19.9688 9.19233 19.9975 9.59578C20.0262 9.99922 19.809 10.3802 19.4472 10.5611L16.6659 11.9518L19.4483 14.7343C19.8389 15.1248 19.8389 15.758 19.4483 16.1485L16.1485 19.4483C15.758 19.8388 15.1248 19.8388 14.7343 19.4483L11.9518 16.6658L10.5611 19.4472C10.3802 19.809 9.99925 20.0262 9.5958 19.9975C9.19236 19.9688 8.84591 19.6999 8.71801 19.3162L4.05134 5.31623C3.93157 4.95689 4.02509 4.56073 4.29292 4.29289ZM6.58117 6.58114L9.85194 16.3934L10.7834 14.5305C10.9272 14.2429 11.2004 14.0421 11.5177 13.9906C11.835 13.9391 12.1577 14.0433 12.385 14.2706L15.4414 17.327L17.327 15.4414L14.2706 12.3849C14.0433 12.1576 13.9391 11.8349 13.9906 11.5177C14.0421 11.2004 14.243 10.9272 14.5305 10.7834L16.3935 9.85191L6.58117 6.58114Z",fill:o})})},window.tablerIcons.IconText=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtText",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M5 5C5 4.44772 5.44772 4 6 4H18C18.5523 4 19 4.44772 19 5V7C19 7.55228 18.5523 8 18 8C17.4477 8 17 7.55228 17 7V6H13V18H14C14.5523 18 15 18.4477 15 19C15 19.5523 14.5523 20 14 20H10C9.44772 20 9 19.5523 9 19C9 18.4477 9.44772 18 10 18H11V6H7V7C7 7.55228 6.55228 8 6 8C5.44772 8 5 7.55228 5 7V5Z",fill:o})})},window.tablerIcons.IconUngroup=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtUngroup",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M2 3C2 2.44772 2.44772 2 3 2H5C5.55228 2 6 2.44772 6 3H12C12 2.44772 12.4477 2 13 2H15C15.5523 2 16 2.44772 16 3V5C16 5.55228 15.5523 6 15 6V8H18C18 7.44772 18.4477 7 19 7H21C21.5523 7 22 7.44772 22 8V10C22 10.5523 21.5523 11 21 11V18C21.5523 18 22 18.4477 22 19V21C22 21.5523 21.5523 22 21 22H19C18.4477 22 18 21.5523 18 21H11C11 21.5523 10.5523 22 10 22H8C7.44772 22 7 21.5523 7 21V19C7 18.4477 7.44772 18 8 18V15H6C6 15.5523 5.55228 16 5 16H3C2.44772 16 2 15.5523 2 15V13C2 12.4477 2.44772 12 3 12V6C2.44772 6 2 5.55228 2 5V3ZM5 6V12C5.55228 12 6 12.4477 6 13H12C12 12.4477 12.4477 12 13 12V6C12.4477 6 12 5.55228 12 5H6C6 5.55228 5.55228 6 5 6ZM15 12V10H18C18 10.5523 18.4477 11 19 11V18C18.4477 18 18 18.4477 18 19H11C11 18.4477 10.5523 18 10 18V15H12C12 15.5523 12.4477 16 13 16H15C15.5523 16 16 15.5523 16 15V13C16 12.4477 15.5523 12 15 12Z",fill:o})})},window.tablerIcons.IconWhiteboardElement=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtWhiteboardElement",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M6 5C5.44772 5 5 5.44772 5 6V7C5 7.55228 4.55228 8 4 8C3.44772 8 3 7.55228 3 7V6C3 4.34315 4.34315 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6ZM15 4C15 3.44772 15.4477 3 16 3H18C19.6569 3 21 4.34315 21 6V7C21 7.55228 20.5523 8 20 8C19.4477 8 19 7.55228 19 7V6C19 5.44772 18.5523 5 18 5H16C15.4477 5 15 4.55228 15 4ZM7 10C7 9.44772 7.44772 9 8 9H16C16.5523 9 17 9.44772 17 10V14C17 14.5523 16.5523 15 16 15H8C7.44772 15 7 14.5523 7 14V10ZM9 11V13H15V11H9ZM4 16C4.55228 16 5 16.4477 5 17V18C5 18.5523 5.44772 19 6 19H8C8.55228 19 9 19.4477 9 20C9 20.5523 8.55228 21 8 21H6C4.34315 21 3 19.6569 3 18V17C3 16.4477 3.44772 16 4 16ZM20 16C20.5523 16 21 16.4477 21 17V18C21 19.6569 19.6569 21 18 21H16C15.4477 21 15 20.5523 15 20C15 19.4477 15.4477 19 16 19H18C18.5523 19 19 18.5523 19 18V17C19 16.4477 19.4477 16 20 16Z",fill:o})})},window.tablerIcons.IconWhiteboardSearch=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtWhiteboardSearch",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M1 6C1 4.34315 2.34315 3 4 3H18C19.6569 3 21 4.34315 21 6V11C21 11.5523 20.5523 12 20 12C19.4477 12 19 11.5523 19 11V6C19 5.44772 18.5523 5 18 5H13V8C13 8.55228 12.5523 9 12 9H6C5.44772 9 5 8.55228 5 8V5H4C3.44772 5 3 5.44772 3 6V13H10C10.5523 13 11 13.4477 11 14V17H12C12.5523 17 13 17.4477 13 18C13 18.5523 12.5523 19 12 19H4C2.34315 19 1 17.6569 1 16V6ZM9 17V15H3V16C3 16.5523 3.44772 17 4 17H9ZM7 5V7H11V5H7ZM18.5 16C17.6716 16 17 16.6716 17 17.5C17 18.3284 17.6716 19 18.5 19C19.3284 19 20 18.3284 20 17.5C20 16.6716 19.3284 16 18.5 16ZM15 17.5C15 15.567 16.567 14 18.5 14C20.433 14 22 15.567 22 17.5C22 18.1028 21.8476 18.6699 21.5793 19.1651L23.7071 21.2929C24.0976 21.6834 24.0976 22.3166 23.7071 22.7071C23.3166 23.0976 22.6834 23.0976 22.2929 22.7071L20.1651 20.5793C19.6699 20.8476 19.1028 21 18.5 21C16.567 21 15 19.433 15 17.5Z",fill:o})})},window.tablerIcons.IconWhiteboard=function({size:e=24,color:o="currentColor",stroke:n=0,...C}){return(0,i.jsx)("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",strokeWidth:n,stroke:o,strokeLinecap:"round",strokeLinejoin:"round",className:"icon iconTabler iconTablerExtWhiteboard",...C,xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)("path",{d:"M18 9C18 8.44772 17.5523 8 17 8C16.4477 8 16 8.44772 16 9H18ZM16 15C16 15.5523 16.4477 16 17 16C17.5523 16 18 15.5523 18 15H16ZM3 14C2.44772 14 2 14.4477 2 15C2 15.5523 2.44772 16 3 16V14ZM11 15H12C12 14.4477 11.5523 14 11 14V15ZM10 19C10 19.5523 10.4477 20 11 20C11.5523 20 12 19.5523 12 19H10ZM14 5C14 4.44772 13.5523 4 13 4C12.4477 4 12 4.44772 12 5H14ZM13 9V10C13.5523 10 14 9.55228 14 9H13ZM7 9H6C6 9.55228 6.44772 10 7 10V9ZM8 5C8 4.44772 7.55228 4 7 4C6.44772 4 6 4.44772 6 5H8ZM5 6H19V4H5V6ZM20 7V17H22V7H20ZM19 18H5V20H19V18ZM4 17V7H2V17H4ZM5 18C4.44772 18 4 17.5523 4 17H2C2 18.6569 3.34315 20 5 20V18ZM20 17C20 17.5523 19.5523 18 19 18V20C20.6569 20 22 18.6569 22 17H20ZM19 6C19.5523 6 20 6.44772 20 7H22C22 5.34315 20.6569 4 19 4V6ZM5 4C3.34315 4 2 5.34315 2 7H4C4 6.44772 4.44772 6 5 6V4ZM16 9V15H18V9H16ZM3 16H11V14H3V16ZM10 15V19H12V15H10ZM12 5V9H14V5H12ZM13 8H7V10H13V8ZM8 9V5H6V9H8Z",fill:o})})}})(); \ No newline at end of file From aa65cff5b60f60b23c3f78c8027738f63f17fe9c Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 11 May 2023 16:06:00 +0300 Subject: [PATCH 45/81] fix: remove unneeded persist --- .../core/src/lib/tools/TLSelectTool/states/TranslatingState.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts index b5d49cb096..07052cbe9e 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/TranslatingState.ts @@ -125,7 +125,6 @@ export class TranslatingState< onExit = () => { // Resume the history when we exit this.app.history.resume() - this.app.persist() // Reset initial data this.didClone = false From 45ce3348c59f3031e14370239f25b3d1f9a34408 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 11 May 2023 16:07:08 +0300 Subject: [PATCH 46/81] enhance: avoid repeated indexOf --- src/main/frontend/handler/whiteboard.cljs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 7e75ed6409..95d1308e77 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -85,15 +85,13 @@ (util/time-ms))})) (defn- compute-tx - [^js app ^js tl-page new-id-nonces db-id-nonces page-name replace?] + [^js app ^js tl-page new-id-nonces db-id-nonces page-name shapes-index replace?] (let [assets (js->clj-keywordize (.getCleanUpAssets app)) - new-shapes (.-shapes tl-page) - shapes-index (map #(gobj/get % "id") new-shapes) upsert-shapes (->> (set/difference new-id-nonces db-id-nonces) (map (fn [{:keys [id]}] (-> (.-serialized ^js (.getShapeById tl-page id)) js->clj-keywordize - (assoc :index (.indexOf shapes-index id))))) + (assoc :index (get id shapes-index))))) (set)) old-ids (set (map :id db-id-nonces)) new-ids (set (map :id new-id-nonces)) @@ -117,7 +115,7 @@ prev-changed-blocks (when (seq changed-shapes) (db/pull-many repo '[*] (mapv (fn [shape] [:block/uuid (uuid (:id shape))]) changed-shapes)))] - {:page-block (build-page-block page-name tl-page assets shapes-index) + {:page-block (build-page-block page-name tl-page assets (keys shapes-index)) :upserted-blocks (->> upsert-shapes (map #(shape->block % page-name)) (map with-timestamps)) @@ -134,20 +132,20 @@ (defn transact-tldr-delta! [page-name ^js app replace?] (let [tl-page ^js (second (first (.-pages app))) shapes (.-shapes ^js tl-page) - shapes-index (map #(gobj/get % "id") shapes) + shapes-index (zipmap (mapv #(gobj/get % "id") shapes) (range (.-length shapes))) new-id-nonces (set (map (fn [shape] (let [id (.-id shape)] - {:id id - :nonce (if (= shape.id (.indexOf shapes-index id)) - (.-nonce shape) - (.getTime (js/Date.)))})) shapes)) + {:id id + :nonce (if (= shape.id (get id shapes-index)) + (.-nonce shape) + (js/Date.now))})) shapes)) repo (state/get-current-repo) db-id-nonces (or (get-in @*last-shapes-nonce [repo page-name]) (set (->> (model/get-whiteboard-id-nonces repo page-name) (map #(update % :id str))))) {:keys [page-block upserted-blocks delete-blocks metadata]} - (compute-tx app tl-page new-id-nonces db-id-nonces page-name replace?) + (compute-tx app tl-page new-id-nonces db-id-nonces page-name shapes-index replace?) tx-data (concat delete-blocks [page-block] upserted-blocks) new-shapes (get-in metadata [:data :new-shapes]) metadata' (cond From a77512c0dac0ca24cd39d149b120c986283a03cb Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 11 May 2023 17:09:13 +0300 Subject: [PATCH 47/81] fix: get --- src/main/frontend/handler/whiteboard.cljs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 95d1308e77..811c8f6857 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -91,7 +91,7 @@ (map (fn [{:keys [id]}] (-> (.-serialized ^js (.getShapeById tl-page id)) js->clj-keywordize - (assoc :index (get id shapes-index))))) + (assoc :index (get shapes-index id))))) (set)) old-ids (set (map :id db-id-nonces)) new-ids (set (map :id new-id-nonces)) @@ -134,9 +134,11 @@ shapes (.-shapes ^js tl-page) shapes-index (zipmap (mapv #(gobj/get % "id") shapes) (range (.-length shapes))) new-id-nonces (set (map (fn [shape] - (let [id (.-id shape)] + (let [id (.-id shape) + _ (js/console.log id) + _ (js/console.log (get shapes-index id))] {:id id - :nonce (if (= shape.id (get id shapes-index)) + :nonce (if (= shape.id (get shapes-index id)) (.-nonce shape) (js/Date.now))})) shapes)) repo (state/get-current-repo) From 9e7542277798e03d75872f51122932d39dccb61f Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Thu, 11 May 2023 17:20:47 +0300 Subject: [PATCH 48/81] fix: remove console log --- src/main/frontend/handler/whiteboard.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 811c8f6857..27a57ffd17 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -134,9 +134,7 @@ shapes (.-shapes ^js tl-page) shapes-index (zipmap (mapv #(gobj/get % "id") shapes) (range (.-length shapes))) new-id-nonces (set (map (fn [shape] - (let [id (.-id shape) - _ (js/console.log id) - _ (js/console.log (get shapes-index id))] + (let [id (.-id shape)] {:id id :nonce (if (= shape.id (get shapes-index id)) (.-nonce shape) From 594a3cd6ee972046f447a53005d3591bb80b9fe9 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Fri, 12 May 2023 12:45:11 +0300 Subject: [PATCH 49/81] fix: updating shape index --- src/main/frontend/handler/whiteboard.cljs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 27a57ffd17..40847965bb 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -85,13 +85,16 @@ (util/time-ms))})) (defn- compute-tx - [^js app ^js tl-page new-id-nonces db-id-nonces page-name shapes-index replace?] + [^js app ^js tl-page new-id-nonces db-id-nonces page-name replace?] (let [assets (js->clj-keywordize (.getCleanUpAssets app)) + new-shapes (.-shapes tl-page) + shapes-index (mapv #(gobj/get % "id") new-shapes) + shape-id->index (zipmap shapes-index (range (.-length new-shapes))) upsert-shapes (->> (set/difference new-id-nonces db-id-nonces) (map (fn [{:keys [id]}] (-> (.-serialized ^js (.getShapeById tl-page id)) js->clj-keywordize - (assoc :index (get shapes-index id))))) + (assoc :index (get shape-id->index id))))) (set)) old-ids (set (map :id db-id-nonces)) new-ids (set (map :id new-id-nonces)) @@ -115,7 +118,7 @@ prev-changed-blocks (when (seq changed-shapes) (db/pull-many repo '[*] (mapv (fn [shape] [:block/uuid (uuid (:id shape))]) changed-shapes)))] - {:page-block (build-page-block page-name tl-page assets (keys shapes-index)) + {:page-block (build-page-block page-name tl-page assets shapes-index) :upserted-blocks (->> upsert-shapes (map #(shape->block % page-name)) (map with-timestamps)) @@ -132,11 +135,13 @@ (defn transact-tldr-delta! [page-name ^js app replace?] (let [tl-page ^js (second (first (.-pages app))) shapes (.-shapes ^js tl-page) - shapes-index (zipmap (mapv #(gobj/get % "id") shapes) (range (.-length shapes))) - new-id-nonces (set (map (fn [shape] + page-block (model/get-page page-name) + prev-shapes-index (get-in page-block [:block/properties :logseq.tldraw.page :shapes-index]) + shape-id->prev-index (zipmap prev-shapes-index (range (count prev-shapes-index))) + new-id-nonces (set (map-indexed (fn [idx shape] (let [id (.-id shape)] {:id id - :nonce (if (= shape.id (get shapes-index id)) + :nonce (if (= idx (get shape-id->prev-index id)) (.-nonce shape) (js/Date.now))})) shapes)) repo (state/get-current-repo) @@ -145,7 +150,7 @@ (set (->> (model/get-whiteboard-id-nonces repo page-name) (map #(update % :id str))))) {:keys [page-block upserted-blocks delete-blocks metadata]} - (compute-tx app tl-page new-id-nonces db-id-nonces page-name shapes-index replace?) + (compute-tx app tl-page new-id-nonces db-id-nonces page-name replace?) tx-data (concat delete-blocks [page-block] upserted-blocks) new-shapes (get-in metadata [:data :new-shapes]) metadata' (cond From 80511d3bed890c567b8fcf0da96a7287835b3dd5 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Fri, 12 May 2023 12:46:58 +0300 Subject: [PATCH 50/81] revert unneeded change --- src/main/frontend/handler/whiteboard.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/handler/whiteboard.cljs b/src/main/frontend/handler/whiteboard.cljs index 40847965bb..3cbe53a707 100644 --- a/src/main/frontend/handler/whiteboard.cljs +++ b/src/main/frontend/handler/whiteboard.cljs @@ -88,7 +88,7 @@ [^js app ^js tl-page new-id-nonces db-id-nonces page-name replace?] (let [assets (js->clj-keywordize (.getCleanUpAssets app)) new-shapes (.-shapes tl-page) - shapes-index (mapv #(gobj/get % "id") new-shapes) + shapes-index (map #(gobj/get % "id") new-shapes) shape-id->index (zipmap shapes-index (range (.-length new-shapes))) upsert-shapes (->> (set/difference new-id-nonces db-id-nonces) (map (fn [{:keys [id]}] From 42dd084544e7421f96eb635865b9a168db96655b Mon Sep 17 00:00:00 2001 From: Andelf Date: Fri, 12 May 2023 20:10:24 +0800 Subject: [PATCH 51/81] chore(release): bump version 0.9.6 (#9376) --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 8 ++++---- resources/package.json | 2 +- src/main/frontend/version.cljs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 0f270d1eee..1bc29bab0f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.logseq.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 58 - versionName "0.9.5" + versionCode 59 + versionName "0.9.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 9ee75f816d..b777c4ee75 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -515,7 +515,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.5; + MARKETING_VERSION = 0.9.6; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -542,7 +542,7 @@ INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.5; + MARKETING_VERSION = 0.9.6; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; @@ -567,7 +567,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.9.5; + MARKETING_VERSION = 0.9.6; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; @@ -594,7 +594,7 @@ INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 0.9.5; + MARKETING_VERSION = 0.9.6; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/resources/package.json b/resources/package.json index 434b787f69..75ad337bf9 100644 --- a/resources/package.json +++ b/resources/package.json @@ -1,7 +1,7 @@ { "name": "Logseq", "productName": "Logseq", - "version": "0.9.5", + "version": "0.9.6", "main": "electron.js", "author": "Logseq", "license": "AGPL-3.0", diff --git a/src/main/frontend/version.cljs b/src/main/frontend/version.cljs index b8f5874ea8..2b900d6c56 100644 --- a/src/main/frontend/version.cljs +++ b/src/main/frontend/version.cljs @@ -1,3 +1,3 @@ (ns ^:no-doc frontend.version) -(defonce version "0.9.5") +(defonce version "0.9.6") From 928742e66ba5ee14b503cfa4e120f6a003ce05e4 Mon Sep 17 00:00:00 2001 From: Ben Yorke Date: Thu, 19 Jan 2023 19:40:04 +0100 Subject: [PATCH 52/81] shui/table introduction --- .gitignore | 5 + deps.edn | 5 +- .../src/logseq/graph_parser/property.cljs | 7 +- deps/shui/.clj-kondo/config.edn | 17 + deps/shui/README.md | 29 ++ deps/shui/deps.edn | 1 + deps/shui/shui-graph/journals/2023_03_27.md | 2 + deps/shui/shui-graph/logseq/config.edn | 348 +++++++++++++ deps/shui/shui-graph/logseq/custom.css | 0 deps/shui/shui-graph/pages/About Shui.md | 22 + deps/shui/shui-graph/pages/Page 1.md | 3 + deps/shui/shui-graph/pages/Page 2.md | 1 + deps/shui/shui-graph/pages/Page 3.md | 1 + deps/shui/shui-graph/pages/contents.md | 4 + .../shui-graph/pages/shui___components.md | 4 + .../pages/shui___components___table.md | 62 +++ deps/shui/src/logseq/shui/context.cljs | 36 ++ deps/shui/src/logseq/shui/core.cljs | 11 + deps/shui/src/logseq/shui/table/v2.cljs | 471 ++++++++++++++++++ deps/shui/src/logseq/shui/util.cljs | 81 +++ e2e-tests/shui/table.spec.js | 304 +++++++++++ e2e-tests/utils.ts | 7 + package.json | 2 + shadow-cljs.edn | 12 +- src/main/frontend/commands.cljs | 4 +- src/main/frontend/components/block.cljs | 134 ++--- src/main/frontend/components/query.cljs | 7 +- src/main/frontend/components/query_table.cljs | 133 +++-- src/main/frontend/handler/editor.cljs | 12 +- src/main/frontend/page.cljs | 12 +- src/main/frontend/rum.cljs | 2 +- src/main/frontend/shui.cljs | 25 + src/main/frontend/state.cljs | 4 +- src/main/frontend/ui.cljs | 48 +- src/main/frontend/util/cursor.cljs | 2 +- tailwind.config.js | 242 ++++++++- yarn.lock | 10 + 37 files changed, 1883 insertions(+), 187 deletions(-) create mode 100644 deps/shui/.clj-kondo/config.edn create mode 100644 deps/shui/README.md create mode 100644 deps/shui/deps.edn create mode 100644 deps/shui/shui-graph/journals/2023_03_27.md create mode 100644 deps/shui/shui-graph/logseq/config.edn create mode 100644 deps/shui/shui-graph/logseq/custom.css create mode 100644 deps/shui/shui-graph/pages/About Shui.md create mode 100644 deps/shui/shui-graph/pages/Page 1.md create mode 100644 deps/shui/shui-graph/pages/Page 2.md create mode 100644 deps/shui/shui-graph/pages/Page 3.md create mode 100644 deps/shui/shui-graph/pages/contents.md create mode 100644 deps/shui/shui-graph/pages/shui___components.md create mode 100644 deps/shui/shui-graph/pages/shui___components___table.md create mode 100644 deps/shui/src/logseq/shui/context.cljs create mode 100644 deps/shui/src/logseq/shui/core.cljs create mode 100644 deps/shui/src/logseq/shui/table/v2.cljs create mode 100644 deps/shui/src/logseq/shui/util.cljs create mode 100644 e2e-tests/shui/table.spec.js create mode 100644 src/main/frontend/shui.cljs diff --git a/.gitignore b/.gitignore index dd4194aaef..f631847aa4 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,8 @@ android/app/src/main/assets/capacitor.config.json /public/static .yarn/ .yarnrc.yml + +deps/shui/.lsp +deps/shui/.lsp-cache +deps/shui/.clj-kondo +deps/shui/shui-graph/logseq/bak diff --git a/deps.edn b/deps.edn index 7a9b82c70f..14439b3ddc 100644 --- a/deps.edn +++ b/deps.edn @@ -27,11 +27,12 @@ camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"} instaparse/instaparse {:mvn/version "1.4.10"} org.clojars.mmb90/cljs-cache {:mvn/version "0.1.4"} + fipp/fipp {:mvn/version "0.6.26"} logseq/common {:local/root "deps/common"} logseq/graph-parser {:local/root "deps/graph-parser"} logseq/publishing {:local/root "deps/publishing"} - metosin/malli {:mvn/version "0.10.0"} - fipp/fipp {:mvn/version "0.6.26"}} + logseq/shui {:local/root "deps/shui"} + metosin/malli {:mvn/version "0.10.0"}} :aliases {:cljs {:extra-paths ["src/dev-cljs/" "src/test/" "src/electron/"] :extra-deps {org.clojure/clojurescript {:mvn/version "1.11.54"} diff --git a/deps/graph-parser/src/logseq/graph_parser/property.cljs b/deps/graph-parser/src/logseq/graph_parser/property.cljs index f0885bbd76..6354a8d187 100644 --- a/deps/graph-parser/src/logseq/graph_parser/property.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/property.cljs @@ -51,7 +51,12 @@ "Properties used by logseq that user can edit" [] (into #{:title :icon :template :template-including-parent :public :filters :exclude-from-graph-view - :logseq.query/nlp-date + :logseq.query/nlp-date + ;; view props + :logseq.color + ;; table props + :logseq.table.version :logseq.table.compact :logseq.table.headers :logseq.table.hover + :logseq.table.borders :logseq.table.stripes :logseq.table.max-width ;; org-mode only :macro :filetags} editable-linkable-built-in-properties)) diff --git a/deps/shui/.clj-kondo/config.edn b/deps/shui/.clj-kondo/config.edn new file mode 100644 index 0000000000..7d483887d9 --- /dev/null +++ b/deps/shui/.clj-kondo/config.edn @@ -0,0 +1,17 @@ +{ :config-in-ns + ;; :used-underscored-binding is turned off for components because of false positive + ;; for rum/defcs and _state. + {all-components {:linters {:used-underscored-binding {:level :off}}}} + + :linters + {;; Disable until it doesn't trigger false positives on rum/defcontext + :earmuffed-var-not-dynamic {:level :off}} + :hooks {:analyze-call {rum.core/defc hooks.rum/defc + rum.core/defcs hooks.rum/defcs + clojure.string/join hooks.path-invalid-construct/string-join}} + :lint-as {rum.core/defcc rum.core/defc + rum.core/with-context clojure.core/let + rum.core/defcontext clojure.core/def + rum.core/defc clojure.core/defn + rum.core/defcs clojure.core/defn + frontend.react/defc clojure.core/defn}} diff --git a/deps/shui/README.md b/deps/shui/README.md new file mode 100644 index 0000000000..b99bca2c23 --- /dev/null +++ b/deps/shui/README.md @@ -0,0 +1,29 @@ +## Description + +This library provides a set of UI components for use within logseq. + +## API + +This library is under the parent namespace `logseq.shui`. This library provides +several namespaces, all of which will be versioned, with the exception of `logseq.shui.context`. + +An example of a versioned namespace is the table namespace: + +`logseq.shui.table.v2` + +`root` components are exported from each versioned file to indicate the root component to be rendered: + +`logseq.shui.table.v2/root` + +Each root component should expect two arguments, `props` and `context`. + +## `props` + +Ultimately, components in shui will need to be used by JavaScript. While it is idiomatic in clojure to +use a list of properties, it is idiomatic in react to use a single props map. Shui components should therefore +stick to this convention when possible to ease the conversion between the two languages. + +## `context` + +Context is a set of functions that call back to the main application. These are abstracted out into a context +object to make it clear what is used internally, and what is used externally. diff --git a/deps/shui/deps.edn b/deps/shui/deps.edn new file mode 100644 index 0000000000..ccd9a316a2 --- /dev/null +++ b/deps/shui/deps.edn @@ -0,0 +1 @@ +{:paths ["src"]} diff --git a/deps/shui/shui-graph/journals/2023_03_27.md b/deps/shui/shui-graph/journals/2023_03_27.md new file mode 100644 index 0000000000..50c2753eb4 --- /dev/null +++ b/deps/shui/shui-graph/journals/2023_03_27.md @@ -0,0 +1,2 @@ +- +- \ No newline at end of file diff --git a/deps/shui/shui-graph/logseq/config.edn b/deps/shui/shui-graph/logseq/config.edn new file mode 100644 index 0000000000..0b98e38379 --- /dev/null +++ b/deps/shui/shui-graph/logseq/config.edn @@ -0,0 +1,348 @@ +{:meta/version 1 + + ;; Currently, we support either "Markdown" or "Org". + ;; This can overwrite your global preference so that + ;; maybe your personal preferred format is Org but you'd + ;; need to use Markdown for some projects. + ;; :preferred-format "" + + ;; Preferred workflow style. + ;; Value is either ":now" for NOW/LATER style, + ;; or ":todo" for TODO/DOING style. + :preferred-workflow :now + + ;; The app will ignore those directories or files. + ;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"] + :hidden [] + + ;; When creating the new journal page, the app will use your template if there is one. + ;; You only need to input your template name here. + :default-templates + {:journals ""} + + ;; Set a custom date format for journal page title + ;; Example: + ;; :journal/page-title-format "EEE, do MMM yyyy" + + ;; Whether to enable hover on tooltip preview feature + ;; Default is true, you can also toggle this via setting page + :ui/enable-tooltip? true + + ;; Show brackets around page references + ;; :ui/show-brackets? true + + ;; Enable showing the body of blocks when referencing them. + :ui/show-full-blocks? false + + ;; Enable Block timestamp + :feature/enable-block-timestamps? false + + ;; Enable remove accents when searching. + ;; After toggle this option, please remember to rebuild your search index by press (cmd+c cmd+s). + :feature/enable-search-remove-accents? true + + ;; Enable journals + ;; :feature/enable-journals? true + + ;; Enable flashcards + ;; :feature/enable-flashcards? true + + ;; Enable Whiteboards + ;; :feature/enable-whiteboards? true + + ;; Disable the built-in Scheduled tasks and deadlines query + ;; :feature/disable-scheduled-and-deadline-query? true + + ;; Specify the number of days in the future to display in the + ;; scheduled tasks and deadlines query, with a default value of 0 which + ;; only displays tasks for today. + ;; Example usage: + ;; Display all scheduled tasks and deadlines in the next 7 days + ;; :scheduled/future-days 7 + + ;; Specify the date on which the week starts. + ;; Goes from 0 to 6 (Monday to Sunday), default to 6 + :start-of-week 6 + + ;; Specify a custom CSS import + ;; This option take precedence over your local `logseq/custom.css` file + ;; You may find a list of awesome logseq themes here: + ;; https://github.com/logseq/awesome-logseq#css-themes + ;; Example: + ;; :custom-css-url "@import url('https://cdn.jsdelivr.net/gh/dracula/logseq@master/custom.css');" + + ;; Specify a custom js import + ;; This option take precedence over your local `logseq/custom.js` file + ;; :custom-js-url "" + + ;; Set a custom Arweave gateway + ;; Default gateway: https://arweave.net + ;; :arweave/gateway "" + + ;; Set Bullet indentation when exporting + ;; default option: tab + ;; Possible options are for `:sidebar` are + ;; 1. `:eight-spaces` as eight spaces + ;; 2. `:four-spaces` as four spaces + ;; 3. `:two-spaces` as two spaces + ;; :export/bullet-indentation :tab + + ;; When :all-pages-public? true, export repo would export all pages within that repo. + ;; Regardless of whether you've set any page to public or not. + ;; Example: + ;; :publishing/all-pages-public? true + + ;; Specify default home page and sidebar status for Logseq + ;; If not specified, Logseq default opens journals page on startup + ;; value for `:page` is name of page + ;; Possible options for `:sidebar` are + ;; 1. `"Contents"` to open up `Contents` in sidebar by default + ;; 2. `page name` to open up some page in sidebar + ;; 3. Or multiple pages in an array ["Contents" "Page A" "Page B"] + ;; If `:sidebar` is not set, sidebar will be hidden + ;; Example: + ;; 1. Setup page "Changelog" as home page and "Contents" in sidebar + ;; :default-home {:page "Changelog", :sidebar "Contents"} + ;; 2. Setup page "Jun 3rd, 2021" as home page without sidebar + ;; :default-home {:page "Jun 3rd, 2021"} + ;; 3. Setup page "home" as home page with multiple pages in sidebar + ;; :default-home {:page "home" :sidebar ["page a" "page b"]} + :default-home {:page "Contents"} + + ;; Tell logseq to use a specific folder in the repo as a default location for notes + ;; if not specified, notes are stored in `pages` directory + ;; :pages-directory "your-directory" + + ;; Tell logseq to use a specific folder in the repo as a default location for journals + ;; if not specified, journals are stored in `journals` directory + ;; :journals-directory "your-directory" + + ;; Set this to true will convert + ;; `[[Grant Ideas]]` to `[[file:./grant_ideas.org][Grant Ideas]]` for org-mode + ;; For more, see https://github.com/logseq/logseq/issues/672 + ;; :org-mode/insert-file-link? true + + ;; Setup custom shortcuts under `:shortcuts` key + ;; Syntax: + ;; 1. `+` means keys pressing simultaneously. eg: `ctrl+shift+a` + ;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s` + ;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac + ;; 4. use `false` to disable particular shortcut + ;; 5. you can define multiple bindings for one action, eg `["ctrl+j" "down"]` + ;; full list of configurable shortcuts are available below: + ;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs + ;; Example: + ;; :shortcuts + ;; {:editor/new-block "enter" + ;; :editor/new-line "shift+enter" + ;; :editor/insert-link "mod+shift+k" + ;; :editor/highlight false + ;; :ui/toggle-settings "t s" + ;; :editor/up ["ctrl+k" "up"] + ;; :editor/down ["ctrl+j" "down"] + ;; :editor/left ["ctrl+h" "left"] + ;; :editor/right ["ctrl+l" "right"]} + :shortcuts {} + + ;; By default, pressing `Enter` in the document mode will create a new line. + ;; Set this to `true` so that it's the same behaviour as the usual outliner mode. + :shortcut/doc-mode-enter-for-new-block? false + + ;; Block content larger than `block/content-max-length` will not be searchable + ;; or editable for performance. + :block/content-max-length 10000 + + ;; Whether to show command doc on hover + :ui/show-command-doc? true + + ;; Whether to show empty bullets for non-document mode (the default mode) + :ui/show-empty-bullets? false + + ;; Pre-defined :view function to use with advanced queries + :query/views + {:pprint + (fn [r] [:pre.code (pprint r)])} + + ;; Pre-defined :result-transform function for use with advanced queries + :query/result-transforms + {:sort-by-priority + (fn [result] (sort-by (fn [h] (get h :block/priority "Z")) result))} + + ;; The app will show those queries in today's journal page, + ;; the "NOW" query asks the tasks which need to be finished "now", + ;; the "NEXT" query asks the future tasks. + :default-queries + {:journals + [{:title "🔨 NOW" + :query [:find (pull ?h [*]) + :in $ ?start ?today + :where + [?h :block/marker ?marker] + [(contains? #{"NOW" "DOING"} ?marker)] + [?h :block/page ?p] + [?p :block/journal? true] + [?p :block/journal-day ?d] + [(>= ?d ?start)] + [(<= ?d ?today)]] + :inputs [:14d :today] + :result-transform (fn [result] + (sort-by (fn [h] + (get h :block/priority "Z")) result)) + :collapsed? false} + {:title "📅 NEXT" + :query [:find (pull ?h [*]) + :in $ ?start ?next + :where + [?h :block/marker ?marker] + [(contains? #{"NOW" "LATER" "TODO"} ?marker)] + [?h :block/page ?p] + [?p :block/journal? true] + [?p :block/journal-day ?d] + [(> ?d ?start)] + [(< ?d ?next)]] + :inputs [:today :7d-after] + :collapsed? false}]} + + ;; Add your own commands to slash menu to speedup. + ;; E.g. + ;; :commands + ;; [ + ;; ["js" "Javascript"] + ;; ["md" "Markdown"] + ;; ] + :commands + [] + + ;; By default, a block can only be collapsed if it has some children. + ;; `:outliner/block-title-collapse-enabled? true` enables a block with a title + ;; (multiple lines) can be collapsed too. For example: + ;; - block title + ;; block content + :outliner/block-title-collapse-enabled? false + + ;; Macros replace texts and will make you more productive. + ;; For example: + ;; Change the :macros value below to: + ;; {"poem" "Rose is $1, violet's $2. Life's ordered: Org assists you."} + ;; input "{{poem red,blue}}" + ;; becomes + ;; Rose is red, violet's blue. Life's ordered: Org assists you. + :macros {} + + ;; The default level to be opened for the linked references. + ;; For example, if we have some example blocks like this: + ;; - a [[page]] (level 1) + ;; - b (level 2) + ;; - c (level 3) + ;; - d (level 4) + ;; + ;; With the default value of level 2, `b` will be collapsed. + ;; If we set the level's value to 3, `b` will be opened and `c` will be collapsed. + :ref/default-open-blocks-level 2 + + :ref/linked-references-collapsed-threshold 50 + + ;; Favorites to list on the left sidebar + :favorites [] + + ;; any number between 0 and 1 (the greater it is the faster the changes of the next-interval of card reviews) (default 0.5) + ;; :srs/learning-fraction 0.5 + + ;; the initial interval after the first successful review of a card (default 4) + ;; :srs/initial-interval 4 + + ;; hide specific properties for blocks + ;; E.g. :block-hidden-properties #{:created-at :updated-at} + ;; :block-hidden-properties #{} + + ;; Enable all your properties to have corresponding pages + :property-pages/enabled? true + + ;; Properties to exclude from having property pages + ;; E.g.:property-pages/excludelist #{:duration :author} + ;; :property-pages/excludelist + + ;; By default, property value separated by commas will not be treated as + ;; page references. You can add properties to enable it. + ;; E.g. :property/separated-by-commas #{:alias :tags} + ;; :property/separated-by-commas #{} + + ;; Properties that are ignored when parsing property values for references + ;; :ignored-page-references-keywords #{"author" "startup"} + + ;; logbook setup + ;; :logbook/settings + ;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated + ;; :enabled-in-all-blocks true ;display logbook in all blocks after timetracking + ;; :enabled-in-timestamped-blocks false ;don't display logbook at all + ;; } + + ;; Mobile photo uploading setup + ;; :mobile/photo + ;; {:allow-editing? true + ;; :quality 80} + + ;; Mobile features options + ;; Gestures + ;; :mobile + ;; {:gestures/disabled-in-block-with-tags ["kanban"]} + + ;; Extra CodeMirror options + ;; See https://codemirror.net/5/doc/manual.html#config for possible options + ;; :editor/extra-codemirror-options {:keyMap "emacs" :lineWrapping true} + + ;; Enable logical outdenting + ;; :editor/logical-outdenting? true + + ;; When both text and a file are in the clipboard, paste the file + ;; :editor/preferred-pasting-file? true + + ;; Quick capture templates for receiving contents from other apps. + ;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded + ;; by received contents from other apps. Note: the {} cannot be omitted. + ;; - {time}: capture time + ;; - {date}: capture date using current date format, use `[[{date}]]` to get a page reference + ;; - {text}: text that users selected before sharing. + ;; - {url}: url or assets path for media files stored in Logseq. + ;; You can also reorder them, or even only use one or two of them in the template. + ;; You can also insert or format any text in the template as shown in the following examples. + ;; :quick-capture-templates + ;; {:text "[[quick capture]] **{time}**: {text} from {url}" + ;; :media "[[quick capture]] **{time}**: {url}"} + + ;; Quick capture options + ;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page nil} + + ;; File sync options + ;; Ignore these files when syncing, regexp is supported. + ;; :file-sync/ignore-files [] + + ;; dwim (do what I mean) for Enter key when editing. + ;; Context-awareness of Enter key makes editing more easily + ; :dwim/settings { + ; :admonition&src? true + ; :markup? false + ; :block-ref? true + ; :page-ref? true + ; :properties? true + ; :list? true + ; } + + ;; Decide the way to escape the special characters in the page title. + ;; Warning: + ;; This is a dangerous operation. If you want to change the setting, + ;; should access the setting `Filename format` and follow the instructions. + ;; Or you have to rename all the affected files manually then re-index on all + ;; clients after the files are synced. Wrong handling may cause page titles + ;; containing special characters to be messy. + ;; Available values: + ;; :file/name-format :triple-lowbar + ;; ;use triple underscore `___` for slash `/` in page title + ;; ;use Percent-encoding for other invalid characters + :file/name-format :triple-lowbar + :feature/enable-whiteboards? true} + + ;; specify the format of the filename for journal files + ;; :journal/file-name-format "yyyy_MM_dd" + + diff --git a/deps/shui/shui-graph/logseq/custom.css b/deps/shui/shui-graph/logseq/custom.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/deps/shui/shui-graph/pages/About Shui.md b/deps/shui/shui-graph/pages/About Shui.md new file mode 100644 index 0000000000..4db5bf0a7b --- /dev/null +++ b/deps/shui/shui-graph/pages/About Shui.md @@ -0,0 +1,22 @@ +- ## What is shui? +- Shui is the component library for logseq. It has 3 main goals: + - 1. Provide an abstraction for specific components, separate from the main codebase + 2. Provide a consistent look and feel for the future of logseq + 3. Provide ready to use components to plugin authors to allow for a more consistent better user experience of plugin authors and users +- +- ## What are the general concepts of shui? +- Shui has a few core principles: + - ### Focus on a native core experience + - We want to provide a smooth, consistent, and native feel for all logseq features, first and foremost + - ### Specific output, general input + - Components should be generally reusable by their props, however should have the user experience themselves + - Eventually, getting to a highly composable components is a great goal, but we should start small and focused first + - ### UI is a marathon, not a sprint + - Components in shui should be versioned, and should expect to evolve over time + - We need to go from highly coupled, low reused components to a loosely coupled, highly reusable library. This will take time, and means components have to be adaptable over time + - Versioning is at the core of shui +- +- ## How to contribute to shui? +- In the logseq repo, there is a directory at `deps/shui`. Here you can find all of the shui components +- In the logseq repo, you can find a copy of this graph at `deps/shui/shui-graph`. Here you can find and add all the test cases needed for different `shui` components +- In the logseq repo, you can find tests under the `e2e-tests/shui`. To keep our infra streamlined, `shui` is bundled with and tested with the current CI for logseq \ No newline at end of file diff --git a/deps/shui/shui-graph/pages/Page 1.md b/deps/shui/shui-graph/pages/Page 1.md new file mode 100644 index 0000000000..41d91cdb9b --- /dev/null +++ b/deps/shui/shui-graph/pages/Page 1.md @@ -0,0 +1,3 @@ +table-example:: true + +- \ No newline at end of file diff --git a/deps/shui/shui-graph/pages/Page 2.md b/deps/shui/shui-graph/pages/Page 2.md new file mode 100644 index 0000000000..77faa066be --- /dev/null +++ b/deps/shui/shui-graph/pages/Page 2.md @@ -0,0 +1 @@ +table-example:: true diff --git a/deps/shui/shui-graph/pages/Page 3.md b/deps/shui/shui-graph/pages/Page 3.md new file mode 100644 index 0000000000..77faa066be --- /dev/null +++ b/deps/shui/shui-graph/pages/Page 3.md @@ -0,0 +1 @@ +table-example:: true diff --git a/deps/shui/shui-graph/pages/contents.md b/deps/shui/shui-graph/pages/contents.md new file mode 100644 index 0000000000..85b6529291 --- /dev/null +++ b/deps/shui/shui-graph/pages/contents.md @@ -0,0 +1,4 @@ +- [[About Shui]] +- [[shui/components]] + - [[shui/components/table]] + - \ No newline at end of file diff --git a/deps/shui/shui-graph/pages/shui___components.md b/deps/shui/shui-graph/pages/shui___components.md new file mode 100644 index 0000000000..9e90c08592 --- /dev/null +++ b/deps/shui/shui-graph/pages/shui___components.md @@ -0,0 +1,4 @@ +- Below is a list of components that can be found in the shui library +- [[shui/components/table]] + - The table component is used to render tabular data. +- \ No newline at end of file diff --git a/deps/shui/shui-graph/pages/shui___components___table.md b/deps/shui/shui-graph/pages/shui___components___table.md new file mode 100644 index 0000000000..6368f06a5a --- /dev/null +++ b/deps/shui/shui-graph/pages/shui___components___table.md @@ -0,0 +1,62 @@ +- ### Props + - logseq.table.version:: 2 + logseq.table.hover:: row + logseq.table.stripes:: true + logseq.table.borders:: false + | Prop Name | Description | Values | + | --- | --- | --- | + | `logseq.table.version` | The version of the table | 1, 2 | + | `logseq.table.hover` | The hover effect of the table | cell (default), row, col, both, none | + | `logseq.table.compact` | Whether to show a compact version of the data | false (default), true | + | `logseq.table.headers` | The casing that should be applied to the header cols | none (default), uppercase, capitalize, capitalize-first, lowercase | + | `logseq.table.borders` | Whether or not the table should have borders between all cells and rows | true (default), false | + | `logseq.table.stripes` | Whether or not the table should have alternately colored table rows | false (default), true | + | `logseq.table.max-width` | The maximum width (in rems) that should be applied to each column | (default 30) | + | `logseq.color` | The color accent of the table | red, orange, yellow, green, blue, purple | +- ### Examples + - #### Simplest possible markdown table + collapsed:: true + - logseq.table.version:: 1 + | Fruit | Color | + | Apples | Red | + | Bananas | Yellow | + - #### Longer more complicated markdown table, with various widths and input types + collapsed:: true + - logseq.table.version:: 2 + | Length | Text | EN | ZH | + | --- | --- | --- | --- | + | 70 | Logseq is a new note-taking app that has been making waves in the productivity community. | x | | + | 138 | With its unique approach to linking and organizing information, Logseq allows users to create a highly interconnected and personalized knowledge base. | x | | + | 194 | Unlike traditional note-taking apps, Logseq encourages users to embrace the power of plain text and markdown formatting, enabling them to easily manipulate and query their notes. | x | | + | 246 | From students to researchers, Logseq's flexible and intuitive interface makes it an ideal tool for anyone looking to optimize their note-taking and knowledge management workflow. | x | | + | 312 | Whether you're looking to organize your thoughts, collaborate with others, or simply streamline your note-taking process, Logseq offers a revolutionary approach that is sure to revolutionize the way you work. | x | | + | 35 | Logseq 是一款在生产力社群中备受瞩目的新型笔记应用。| | x | + | 59 | Logseq 以其独特的链接和组织信息方式,使用户能够创建高度互联且个性化的知识库。 | | x | 86 | 不同于传统笔记应用,Logseq 鼓励用户采用纯文本和 Markdown 格式,使其能够轻松地操作和查询笔记。 | | x | + | 123 | 从学生到研究人员,Logseq 灵活直观的界面使其成为任何想要优化笔记和知识管理工作流程的人的理想工具。| | x | + | 152 | 无论您是想整理自己的思路、与他人合作,还是简化笔记流程,Logseq 提供的革命性方法肯定会改变您的工作方式。| | x | + - #### Query table for blocks + - logseq.table.version:: 2 + query-table:: true + query-properties:: [:block] + logseq.table.borders:: false + {{query #table-example/block}} + - + - #### data + - Block 1 #table-example/block + table-example:: true + - Block 2 #table-example/block + table-example:: true + - Block 3 #table-example/block + table-example:: true + - #### Query table for pages + - {{query (page-property "table-example" "true")}} + logseq.table.version:: 2 + - [[Page 1]] + - [[Page 2]] + - [[Page 3]] + - #### Query table for mixed pages and blocks + - {{query (property "table-example" true)}} + query-table:: true + logseq.table.version:: 2 + - +- {{query }} \ No newline at end of file diff --git a/deps/shui/src/logseq/shui/context.cljs b/deps/shui/src/logseq/shui/context.cljs new file mode 100644 index 0000000000..fd3bbafe8c --- /dev/null +++ b/deps/shui/src/logseq/shui/context.cljs @@ -0,0 +1,36 @@ +(ns logseq.shui.context) + +(defn inline->inline-block [inline block-config] + (fn [_context item] + (inline block-config item))) + +(defn inline->map-inline-block [inline block-config] + (let [inline* (inline->inline-block inline block-config)] + (fn [context col] + (map #(inline* context %) col)))) + +(defn make-context [{:keys [block-config app-config inline int->local-time-2]}] + {;; Shui needs access to the global configuration of the application + :config app-config + ;; Until components are converted over, they need to fallback to the old inline function + ;; Wrap the old inline function to allow for interception, but fallback to the old inline function + :inline-block (inline->inline-block inline block-config) + :map-inline-block (inline->map-inline-block inline block-config) + ;; Currently frontend component are provided an object map containin at least the following keys: + ;; These will be passed through in a whitelisted fashion so as to be able to track the dependencies + ;; back to the core application + ;; TODO: document the following + :block (:block block-config) ;; the db entity of the current block + :block? (:block? block-config) + :blocks-container-id (:blocks-container-id block-config) + :editor-box (:editor-box block-config) + :id (:id block-config) + :mode? (:mode? block-config) + :query-result (:query-result block-config) + :sidebar? (:sidebar? block-config) + :start-time (:start-time block-config) + :uuid (:uuid block-config) + :whiteboard? (:whiteboard? block-config) + ;; Some functions from logseq's application will be used in the shui components. To avoid circular dependencies, + ;; they will be provided via the context object + :int->local-time-2 int->local-time-2}) diff --git a/deps/shui/src/logseq/shui/core.cljs b/deps/shui/src/logseq/shui/core.cljs new file mode 100644 index 0000000000..245d1e2373 --- /dev/null +++ b/deps/shui/src/logseq/shui/core.cljs @@ -0,0 +1,11 @@ +(ns logseq.shui.core + (:require + [logseq.shui.table.v2 :as shui.table.v2] + [logseq.shui.context :as shui.context])) + +;; table component +(def table shui.table.v2/root) +(def table-v2 shui.table.v2/root) + +;; context +(def make-context shui.context/make-context) diff --git a/deps/shui/src/logseq/shui/table/v2.cljs b/deps/shui/src/logseq/shui/table/v2.cljs new file mode 100644 index 0000000000..d84fc229e0 --- /dev/null +++ b/deps/shui/src/logseq/shui/table/v2.cljs @@ -0,0 +1,471 @@ +(ns logseq.shui.table.v2 + (:require + [clojure.string :as str] + [logseq.shui.util :refer [use-ref-bounding-client-rect use-dom-bounding-client-rect $main-content] :as util] + [rum.core :as rum])) + +(declare table-cell) + +(def COLORS #{"tomato" "red" "crimson" "pink" "plum" "purple" "violet" "indigo" "blue" "sky" "cyan" "teal" "mint" "green" "grass" "lime" "yellow" "amber" "orange" "brown"}) +(def MAX_WIDTH 30 #_rem) ;; Max width in rem for a single column +(def MIN_WIDTH 4 #_rem) ;; Min width in rem for a single column + +;; in order to make sure the tailwind classes are included, +;; the values are pulled from the classes via regex. +;; the return values are simply the numbers in the classes. +(def CELL_PADDING (->> "px-[0.75rem]" (re-find #"\d+\.?\d*") js/parseFloat)) +(def CELL_PADDING_COMPACT (->> "px-[0.25rem]" (re-find #"\d+\.?\d*") js/parseFloat)) +(def BORDER_WIDTH (->> "border-[1px]" (re-find #"\d+\.?\d*") js/parseFloat)) + +;; -- Helpers ------------------------------------------------------------------ + +(defn get-in-first + ([obj path] (get-in obj path)) + ([obj path & more] (get-in obj path (apply get-in-first obj more)))) + +(defn get-in-first-fallback + ([obj path] (get-in obj path)) + ([obj path fallback] (get-in obj path fallback)) + ([obj path path-b & more] (get-in obj path (apply get-in-first-fallback obj path-b more)))) + +(defn read-prop [value] + (case value + "false" false + "true" true + value)) + +(defn get-view-prop + "Get the config for a specified item. Can be overridden in blocks, specified in config, + fallback to default config, or fallback to the provided parameters" + ([context kw] + (read-prop + (get-in-first context [:block :properties kw] + [:block :block/properties kw] + [:config kw]))) + ([context kw fallback] + (read-prop + (get-in-first-fallback context [:block :properties kw] + [:block :block/properties kw] + [:config kw] + fallback)))) + +(defn color->gray [color] + (case color + ("tomato" "red" "crimson" "pink" "plum" "purple" "violet") "mauve" + ("indigo" "blue" "sky" "cyan") "slate" + ("teal" "mint" "green") "sage" + ("grass" "lime") "olive" + ("yellow" "amber" "orange" "brown") "sand" + nil)) + +(defn rdx + ([color step] (str "bg-" color "-" step)) + ([param color step] (str (name param) "-" color "-" step))) + ; ([color step] (str "bg-" color "dark-" step)) + ; ([param color step] (str param "-" color "dark-" step)))) + + ; --ls-primary-background-color: #fff; + ; --ls-secondary-background-color: #f8f8f8; + ; --ls-tertiary-background-color: #f2f2f3; + ; --ls-quaternary-background-color: #ebeaea)); + +(defn lsx + "This is a temporary bridge between the radix color grading and the + current logseq theming variables. Should set the prop to the given css variable" + ([step] (lsx :bg step)) + ([param step] + (case step + 1 ({"bg" "bg-[color:var(--ls-primary-background-color)]"} (name param)) + 2 ({"bg" "bg-[color:var(--ls-secondary-background-color)]"} (name param)) + 3 ({"bg" "bg-[color:var(--ls-tertiary-background-color)]"} (name param)) + 4 ({"bg" "bg-[color:var(--ls-quaternary-background-color)]"} (name param)) + 5 ({"bg" "bg-[color:var(--ls-quinary-background-color)]"} (name param)) + 6 ({"bg" "bg-[color:var(--ls-senary-background-color)]"} (name param)) + 7 ({"bg" "bg-[color:var(--ls-border-color)]" + "border" "border-[color:var(--ls-border-color)]"} (name param)) + 11 ({"text" "text-[color:var(--ls-secondary-text-color)]"} (name param)) + 12 ({"text" "text-[color:var(--ls-primary-text-color)]"} (name param))))) + +(defn varc [color step] + (str "var(--color-" color "-" step ")")) + +(defn last-str + "Given an inline AST, return the last string element you can walk to" + [inline] + (cond + (keyword? inline) (name inline) + (string? inline) inline + (coll? inline) (last-str (last inline)) + :else (pr-str inline))) + +(comment + (last-str "A") + (last-str ["Plain" "A"]) + (last-str [["Plain" "A"]]) + (last-str [["Plain" "A"] + [["Emphasis" [["Italic"] [["Plain" "B"]]]]]])) + +(defn render-cell-in-context + "Some instances of the table provide us with raw data, others provide us with + inline ASTs. This function renders the content appropriately, passing the AST along + to map-inline if necessary." + [{:keys [map-inline-block int->local-time-2]} cell-data] + (cond + (sequential? cell-data) (map-inline-block [:table :v2] cell-data) + (string? cell-data) cell-data + (keyword? cell-data) (name cell-data) + (boolean? cell-data) (pr-str cell-data) + (number? cell-data) (if-let [date (int->local-time-2 cell-data)] + date cell-data))) + +(defn map-with-all-indices [data] + (let [!row-index (volatile! -1)] + (for [[group-index group] (map-indexed vector data) + [group-row-index row] (map-indexed vector group) + :let [row-index (vswap! !row-index inc)]] + [group-index group-row-index row-index group row]))) + +(defn get-columns [block data] + (->> (or (some-> (get-in block [:block/properties :logseq.table.cols]) + (str/split #", ?")) + (map last-str (ffirst data))) + (map (comp str/lower-case str/trim)))) + +(defn cell-bg-classes + "We track the cell the cursor last entered and update the cells according to the configured + hover preference: cell, row, col, both, or none. + We also have to account for the header cells and stripes cells" + [{:keys [row-index col-index hover header? gray color stripes? cursor]}] + (let [;; check how the cursor position overlaps with the current cell + row-highlighted? (= row-index (second cursor)) + col-highlighted? (= col-index (first cursor)) + cell-highlighted? (and row-highlighted? col-highlighted?) + ;; check how the cell needs to be highlighted + highlight-row? (and row-highlighted? (#{"row" "both"} hover)) + highlight-col? (and col-highlighted? (#{"col" "both"} hover)) + highlight-cell? (and cell-highlighted? (#{"cell" "row" "col" "both"} hover))] + (cond + highlight-cell? (if header? (lsx 6) (lsx 4)) + highlight-row? (if header? (lsx 5) (lsx 3)) + highlight-col? (if header? (lsx 5) (lsx 3)) + header? (lsx 4) + (and stripes? (even? row-index)) (lsx 2) + :else (lsx 1)))) + +(defn cell-rounded-classes + "Depending on where the cell is, and whether there is a gradient accent, we need to round specific corners + The cond-> is used to account for single row or single column talbes that may have multiple rounded corners." + [{:keys [color row-index col-index total-rows total-cols]}] + (let [no-gradient-accent? (nil? color)] + (cond-> "" + (and no-gradient-accent? (= [row-index col-index] [0 0])) (str " rounded-tl") + (and no-gradient-accent? (= [row-index col-index] [0 (dec total-cols)])) (str " rounded-tr") + (= [row-index col-index] [(dec total-rows) 0]) (str " rounded-bl") + (= [row-index col-index] [(dec total-rows) (dec total-cols)]) (str " rounded-br")))) + +(defn cell-text-transform-classes [{:keys [headers header?]}] + (when header? + (cond-> (get #{"uppercase" "capitalize" "lowercase" "none" "capitalize-first"} headers "none") + (= headers "capitalize-first") (str " lowercase")))) + +(defn cell-padding-classes [{:keys [compact? header?]}] + (cond + #_compact_th (and compact? header?) (str "px-[" CELL_PADDING_COMPACT "rem] py-0.5") + #_compact_td compact? (str "px-[" CELL_PADDING_COMPACT "rem] py-0.5") + #_padded_th header? (str "px-[" CELL_PADDING "rem] py-1.5") + #_padded_td :else (str "px-[" CELL_PADDING "rem] py-2"))) + +(defn cell-text-classes [{:keys [header?]}] + (if header? + (str (lsx :text 11) " text-sm tracking-wide font-bold") + (str (lsx :text 12) " text-base"))) + +(defn cell-classes [table-opts] + (str/join " " + [(cell-bg-classes table-opts) + (cell-rounded-classes table-opts) + (cell-text-classes table-opts) + (cell-text-transform-classes table-opts) + (cell-padding-classes table-opts)])) + +;; -- Handlers ----------------------------------------------------------------- + +(defn handle-cell-pointer-down [e {:keys [cell-focus col-index row-index]}] + (when (not= cell-focus [col-index row-index]) + (.stopPropagation e) + (.preventDefault e))) + +(defn handle-cell-click + "When a cell is clicked, we need to update the cursor position and the selected cells" + [e {:keys [cell-focus set-cell-focus header? col-index row-index]} cell-ref] + ; (.stopPropagation e) + (.preventDefault e) + (when-not (= cell-focus [col-index row-index]) + (set-cell-focus [col-index row-index]))) + + +(defn handle-cell-keydown + "When a cell is focused, we need to update the cursor position and the selected cells" + [e {:keys [cell-focus set-cell-focus header? col-index row-index total-rows total-cols]}] + (when (= cell-focus [col-index row-index]) + (and (case (.-key e) + "ArrowUp" (if (= row-index 0) + (set-cell-focus [col-index row-index]) + (set-cell-focus [col-index (dec row-index)])) + "ArrowDown" (if (= row-index (dec total-rows)) + (set-cell-focus [col-index row-index]) + (set-cell-focus [col-index (inc row-index)])) + "ArrowLeft" (cond + ;; if we are in the top left, then do not move the focus + (and (= col-index 0) (= row-index 0)) + (set-cell-focus [col-index row-index]) + ;; if we are in the first column, then move to the last column of the previous row + (= col-index 0) + (set-cell-focus [(dec total-cols) (dec row-index)]) + ;; otherwise, move to the previous column + :else + (set-cell-focus [(dec col-index) row-index])) + "ArrowRight" (cond + ;; if we are in the bottom right, then do not move the focus + (and (= col-index (dec total-cols)) (= row-index (dec total-rows))) + (set-cell-focus [col-index row-index]) + ;; if we are in the last column, then move to the first column of the next row + (= col-index (dec total-cols)) + (set-cell-focus [0 (inc row-index)]) + ;; otherwise, move to the next column + :else + (set-cell-focus [(inc col-index) row-index])) + nil) + ;; Prevent default actions when the table handles it itself + (.preventDefault e) + (.stopPropagation e)))) + + +;; -- Hooks -------------------------------------------------------------------- + +(defn use-atom + "A hook that wraps use-state to allow for interaction with + the state as if it were an atom" + [initial-value] + (let [atom-ref (rum/use-ref (atom initial-value)) + atom-current (.. atom-ref -current) + [state set-state] (rum/use-state initial-value)] + (rum/use-effect! (fn [] + (set-state @atom-current) + identity) + [atom-current]) + [state atom-current])) + +(defn use-dynamic-widths [data] + (let [[static atomic] (use-atom {}) + add-column-width (fn [col-index width] + (when (< (get @atomic col-index 0) (min MAX_WIDTH width)) + (swap! atomic assoc col-index (min MAX_WIDTH width)) + ;; rum is complaining that we can only return teardown functions + identity))] + ;; Reset the minimum widths when the data changes + (rum/use-effect! (fn [] (reset! atomic {}) identity) + [data]) + [static add-column-width])) + +(defn use-table-flow-at-width [table-px max-cols-px] + (let [[overflow set-overflow] (rum/use-state false) + [underflow set-underflow] (rum/use-state false) + handle-container-width (fn [container-px] + (set-underflow (< max-cols-px container-px)) + (set-overflow (< container-px table-px)))] + [overflow underflow handle-container-width])) + +;; -- Components (V2) ----------------------------------------------------------- + +(rum/defc table-scrollable-overflow [handle-root-width-change child] + (let [[set-root-ref root-rect root-ref] (use-ref-bounding-client-rect) + main-content-rect (use-dom-bounding-client-rect ($main-content)) + + left-adjustment (- (:left root-rect) (:left main-content-rect)) + right-adjustment (- (:width main-content-rect) + (- (:right root-rect) (:left main-content-rect))) + + ;; Because in a scrollable container, we need to account for the scrollbar being clicked, + ;; we add a handler to prevent the table from switching to the input on click. + ;; This also prevents the table from switching to eiditng mode when the left or right area + ;; of the table is clicked, but that feels natural to me. + handle-pointer-down (fn [e] + (when (= root-ref (.. e -target -parentElement)) + (.preventDefault e)))] + (rum/use-effect! #(handle-root-width-change (:width root-rect)) [(:width root-rect)]) + [:div {:ref set-root-ref} + [:div {:style {:width (:width main-content-rect) + :margin-left (- (:left main-content-rect) (:left root-rect)) + :padding-left left-adjustment + :padding-right right-adjustment + :overflow-x "scroll"} + :class "mt-2" + :on-pointer-down handle-pointer-down} + child]])) + +(rum/defc table-gradient-accent [{:keys [color]}] + [:div.rounded-t.h-2.-ml-px.-mt-px.-mr-px + {:style {:grid-column "1 / -1" :order -999} + :class (str "grad-bg-" color "-9") + :data-testid "v2-table-gradient-accent"}]) + +(rum/defc table-header-row [handle-cell-width-change cells {:keys [cell-col-map] :as opts}] + [:<> + (for [[cell-index cell] (map-indexed vector cells) + :let [col-index (get cell-col-map cell-index)] + :when col-index] + ^{:key cell-index} + (table-cell handle-cell-width-change cell (assoc opts :cell-index cell-index :col-index col-index :header? true)))]) + +(rum/defc table-data-row [handle-cell-width-change cells {:keys [cell-col-map] :as opts}] + [:<> + (for [[cell-index cell] (map-indexed vector cells) + :let [col-index (get cell-col-map cell-index)] + :when col-index] + ^{:key cell-index} + (table-cell handle-cell-width-change cell (assoc opts :cell-index cell-index :col-index col-index)))]) + +(rum/defc table-cell [handle-cell-width-change cell {:keys [row-index col-index render-cell show-separator? total-cols set-cell-hover cell-focus table-underflow?] :as opts}] + (let [cell-ref (rum/use-ref nil) + cell-order (+ (* row-index total-cols) col-index) + static-width (get-in opts [:static-widths col-index]) + dynamic-width (when-not static-width + (get-in opts [:dynamic-widths col-index]))] + ;; Whenever the cell changes, we need to calculate new bounds for the given content + ;; -innerText is used here to strip out formatting, this may turn out to not work for all given block types + (rum/use-layout-effect! #(->> (.. cell-ref -current -innerText) + (count) + (handle-cell-width-change col-index)) + [cell]) + + ;; Whenever the cell becomes focused, we set it's tabIndex. When the tabIndex is set, call focus on the element + (rum/use-layout-effect! #(when (= cell-focus [col-index row-index]) + ; (.. cell-ref -current -tabIndex 0) + (some-> cell-ref .-current .focus)) + ; (.execCommand js/document "selectAll")) + [cell-focus]) + [:div {:ref cell-ref + :class (cell-classes opts) + :style (cond-> {:box-sizing :border-box} + (not table-underflow?) (assoc :max-width (str MAX_WIDTH "rem")) + static-width (assoc :width (str static-width "rem")) + dynamic-width (assoc :min-width (str (max MIN_WIDTH dynamic-width) "rem")) + cell-order (assoc :order cell-order) + show-separator? (assoc :margin-top 3)) + :tab-index (when (= cell-focus [col-index row-index]) "-1") + :on-pointer-enter #(set-cell-hover [col-index row-index]) + :on-click #(handle-cell-click % opts cell-ref) + :on-pointer-down #(handle-cell-pointer-down % opts) + ; :on-pointer-up handle-cell-interrupt + :on-key-down #(handle-cell-keydown % opts)} + (render-cell cell)])) + +(rum/defc table-container [{:keys [columns borders? table-overflow? total-table-width gray set-cell-hover] :as opts} & children] + (let [grid-template-columns (str "repeat(" (count columns) ", minmax(max-content, 1fr))")] + [:div.grid.border.rounded {:style {:grid-template-columns grid-template-columns + :gap (when borders? BORDER_WIDTH) + :width (when table-overflow? total-table-width)} + :class (str (lsx 7) " " (lsx :border 7)) + :data-testid "v2-table-container" + :on-pointer-leave #(set-cell-hover [])} + children])) + +(rum/defc root + [{:keys [data] :as _props} {:keys [block] :as context}] + (let [;; In order to highlight cells in the same row or column of the hovered cell, + ;; we need to know the row and column that the cursor is in + [[_cell-hover-x _cell-hover-y :as cell-hover] set-cell-hover] (rum/use-state []) + [[_cell-focus-x _cell-focus-y :as cell-focus] set-cell-focus] (rum/use-state []) + + ;; Depending on the content of the table, we roughly adjust the width of the column + ;; to do this we need to keep track of the .innerText.length of each cell and update + ;; it whenever it changes + [dynamic-widths handle-cell-width-change] (use-dynamic-widths data) + + ;; We need to call into the view config several times, so we can memoize it + ;; TODO: insert global config here + get-view-prop* (partial get-view-prop context) + + ;; Most of the config options will be repeated and reused throughout the table, so store + ;; all of it's state in a single map for consistency + table-opts {; user configurable properties (sometimes with defaults) + :color (get-view-prop* :logseq.color) + :headers (get-view-prop* :logseq.table.headers "none") + :borders? (get-view-prop* :logseq.table.borders true) + :compact? (get-view-prop* :logseq.table.compact false) + :hover (get-view-prop* :logseq.table.hover "cell") + :stripes? (get-view-prop* :logseq.table.stripes false) + :gray (color->gray (get-in context [:config :logseq.color])) + :columns (get-columns block data) + + ; non configurable properties + :cell-hover cell-hover + :cell-focus cell-focus + :cursor (or (not-empty cell-focus) (not-empty cell-hover)) + :dynamic-widths dynamic-widths + :render-cell (partial render-cell-in-context context) + :set-cell-hover set-cell-hover + :set-cell-focus set-cell-focus + :total-rows (reduce + 0 (map count data))} + + ;; The total table width has to account for the borders and the padding + ;; everything is tracked in rems, except for the border, since it's so small + cell-padding-width (* 2 (if (:compact? table-opts) CELL_PADDING_COMPACT CELL_PADDING)) + total-border-width (* (count (:columns table-opts)) BORDER_WIDTH) + total-table-width (->> (vals dynamic-widths) + (map (partial + cell-padding-width)) + (reduce + 0) + (util/rem->px) + (+ total-border-width)) + total-max-col-width (-> (count (:columns table-opts)) + (* MAX_WIDTH) + (util/rem->px) + (+ total-border-width)) + + ;; The table is actually rendered differently when it needs to be scrollable. + ;; Keep track of whether the ideal table size overflows it's container size, + ;; and provide a handler to be called whenever the container width changes + [table-overflow? table-underflow? handle-root-width-change] (use-table-flow-at-width total-table-width total-max-col-width) + + ;; Because the data may come in a different order than it should be presented, + ;; we need to distinguish between these and provide a conversion. + ;; The order the data is stored in is referred to as the cell order. + ;; The order the data is displayed as is referred to as the col order. + ;; Since these are called on every render of every cell, and are not dynamic, they are computed up front + cell-col-map (->> (ffirst data) + (map-indexed (juxt #(identity %1) + #(.indexOf (:columns table-opts) (.toLowerCase (last-str %2))))) + (remove (comp #{-1} second)) + (into {})) + + ;; There are a couple more computed table properties that are best calculated + ;; after the initial object is creaated + table-opts (assoc table-opts :total-cols (count (:columns table-opts)) + :total-table-width total-table-width + :table-overflow? table-overflow? + :table-underflow? table-underflow? + :cell-col-map cell-col-map)] + ; (js/console.log "shui table opts context" (clj->js context)) + ; (js/console.log "shui table opts" (clj->js table-opts)) + ; (js/console.log "shui table opts" (pr-str table-opts)) + ;; Scrollable Container: if the table is larger than the container, manage the scrolling effects here + (table-scrollable-overflow handle-root-width-change + ;; Grid Container: control the outermost table related element (border radius, grid, etc) + (table-container table-opts + ;; Gradient Accent: the accent color at the top of the application + (when (:color table-opts) + (table-gradient-accent table-opts)) + ;; Rows: the actual table rows + (for [[group-index group-row-index row-index _group row] (map-with-all-indices data) + :let [show-separator? (and (= 0 group-row-index) (< 1 group-index)) + opts (assoc table-opts :group-index group-index + :group-row-index group-row-index + :row-index row-index + :show-separator? show-separator?)]] + (if (= 0 group-index) + ;; Table Header: Rows in the first section are rendered as headers + ^{:key row-index} (table-header-row handle-cell-width-change row opts) + ;; Table Body: The rest of the data is rendered as cells + ^{:key row-index} (table-data-row handle-cell-width-change row opts))))))) + diff --git a/deps/shui/src/logseq/shui/util.cljs b/deps/shui/src/logseq/shui/util.cljs new file mode 100644 index 0000000000..c0e33fac77 --- /dev/null +++ b/deps/shui/src/logseq/shui/util.cljs @@ -0,0 +1,81 @@ +(ns logseq.shui.util + (:require + [clojure.string :as s] + [rum.core :refer [use-state use-effect!] :as rum] + [goog.dom :as gdom])) + + +;; /--------------- app ------------\ +;; /-------- left --------\ \ +;; /l-side\ \ /- r-side --\ +;; +;; |--------|-------------------|-------------| \ head +;; |--------|-------------------| | / +;; | | | | +;; | | | | +;; | | | | +;; |--------|-------------------|-------------| + +(def $app (partial gdom/getElement "app-container")) +(def $left (partial gdom/getElement "left-container")) +(def $head (partial gdom/getElement "head-container")) +(def $main (partial gdom/getElement "main-container")) +(def $main-content (partial gdom/getElement "main-content-container")) +(def $left-sidebar (partial gdom/getElement "left-sidebar")) +(def $right-sidebar (partial gdom/getElement "right-sidebar")) + +(defn el->clj-rect [el] + (let [rect (.getBoundingClientRect el)] + {:top (.-top rect) + :left (.-left rect) + :bottom (.-bottom rect) + :right (.-right rect) + :width (.-width rect) + :height (.-height rect) + :x (.-x rect) + :y (.-y rect)})) + +(defn clj-rect-observer [update!] + (js/ResizeObserver. + (fn [entries] + (when (.-contentRect (first (js->clj entries))) + (update!))))) + +(defn use-dom-bounding-client-rect + ([el] (use-dom-bounding-client-rect el nil)) + ([el tick] + (let [[rect set-rect] (rum/use-state nil)] + (rum/use-effect! + (if el + (fn [] + (let [update! #(set-rect (el->clj-rect el)) + observer (clj-rect-observer update!)] + (update!) + (.observe observer el) + #(.disconnect observer))) + #()) + [el tick]) + rect))) + +(defn use-ref-bounding-client-rect + ([] (use-ref-bounding-client-rect nil)) + ([tick] + (let [[ref set-ref] (rum/use-state nil) + rect (use-dom-bounding-client-rect ref tick)] + [set-ref rect ref])) + ([ref tick] [nil (use-dom-bounding-client-rect ref tick)])) + + +(defn rem->px [rem] + (-> js/document.documentElement + js/getComputedStyle + (.-fontSize) + (js/parseFloat) + (* rem))) + +(defn px->rem [px] + (->> js/document.documentElement + js/getComputedStyle + (.-fontSize) + (js/parseFloat) + (/ px))) diff --git a/e2e-tests/shui/table.spec.js b/e2e-tests/shui/table.spec.js new file mode 100644 index 0000000000..4d4c73bc67 --- /dev/null +++ b/e2e-tests/shui/table.spec.js @@ -0,0 +1,304 @@ +import { expect } from '@playwright/test' +import fs from 'fs/promises' +import path from 'path' +import { test } from '../fixtures' +import { randomString, editFirstBlock, navigateToStartOfBlock, createRandomPage } from '../utils' + +test.setTimeout(60000) + +const KEY_DELAY = 100 + +// The following function assumes that the block is currently in edit mode, +// and it just enters a simple table +const inputSimpleTable = async (page) => { + await page.keyboard.type('| Header A | Header B |') + await page.keyboard.press('Shift+Enter') + await page.keyboard.type('| A1 | B1 |') + await page.keyboard.press('Shift+Enter') + await page.keyboard.type('| A2 | B2 |') + await page.keyboard.press('Escape') + await page.waitForTimeout(KEY_DELAY) +} + +// The following function does not assume any state, and will prepend the provided lines to the +// first block of the document +const prependPropsToFirstBlock = async (page, block, ...props) => { + await editFirstBlock(page) + await page.waitForTimeout(KEY_DELAY) + await navigateToStartOfBlock(page, block) + await page.waitForTimeout(KEY_DELAY) + + for (const prop of props) { + await page.keyboard.type(prop) + await page.waitForTimeout(KEY_DELAY) + await page.keyboard.press('Shift+Enter') + await page.waitForTimeout(KEY_DELAY) + } + + await page.keyboard.press('Escape') + await page.waitForTimeout(KEY_DELAY) +} + +const setPropInFirstBlock = async (page, block, prop, value) => { + await editFirstBlock(page) + await page.waitForTimeout(KEY_DELAY) + await navigateToStartOfBlock(page, block) + await page.waitForTimeout(KEY_DELAY) + + const inputValue = await page.inputValue('textarea >> nth=0') + + const match = inputValue.match(new RegExp(`${prop}::(.*)(\n|$)`)) + + if (!match) { + await page.keyboard.press('Shift+Enter') + await page.waitForTimeout(KEY_DELAY) + await page.keyboard.press('ArrowUp') + await page.waitForTimeout(KEY_DELAY) + await page.keyboard.type(`${prop}:: ${value}`) + // await page.waitForTimeout(1000) + // await page.waitForTimeout(KEY_DELAY) + // await page.keyboard.type(prop + ':: ' + value) + // await page.waitForTimeout(1000) + // await page.keyboard.press('Shift+Enter') + await page.waitForTimeout(KEY_DELAY) + await page.keyboard.press('Escape') + return await page.waitForTimeout(KEY_DELAY) + } + + const [propLine, propValue, propTernary] = match + const startIndex = match.index + const endIndex = startIndex + propLine.length - propTernary.length + + // Go to the of the prop + for (let i = 0; i < endIndex; i++) { + await page.keyboard.press('ArrowRight') + } + + // Delete the value of the prop + for (let i = 0; i < propValue.length; i++) { + await page.keyboard.press('Backspace') + } + + // Input the new value of the prop + await page.keyboard.type(" " + value.trim()) + await page.waitForTimeout(KEY_DELAY) + await page.keyboard.press('Escape') + return await page.waitForTimeout(KEY_DELAY) +} + + +test('table can have it\'s version changed via props', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a v1 table + inputSimpleTable(page) + + // find and confirm existence of first data cell + await expect(await page.locator('table tbody tr >> nth=0').innerHTML()).toContain('A1') + + // change to a version 2 table + await setPropInFirstBlock(page, block, 'logseq.table.version', '2') + + // find and confirm existence of first data cell in new format + await expect(await page.getByTestId('v2-table-container').innerHTML()).toContain('A1
') +}) + +test('table can configure logseq.color::', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a v1 table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + + // check for default general config + await expect(await page.getByTestId('v2-table-gradient-accent')).not.toBeVisible() + + await setPropInFirstBlock(page, block, 'logseq.color', 'red') + + // check for gradient accent + await expect(await page.getByTestId('v2-table-gradient-accent')).toBeVisible() +}) + +test('table can configure logseq.table.hover::', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a v1 table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + + await page.waitForTimeout(KEY_DELAY) + await page.getByText('A1', { exact: true }).hover() + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]') + await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + + await setPropInFirstBlock(page, block, 'logseq.table.hover', 'row') + + await page.waitForTimeout(KEY_DELAY) + await page.getByText('A1', { exact: true }).hover() + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]') + await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + + await setPropInFirstBlock(page, block, 'logseq.table.hover', 'col') + + await page.waitForTimeout(KEY_DELAY) + await page.getByText('A1', { exact: true }).hover() + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]') + await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + + await setPropInFirstBlock(page, block, 'logseq.table.hover', 'both') + + await page.waitForTimeout(KEY_DELAY) + await page.getByText('A1', { exact: true }).hover() + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]') + await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + + await setPropInFirstBlock(page, block, 'logseq.table.hover', 'none') + + await page.waitForTimeout(KEY_DELAY) + await page.getByText('A1', { exact: true }).hover() + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-quaternary-background-color)]') + await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') + await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]') +}) + +test('table can configure logseq.table.headers', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + + // Check none (default) + await expect(await page.getByText('Header A', { exact: true })).toBeVisible() + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A") + + // Check none (explicit) + await setPropInFirstBlock(page, block, 'logseq.table.headers', 'none') + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A") + + // Check uppercase + await setPropInFirstBlock(page, block, 'logseq.table.headers', 'uppercase') + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("HEADER A") + + // Check lowercase + await setPropInFirstBlock(page, block, 'logseq.table.headers', 'lowercase') + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("header a") + + // Check capitalize + await setPropInFirstBlock(page, block, 'logseq.table.headers', 'capitalize') + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A") + + // Check capitalize-first + await setPropInFirstBlock(page, block, 'logseq.table.headers', 'capitalize-first') + await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header a") +}) + +test('table can configure logseq.table.borders', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + + // Check true (default) + await expect(await page.getByTestId('v2-table-container')).toHaveCSS("gap", /^[1-9].*/) + + // Check true (explicit) + await setPropInFirstBlock(page, block, 'logseq.table.borders', 'true') + await expect(await page.getByTestId('v2-table-container')).toHaveCSS("gap", /^[1-9].*/) + + // Check false + await setPropInFirstBlock(page, block, 'logseq.table.borders', 'false') + await expect(await page.getByTestId('v2-table-container')).not.toHaveCSS("gap", /^[1-9].*/) +}) + +test('table can configure logseq.table.stripes', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + await page.waitForTimeout(KEY_DELAY) + + // Check false (default) + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]") + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]") + + // Check false (explicit) + await setPropInFirstBlock(page, block, 'logseq.table.stripes', 'false') + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]") + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]") + + // Check false + await setPropInFirstBlock(page, block, 'logseq.table.stripes', 'true') + await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]") + await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-secondary-background-color)]") +}) + +test('table can configure logseq.table.compact', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + await page.waitForTimeout(KEY_DELAY) + + // Check false (default) + const defaultClasses = await page.getByText('A1', { exact: true }).getAttribute('class') + + // Check false (explicit) + await setPropInFirstBlock(page, block, 'logseq.table.compact', 'false') + const falseClasses = await page.getByText('A1', { exact: true }).getAttribute('class') + + // Check false + await setPropInFirstBlock(page, block, 'logseq.table.compact', 'true') + const trueClasses = await page.getByText('A1', { exact: true }).getAttribute('class') + + const getPX = (str) => { + const match = str.match(/px-\[([0-9\.]*)[a-z]*\]/) + return match ? parseFloat(match[1]) : null + } + + await expect(getPX(defaultClasses)).toEqual(getPX(falseClasses)) + await expect(getPX(defaultClasses)).toBeGreaterThan(getPX(trueClasses)) +}) + +test('table can configure logseq.table.cols::', async ({ page, block, graphDir }) => { + const pageTitle = await createRandomPage(page) + + // create a v1 table + await page.keyboard.type('logseq.table.version:: 2') + await page.keyboard.press('Shift+Enter') + await inputSimpleTable(page) + + // check for default general config + await expect(await page.getByText('A1', { exact: true })).toBeVisible() + await expect(await page.getByText('B1', { exact: true })).toBeVisible() + + await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header A, Header B') + await expect(await page.getByText('A1', { exact: true })).toBeVisible() + await expect(await page.getByText('B1', { exact: true })).toBeVisible() + + await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header A') + await expect(await page.getByText('A1', { exact: true })).toBeVisible() + await expect(await page.getByText('B1', { exact: true })).not.toBeVisible() + + await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header B') + await expect(await page.getByText('A1', { exact: true })).not.toBeVisible() + await expect(await page.getByText('B1', { exact: true })).toBeVisible() +}) diff --git a/e2e-tests/utils.ts b/e2e-tests/utils.ts index 5abff4220a..503ea7d638 100644 --- a/e2e-tests/utils.ts +++ b/e2e-tests/utils.ts @@ -206,3 +206,10 @@ export async function getIsWebAPIClipboardSupported(page: Page): Promiseblock-ref id)])) - [:span.warning.mr-1 {:title "Block ref invalid"} - (block-ref/->block-ref id)])) + [:span.warning.mr-1 {:title "Block ref invalid"} + (block-ref/->block-ref id)])) (defn inline-text ([format v] @@ -1106,8 +1108,8 @@ {:href (path/path-join "file://" path) :data-href path :target "_blank"} - title - (assoc :title title)) + title + (assoc :title title)) (map-inline config label))) :else @@ -1200,8 +1202,8 @@ (cond-> {:href (ar-url->http-url href) :target "_blank"} - title - (assoc :title title)) + title + (assoc :title title)) (map-inline config label)) :else @@ -1210,11 +1212,11 @@ (cond-> {:href href :target "_blank"} - title - (assoc :title title)) + title + (assoc :title title)) (map-inline config label))))))) -(declare ->hiccup) +(declare ->hiccup inline) (defn wrap-query-components [config] @@ -1223,7 +1225,8 @@ :->elem ->elem :page-cp page-cp :inline-text inline-text - :map-inline map-inline})) + :map-inline map-inline + :inline inline})) ;;;; Macro component render functions (defn- macro-query-cp @@ -2247,7 +2250,7 @@ (and (not block-content?) (seq (:block/children block)) (= move-to :nested))) - (dnd-separator move-to block-content?)))))) + (dnd-separator move-to block-content?)))))) (defn clock-summary-cp [block body] @@ -2312,19 +2315,19 @@ content (if (string? content) (string/trim content) "") mouse-down-key (if (util/ios?) :on-click - :on-mouse-down ; TODO: it seems that Safari doesn't work well with on-mouse-down - ) + :on-mouse-down) ; TODO: it seems that Safari doesn't work well with on-mouse-down + attrs (cond-> {:blockid (str uuid) :data-type (name block-type) :style {:width "100%" :pointer-events (when stop-events? "none")}} - (not (string/blank? (:hl-color properties))) - (assoc :data-hl-color (:hl-color properties)) + (not (string/blank? (:hl-color properties))) + (assoc :data-hl-color (:hl-color properties)) - (not block-ref?) - (assoc mouse-down-key (fn [e] - (block-content-on-mouse-down e block block-id content edit-input-id))))] + (not block-ref?) + (assoc mouse-down-key (fn [e] + (block-content-on-mouse-down e block block-id content edit-input-id))))] [:div.block-content.inline (cond-> {:id (str "block-content-" uuid) :on-mouse-up (fn [e] @@ -3002,8 +3005,8 @@ :li (cond-> {:checked checked?} - number - (assoc :value number)) + number + (assoc :value number)) (vec-cat [(->elem :p @@ -3021,52 +3024,55 @@ (defn table [config {:keys [header groups col_groups]}] - (let [tr (fn [elm cols] - (->elem - :tr - (mapv (fn [col] - (->elem - elm - {:scope "col" - :class "org-left"} - (map-inline config col))) - cols))) - tb-col-groups (try - (mapv (fn [number] - (let [col-elem [:col {:class "org-left"}]] - (->elem - :colgroup - (repeat number col-elem)))) - col_groups) - (catch :default _e - [])) - head (when header - [:thead (tr :th header)]) - groups (mapv (fn [group] - (->elem - :tbody - (mapv #(tr :td %) group))) - groups)] - [:div.table-wrapper - (->elem - :table - {:class "table-auto" - :border 2 - :cell-spacing 0 - :cell-padding 6 - :rules "groups" - :frame "hsides"} - (vec-cat - tb-col-groups - (cons head groups)))])) + (case (get-shui-component-version :table config) + 2 (shui/table-v2 {:data (concat [[header]] groups)} + (make-shui-context config inline)) + 1 (let [tr (fn [elm cols] + (->elem + :tr + (mapv (fn [col] + (->elem + elm + {:scope "col" + :class "org-left"} + (map-inline config col))) + cols))) + tb-col-groups (try + (mapv (fn [number] + (let [col-elem [:col {:class "org-left"}]] + (->elem + :colgroup + (repeat number col-elem)))) + col_groups) + (catch :default _e + [])) + head (when header + [:thead (tr :th header)]) + groups (mapv (fn [group] + (->elem + :tbody + (mapv #(tr :td %) group))) + groups)] + [:div.table-wrapper + (->elem + :table + {:class "table-auto" + :border 2 + :cell-spacing 0 + :cell-padding 6 + :rules "groups" + :frame "hsides"} + (vec-cat + tb-col-groups + (cons head groups)))]))) (defn logbook-cp [log] (let [clocks (filter #(string/starts-with? % "CLOCK:") log) - clocks (reverse (sort-by str clocks)) + clocks (reverse (sort-by str clocks))] ;; TODO: display states change log ; states (filter #(not (string/starts-with? % "CLOCK:")) log) - ] + (when (seq clocks) (let [tr (fn [elm cols] (->elem :tr (mapv (fn [col] (->elem elm col)) cols))) @@ -3091,6 +3097,8 @@ [config col] (map #(inline config %) col)) +(declare ->hiccup) + (rum/defc src-cp < rum/static [config options html-export?] (when options diff --git a/src/main/frontend/components/query.cljs b/src/main/frontend/components/query.cljs index 4404610a45..cdd9e789fc 100644 --- a/src/main/frontend/components/query.cljs +++ b/src/main/frontend/components/query.cljs @@ -50,7 +50,7 @@ view-f result group-by-page?]}] - (let [{:keys [->hiccup ->elem inline-text page-cp map-inline]} config + (let [{:keys [->hiccup ->elem inline-text page-cp map-inline inline]} config *query-error query-error-atom only-blocks? (:block/uuid (first result)) blocks-grouped-by-page? (and group-by-page? @@ -59,6 +59,7 @@ (:block/name (ffirst result)) (:block/uuid (first (second (first result)))) true)] + (println "this should be a function" inline) (if @*query-error (do (log/error :exception @*query-error) @@ -77,10 +78,10 @@ (util/hiccup-keywordize result)) page-list? - (query-table/result-table config current-block result {:page? true} map-inline page-cp ->elem inline-text) + (query-table/result-table config current-block result {:page? true} map-inline page-cp ->elem inline-text inline) table? - (query-table/result-table config current-block result {:page? false} map-inline page-cp ->elem inline-text) + (query-table/result-table config current-block result {:page? false} map-inline page-cp ->elem inline-text inline) (and (seq result) (or only-blocks? blocks-grouped-by-page?)) (->hiccup result diff --git a/src/main/frontend/components/query_table.cljs b/src/main/frontend/components/query_table.cljs index 9705eae2ac..9283803fd6 100644 --- a/src/main/frontend/components/query_table.cljs +++ b/src/main/frontend/components/query_table.cljs @@ -3,13 +3,15 @@ [frontend.date :as date] [frontend.db :as db] [frontend.db.query-dsl :as query-dsl] + [frontend.format.block :as block] [frontend.handler.common :as common-handler] [frontend.handler.editor.property :as editor-property] + [frontend.shui :refer [get-shui-component-version make-shui-context]] [frontend.state :as state] [frontend.util :as util] [frontend.util.clock :as clock] [frontend.util.property :as property] - [frontend.format.block :as block] + [logseq.shui.core :as shui] [medley.core :as medley] [rum.core :as rum] [logseq.graph-parser.text :as text])) @@ -42,9 +44,9 @@ (defn- locale-compare "Use locale specific comparison for strings and general comparison for others." [x y] - (if (and (number? x) (number? y)) - (< x y) - (.localeCompare (str x) (str y) (state/sub :preferred-language) #js {:numeric true}))) + (if (and (number? x) (number? y)) + (< x y) + (.localeCompare (str x) (str y) (state/sub :preferred-language) #js {:numeric true}))) (defn- sort-result [result {:keys [sort-by-column sort-desc? sort-nlp-date? page?]}] (if (some? sort-by-column) @@ -98,7 +100,7 @@ keys (if page? (distinct (concat keys [:created-at :updated-at])) keys)] keys)) -(defn- get-columns [current-block result {:keys [page?]}] +(defn get-columns [current-block result {:keys [page?]}] (let [query-properties (some-> (get-in current-block [:block/properties :query-properties] "") (common-handler/safe-read-string "Parsing query properties failed")) query-properties (if page? (remove #{:block} query-properties) query-properties) @@ -152,10 +154,21 @@ ;; Fallback to original properties for page blocks (get-in row [:block/properties column])))])) +(defn build-column-text [row column] + (case column + :page (or (get-in row [:block/page :block/original-name]) + (get-in row [:block/original-name]) + (get-in row [:block/content])) + :block (or (get-in row [:block/original-name]) + (get-in row [:block/content])) + (or (get-in row [:block/properties column]) + (get-in row [:block/properties-text-values column]) + (get-in row [(keyword :block column)])))) + (rum/defcs result-table < rum/reactive (rum/local false ::select?) (rum/local false ::mouse-down?) - [state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text] + [state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text inline] (when current-block (let [select? (get state ::select?) *mouse-down? (::mouse-down? state) @@ -168,53 +181,65 @@ ;; as user needs to know if there result is sorted sort-state (get-sort-state current-block) sort-result (sort-result result (assoc sort-state :page? page?)) - property-separated-by-commas? (partial text/separated-by-commas? (state/get-config))] - [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e)) - :style {:width "100%"} - :class (when-not page? "query-table")} - [:table.table-auto - [:thead - [:tr.cursor - (for [column columns] - (let [title (if (and (= column :clock-time) (integer? clock-time-total)) - (util/format "clock-time(total: %s)" (clock/seconds->days:hours:minutes:seconds - clock-time-total)) - (name column))] - (sortable-title title column sort-state (:block/uuid current-block))))]] - [:tbody - (for [row sort-result] - (let [format (:block/format row)] + property-separated-by-commas? (partial text/separated-by-commas? (state/get-config)) + table-version (get-shui-component-version :table config) + result-as-text (for [row sort-result] + (for [column columns] + (build-column-text row column))) + render-column-value (fn [row-format cell-format value] + (cond + ;; elements should be rendered as they are provided + (= :element cell-format) value + ;; collections are treated as a comma separated list of page-cps + (coll? value) (->> (map #(page-cp {} {:block/name %}) value) + (interpose [:span ", "])) + ;; boolean values need to first be stringified + (boolean? value) (str value) + ;; string values will attempt to be rendered as pages, falling back to + ;; inline-text when no page entity is found + (string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])] + (page-cp {} page) + (inline-text row-format value)) + ;; anything else should just be rendered as provided + :else value))] + + (case table-version + 2 (shui/table-v2 {:data (conj [[columns]] result-as-text)} + (make-shui-context config inline)) + 1 [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e)) + :style {:width "100%"} + :class (when-not page? "query-table")} + [:table.table-auto + [:thead [:tr.cursor (for [column columns] - (let [value (build-column-value row - column - {:page? page? - :->elem ->elem - :map-inline map-inline - :config config - :comma-separated-property? (property-separated-by-commas? column)})] - [:td.whitespace-nowrap {:on-mouse-down (fn [] - (reset! *mouse-down? true) - (reset! select? false)) - :on-mouse-move (fn [] (reset! select? true)) - :on-mouse-up (fn [] - (when (and @*mouse-down? (not @select?)) - (state/sidebar-add-block! - (state/get-current-repo) - (:db/id row) - :block-ref) - (reset! *mouse-down? false)))} - (when value - (if (= :element (first value)) - (second value) - (let [value (second value)] - (if (coll? value) - (let [vals (for [row value] - (page-cp {} {:block/name row}))] - (interpose [:span ", "] vals)) - (cond - (boolean? value) (str value) - (string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])] - (page-cp {} page) - (inline-text format value)) - :else value)))))]))]))]]]))) + (let [title (if (and (= column :clock-time) (integer? clock-time-total)) + (util/format "clock-time(total: %s)" (clock/seconds->days:hours:minutes:seconds + clock-time-total)) + (name column))] + (sortable-title title column sort-state (:block/uuid current-block))))]] + [:tbody + (for [row sort-result] + (let [format (:block/format row)] + [:tr.cursor + (for [column columns] + (let [value (build-column-value row + column + {:page? page? + :->elem ->elem + :map-inline map-inline + :config config + :comma-separated-property? (property-separated-by-commas? column)})] + [:td.whitespace-nowrap {:on-mouse-down (fn [] + (reset! *mouse-down? true) + (reset! select? false)) + :on-mouse-move (fn [] (reset! select? true)) + :on-mouse-up (fn [] + (when (and @*mouse-down? (not @select?)) + (state/sidebar-add-block! + (state/get-current-repo) + (:db/id row) + :block-ref) + (reset! *mouse-down? false)))} + (when value + (apply render-column-value format value))]))]))]]])))) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 6cffe63c7b..f431a6f190 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -426,7 +426,7 @@ (not has-children?))] (outliner-tx/transact! {:outliner-op :insert-blocks} - (save-current-block! {:current-block current-block}) + (save-current-block! {:current-block current-block}) (outliner-core/insert-blocks! [new-block] current-block {:sibling? sibling? :keep-uuid? keep-uuid? :replace-empty-target? replace-empty-target?})))) @@ -1244,8 +1244,8 @@ [blocks] (outliner-tx/transact! {:outliner-op :save-block} - (doseq [[block value] blocks] - (save-block-if-changed! block value)))) + (doseq [[block value] blocks] + (save-block-if-changed! block value)))) (defn save-current-block! "skip-properties? if set true, when editing block is likely be properties, skip saving" @@ -2735,7 +2735,7 @@ (outliner-tx/transact! {:outliner-op :move-blocks :real-outliner-op :indent-outdent} - (outliner-core/indent-outdent-blocks! [block] indent?))) + (outliner-core/indent-outdent-blocks! [block] indent?))) (state/set-editor-op! :nil))) (defn keydown-tab-handler @@ -3178,9 +3178,9 @@ ;; if the move is to cross block boundary, select the whole block (or (and (= direction :up) (cursor/textarea-cursor-rect-first-row? cursor-rect)) (and (= direction :down) (cursor/textarea-cursor-rect-last-row? cursor-rect))) - (select-block-up-down direction) + (select-block-up-down direction) ;; simulate text selection - (cursor/select-up-down input direction anchor cursor-rect))) + (cursor/select-up-down input direction anchor cursor-rect))) (select-block-up-down direction)))) (defn open-selected-block! diff --git a/src/main/frontend/page.cljs b/src/main/frontend/page.cljs index 87c4ca32f8..967b485c31 100644 --- a/src/main/frontend/page.cljs +++ b/src/main/frontend/page.cljs @@ -52,11 +52,11 @@ [:div.flex.flex-col.items-start [:div.text-2xs.font-bold.uppercase.toned-down (t :page/step "1")] [:div [:span.highlighted.font-bold "Rebuild"] [:span.toned-down " search index"]]] - [:div - (ui/button (t :page/try) - :small? true - :on-click (fn [] - (search-handler/rebuild-indices! true)))]] + [:div + (ui/button (t :page/try) + :small? true + :on-click (fn [] + (search-handler/rebuild-indices! true)))]] [:div.flex.flex-row.justify-between.align-items.mb-2.items-center.separator-top.py-4 [:div.flex.flex-col.items-start [:div.text-2xs.font-bold.uppercase.toned-down (t :page/step "2")] @@ -92,7 +92,7 @@ (ui/inject-dynamic-style-node!) (quick-tour/init) (plugin-handler/host-mounted!) - (assoc state ::teardown (setup-fns!) )) + (assoc state ::teardown (setup-fns!))) :will-unmount (fn [state] (when-let [teardown (::teardown state)] (teardown)))} diff --git a/src/main/frontend/rum.cljs b/src/main/frontend/rum.cljs index de4f7f291d..b4afe69c5c 100644 --- a/src/main/frontend/rum.cljs +++ b/src/main/frontend/rum.cljs @@ -92,7 +92,7 @@ (fn [] (rum/set-ref! *mounted true) #(rum/set-ref! *mounted false)) - []) + []) #(rum/deref *mounted))) (defn use-bounding-client-rect diff --git a/src/main/frontend/shui.cljs b/src/main/frontend/shui.cljs new file mode 100644 index 0000000000..3519961020 --- /dev/null +++ b/src/main/frontend/shui.cljs @@ -0,0 +1,25 @@ +(ns frontend.shui + "Glue between frontend code and deps/shui for convenience" + (:require + [frontend.date :refer [int->local-time-2]] + [frontend.state :as state] + [logseq.shui.context :refer [make-context]])) + +(def default-versions {:logseq.table.version 1}) + +(defn get-shui-component-version + "Returns the version of the shui component, checking first + the block properties, then the global config, then the defaults." + [component-name block-config] + (let [version-key (keyword (str "logseq." (name component-name) ".version"))] + (js/parseFloat + (or (get-in block-config [:block :block/properties version-key]) + (get-in (state/get-config) [version-key]) + (get-in default-versions [version-key]) + 1)))) + +(defn make-shui-context [block-config inline] + (make-context {:block-config block-config + :app-config (state/get-config) + :inline inline + :int->local-time-2 int->local-time-2})) diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index 0312b01a5f..ef05967334 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -259,9 +259,9 @@ ;; :file-sync/progress {} ;; :file-sync/start-time {} ;; :file-sync/last-synced-at {}} - :file-sync/graph-state {:current-graph-uuid nil + :file-sync/graph-state {:current-graph-uuid nil} ;; graph-uuid -> ... - } + :user/info {:UserGroups (storage/get :user-groups)} :encryption/graph-parsing? false diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 383c99c5b3..cf32b7eecd 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -730,26 +730,26 @@ [state {:keys [on-mouse-down header title-trigger? collapsed?]}] (let [control? (get state ::control?)] [:div.content - [:div.flex-1.flex-row.foldable-title (cond-> - {:on-mouse-over #(reset! control? true) - :on-mouse-out #(reset! control? false)} - title-trigger? - (assoc :on-mouse-down on-mouse-down - :class "cursor")) - [:div.flex.flex-row.items-center - (when-not (mobile-util/native-platform?) - [:a.block-control.opacity-50.hover:opacity-100.mr-2 - (cond-> - {:style {:width 14 - :height 16 - :margin-left -30}} - (not title-trigger?) - (assoc :on-mouse-down on-mouse-down)) - [:span {:class (if (or @control? @collapsed?) "control-show cursor-pointer" "control-hide")} - (rotating-arrow @collapsed?)]]) - (if (fn? header) - (header @collapsed?) - header)]]])) + [:div.flex-1.flex-row.foldable-title (cond-> + {:on-mouse-over #(reset! control? true) + :on-mouse-out #(reset! control? false)} + title-trigger? + (assoc :on-mouse-down on-mouse-down + :class "cursor")) + [:div.flex.flex-row.items-center + (when-not (mobile-util/native-platform?) + [:a.block-control.opacity-50.hover:opacity-100.mr-2 + (cond-> + {:style {:width 14 + :height 16 + :margin-left -30}} + (not title-trigger?) + (assoc :on-mouse-down on-mouse-down)) + [:span {:class (if (or @control? @collapsed?) "control-show cursor-pointer" "control-hide")} + (rotating-arrow @collapsed?)]]) + (if (fn? header) + (header @collapsed?) + header)]]])) (rum/defcs foldable < db-mixins/query rum/reactive (rum/local false ::collapsed?) @@ -852,10 +852,10 @@ [:option (cond-> {:key label :value (or value label)} ;; NOTE: value might be an empty string, `or` is safe here - disabled - (assoc :disabled disabled) - selected - (assoc :selected selected)) + disabled + (assoc :disabled disabled) + selected + (assoc :selected selected)) label])])) (rum/defc radio-list diff --git a/src/main/frontend/util/cursor.cljs b/src/main/frontend/util/cursor.cljs index e254be1226..e49ff32511 100644 --- a/src/main/frontend/util/cursor.cljs +++ b/src/main/frontend/util/cursor.cljs @@ -226,7 +226,7 @@ (defn- move-cursor-up-down [input direction] - (move-cursor-to input (next-cursor-pos-up-down direction (get-caret-pos input)))) + (move-cursor-to input (next-cursor-pos-up-down direction (get-caret-pos input)))) (defn move-cursor-up [input] (move-cursor-up-down input :up)) diff --git a/tailwind.config.js b/tailwind.config.js index a60ba9ba0f..40a34dc759 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,4 +1,29 @@ +const plugin = require('tailwindcss/plugin') const colors = require('tailwindcss/colors') +const radix = require('@radix-ui/colors') + +const gradientColors = { + tomato: ["amber", "orange", "tomato", "red", "crimson"], + red: ["orange", "tomato", "red", "crimson", "pink"], + crimson: ["tomato", "red", "crimson", "pink", "plum"], + pink: ["red", "crimson", "pink", "plum", "purple"], + plum: ["crimson", "pink", "plum", "purple", "violet"], + purple: ["pink", "plum", "purple", "violet", "indigo"], + violet: ["plum", "purple", "violet", "indigo", "blue"], + indigo: ["purple", "violet", "indigo", "blue", "cyan"], + blue: ["violet", "indigo", "blue", "cyan", "teal"], + // sky: ["indigo", "blue", "sky", "cyan", "teal"], + cyan: ["indigo", "blue", "cyan", "teal", "green"], + teal: ["blue", "cyan", "teal", "green", "grass"], + // mint: ["cyan", "teal", "mint", "green", "grass"], + green: ["cyan", "teal", "green", "grass", "amber"], + grass: ["teal", "green", "grass", "amber", "orange"], + // lime: ["green", "grass", "lime", "yellow", "amber"], + // yellow: ["grass", "lime", "yellow", "amber", "orange"], + amber: ["green", "grass", "amber", "orange", "tomato"], + orange: ["grass", "amber", "orange", "tomato", "red"], + // brown: ["green", "grass", "brown", "tomato", "red"], +} function exposeColorsToCssVars ({ addBase, theme }) { function extractColorVars (colorObj, colorGroup = '') { @@ -19,28 +44,160 @@ function exposeColorsToCssVars ({ addBase, theme }) { }) } +function buildColor(color, custom) { + const base = custom || colors[color] || {} + + for (const [xName, xValue] of Object.entries(radix[color] || {})) { + const regexResult = xName.match(/\d+$/) + if (!regexResult) { continue; } + const xStep = regexResult[0] + base[xStep] = xValue + } + + return base +} + +// this will allow us to use gradient color functions in the ui: +// grad-bg-tomato-3 OR grad-bg-tomato-3-alpha +// it will also loop through all 5 color stops, unless the stops are specified +// grad-bg-stops-3 +// this will have a default repeating gradient at a step that can be configured with +// grad-bg-cycle-32 +const addGradientColors = plugin(({ addBase, addComponents, addUtilities, config, ___theme }) => { + const dark = getDarkSelector(config) + + addUtilities({ + ['.grad-bg-stops-3']: { + '--grad-bg-stops': "var(--grad-bg-stop-b), var(--grad-bg-stop-c), var(--grad-bg-stop-d)", + }, + ['.grad-bg-stops-5']: { + '--grad-bg-stops': "var(--grad-bg-stop-a), var(--grad-bg-stop-b), var(--grad-bg-stop-c), var(--grad-bg-stop-d), var(--grad-bg-stop-e)", + }, + ['.grad-bg-cycle-12']: { + 'background-image': 'repeatint-linear-gradient(to right, var(--grad-bg-stops))', + }, + }) + + Object.values(gradientColors).forEach((stops, ___index) => { + const baseColor = stops[2] + const color = (scale, stopIndex = 2, suffix = "") => `--color-${stops[stopIndex]}${suffix}-${scale}` + + addComponents({ + // tailwind componnent for .grad-bg-COLOR-9 + [`.grad-bg-${baseColor}-9`]: { + "--grad-bg-stop-a": `var(${color(9, 0)})`, + "--grad-bg-stop-b": `var(${color(9, 1)})`, + "--grad-bg-stop-c": `var(${color(9, 2)})`, + "--grad-bg-stop-d": `var(${color(9, 3)})`, + "--grad-bg-stop-e": `var(${color(9, 4)})`, + "--grad-bg-stops-default": `var(--grad-bg-stop-b), var(--grad-bg-stop-c), var(--grad-bg-stop-d)`, + "background-image": `linear-gradient(var(--grad-bg-direction, to right), var(--grad-bg-stops, var(--grad-bg-stops-default)))`, + + [dark]: { + "--grad-bg-stop-a": `var(${color(9, 0, "dark")})`, + "--grad-bg-stop-b": `var(${color(9, 1, "dark")})`, + "--grad-bg-stop-c": `var(${color(9, 2, "dark")})`, + "--grad-bg-stop-d": `var(${color(9, 3, "dark")})`, + "--grad-bg-stop-e": `var(${color(9, 4, "dark")})`, + } + }, + // tailwind component for .grad-bg-COLOR-9-alpha + [`.grad-bg-${baseColor}-9-alpha`]: { + "--grad-bg-stop-a": `var(${color(9, 0)})`, + "--grad-bg-stop-b": `var(${color(9, 1)})`, + "--grad-bg-stop-c": `var(${color(9, 2)})`, + "--grad-bg-stop-d": `var(${color(9, 3)})`, + "--grad-bg-stop-e": `var(${color(9, 4)})`, + "--grad-bg-stops-default": `var(--grad-bg-stop-b), var(--grad-bg-stop-c), var(--grad-bg-stop-d)`, + "background-image": `linear-gradient(var(--grad-bg-direction, to right), var(--grad-bg-stops, var(--grad-bg-stops-default)))`, + + [dark]: { + "--grad-bg-stop-a": `var(${color(9, 0, "dark")})`, + "--grad-bg-stop-b": `var(${color(9, 1, "dark")})`, + "--grad-bg-stop-c": `var(${color(9, 2, "dark")})`, + "--grad-bg-stop-d": `var(${color(9, 3, "dark")})`, + "--grad-bg-stop-e": `var(${color(9, 4, "dark")})`, + } + }, + }) + }) +}) + +function getDarkSelector(config) { + const darkMode = config("darkMode"); + const prefix = config("prefix"); + + if (Array.isArray(darkMode)) { + if (darkMode.length < 2) { + throw new Error( + "To customize the dark mode selector, `darkMode` should contain two items. Documentation: https://tailwindcss.com/docs/dark-mode#customizing-the-class-name" + ); + } + + if (darkMode[0] !== "class") { + throw new Error( + 'To customize the dark mode selector, `darkMode` should have "class" as its first item. Documentation: https://tailwindcss.com/docs/dark-mode#customizing-the-class-name' + ); + } + + return darkMode[1] + " &"; + } + + if (darkMode === "media") { + return "@media (prefers-color-scheme: dark)"; + } + + if (darkMode !== "class") { + throw new Error( + "Invalid `darkMode`. Documentation: https://tailwindcss.com/docs/dark-mode" + ); + } + + if (prefix) { + return `[class~="${prefix}dark"] &`; + } + + return '[class~="dark"] &'; +} + module.exports = { darkMode: 'class', content: [ './src/**/*.js', './src/**/*.cljs', - './resources/**/*.html' + './resources/**/*.html', + './deps/shui/src/**/*.cljs', ], safelist: [ - 'bg-black', 'bg-white', + 'bg-black', 'bg-white', 'capitalize-first', { pattern: /bg-(gray|red|yellow|green|blue|orange|indigo|rose|purple|pink)-(100|200|300|400|500|600|700|800|900)/ }, { pattern: /text-(gray|red|yellow|green|blue|orange|indigo|rose|purple|pink)-(100|200|300|400|500|600|700|800|900)/ }, - { pattern: /columns-([1-9]|1[0-2])|(auto|3xs|2xs|xs|sm|md|lg|xl)|([2-7]xl)/ } + { pattern: /columns-([1-9]|1[0-2])|(auto|3xs|2xs|xs|sm|md|lg|xl)|([2-7]xl)/ }, + { pattern: /bg-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /shadow-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /text-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /ring-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /from-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /via-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /to-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(1|2|3|4|5|6|7|8|9|10|11|12)/ }, + { pattern: /border-(mauve|slate|sage|olive|sand|tomato|red|crimson|pink|plum|purple|violet|indigo|blue|sky|cyan|teal|mint|green|grass|lime|yellow|amber|orange|brown)(dark)?-(4|5|6|7|8)/ }, ], plugins: [ require('@tailwindcss/forms'), require('@tailwindcss/typography'), require('@tailwindcss/aspect-ratio'), require('@tailwindcss/line-clamp'), + require('tailwind-capitalize-first-letter'), + addGradientColors, exposeColorsToCssVars ], theme: { extend: { + backgroundImage: { + 'gradient-conic': 'conic-gradient(var(--tw-gradient-stops))', + 'gradient-conic-bounce': 'conic-gradient(var(--tw-gradient-from), var(--tw-gradient-via), var(--tw-gradient-to), var(--tw-gradient-via), var(--tw-gradient-from))', + 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', + }, fontSize: { '2xs': ['0.625rem', '0.875rem'] }, @@ -59,14 +216,44 @@ module.exports = { } }, colors: { - transparent: 'transparent', - current: 'currentColor', + // Tailwind colors black: colors.black, + current: 'currentColor', + rose: colors.rose, + transparent: 'transparent', white: colors.white, - gray: colors.neutral, - green: colors.green, - blue: colors.blue, - indigo: { + + // Radix colors + amber: buildColor("amber"), + blue: buildColor("blue"), + bronze: buildColor("bronze"), + brown: buildColor("brown"), + crimson: buildColor("crimson"), + cyan: buildColor("cyan"), + gold: buildColor("gold"), + grass: buildColor("grass"), + green: buildColor("green"), + lime: buildColor("lime"), + mauve: buildColor("mauve"), + mint: buildColor("mint"), + olive: buildColor("olive"), + orange: buildColor("orange"), + pink: buildColor("pink"), + plum: buildColor("plum"), + purple: buildColor("purple"), + red: buildColor("red"), + sage: buildColor("sage"), + sand: buildColor("sand"), + sky: buildColor("sky"), + slate: buildColor("slate"), + teal: buildColor("teal"), + tomato: buildColor("tomato"), + violet: buildColor("violet"), + + // Custom colors + gray: buildColor("gray", colors.neutral), + yellow: buildColor("yellow", colors.amber), + indigo: buildColor("indigo", { 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', @@ -77,13 +264,36 @@ module.exports = { 700: '#005b8a', 800: '#075985', 900: '#0c4a6e', - }, - red: colors.red, - yellow: colors.amber, - orange: colors.orange, - rose: colors.rose, - purple: colors.purple, - pink: colors.pink + }), + + tomatodark: buildColor("tomatoDark"), + reddark: buildColor("redDark"), + crimsondark: buildColor("crimsonDark"), + pinkdark: buildColor("pinkDark"), + plumdark: buildColor("plumDark"), + purpledark: buildColor("purpleDark"), + violetdark: buildColor("violetDark"), + skydark: buildColor("skyDark"), + indigodark: buildColor("indigoDark"), + bluedark: buildColor("blueDark"), + cyandark: buildColor("cyanDark"), + mintdark: buildColor("mintDark"), + tealdark: buildColor("tealDark"), + greendark: buildColor("greenDark"), + limedark: buildColor("limeDark"), + grassdark: buildColor("grassDark"), + yellowdark: buildColor("yellowDark"), + amberdark: buildColor("amberDark"), + orangedark: buildColor("orangeDark"), + browndark: buildColor("brownDark"), + graydark: buildColor("grayDark"), + mauvedark: buildColor("mauveDark"), + slatedark: buildColor("slateDark"), + sagedark: buildColor("sageDark"), + olivedark: buildColor("oliveDark"), + sanddark: buildColor("sandDark"), + golddark: buildColor("goldDark"), + bronzedark: buildColor("bronzeDark"), } } } diff --git a/yarn.lock b/yarn.lock index 15de9e6ce5..feb45f1dd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -733,6 +733,11 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@radix-ui/colors@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@radix-ui/colors/-/colors-0.1.8.tgz#b08c62536fc462a87632165fb28e9b18f9bd047e" + integrity sha512-jwRMXYwC0hUo0mv6wGpuw254Pd9p/R6Td5xsRpOmaWkUHlooNWqVcadgyzlRumMq3xfOTXwJReU0Jv+EIy4Jbw== + "@sentry/browser@6.19.7": version "6.19.7" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.7.tgz#a40b6b72d911b5f1ed70ed3b4e7d4d4e625c0b5f" @@ -7048,6 +7053,11 @@ table@^6.6.0: string-width "^4.2.3" strip-ansi "^6.0.1" +tailwind-capitalize-first-letter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tailwind-capitalize-first-letter/-/tailwind-capitalize-first-letter-1.0.4.tgz#d7a07c1dda4a7555f2240d57154df394b0ee8db6" + integrity sha512-ZB8hBi68JI4aQ1cDUxuFWfMYTxgBvlzIdPPHSkFkMUlo7p2QlbMy0hVv/vAREAFmkUh9QfjuKQnOSbe4Gnqljg== + tailwindcss@3.1.8: version "3.1.8" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.8.tgz#4f8520550d67a835d32f2f4021580f9fddb7b741" From 7335a6f623f48a53bbe2b38a41fbb43060d40b8c Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 12 May 2023 11:24:24 -0400 Subject: [PATCH 53/81] Fix org mode page refs - close #9367 --- .../src/logseq/graph_parser/block.cljs | 16 ++++--- .../graph_parser/test/docs_graph_helper.cljs | 2 +- .../test/logseq/graph_parser_test.cljs | 45 +++++++++++++------ .../handler/repo_conversion_test.cljs | 2 +- 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/deps/graph-parser/src/logseq/graph_parser/block.cljs b/deps/graph-parser/src/logseq/graph_parser/block.cljs index f06c45265b..b4ee597207 100644 --- a/deps/graph-parser/src/logseq/graph_parser/block.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/block.cljs @@ -35,27 +35,31 @@ (string/join)))) (defn- get-page-reference - [block] + [block format] (let [page (cond (and (vector? block) (= "Link" (first block))) - (let [typ (first (:url (second block))) + (let [url-type (first (:url (second block))) value (second (:url (second block)))] ;; {:url ["File" "file:../pages/hello_world.org"], :label [["Plain" "hello world"]], :title nil} (or (and - (= typ "Page_ref") + (= url-type "Page_ref") (and (string? value) (not (or (gp-config/local-asset? value) (gp-config/draw? value)))) value) (and - (= typ "Search") + (= url-type "Search") (page-ref/page-ref? value) (text/page-ref-un-brackets! value)) + (and (= url-type "Search") + (= format :org) + value) + (and - (= typ "File") + (= url-type "File") (second (first (:label (second block))))))) (and (vector? block) (= "Nested_link" (first block))) @@ -327,7 +331,7 @@ (when-not (and (vector? form) (= (first form) "Custom") (= (second form) "query")) - (when-let [page (get-page-reference form)] + (when-let [page (get-page-reference form (:format block))] (swap! *refs conj page)) (when-let [tag (get-tag form)] (let [tag (text/page-ref-un-brackets! tag)] diff --git a/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs b/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs index 4f0434e57d..b10e50df4e 100644 --- a/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/test/docs_graph_helper.cljs @@ -153,7 +153,7 @@ ;; only increase over time as the docs graph rarely has deletions (testing "Counts" (is (= 306 (count files)) "Correct file count") - (is (= 69500 (count (d/datoms db :eavt))) "Correct datoms count") + (is (= 69508 (count (d/datoms db :eavt))) "Correct datoms count") (is (= 5866 (ffirst diff --git a/deps/graph-parser/test/logseq/graph_parser_test.cljs b/deps/graph-parser/test/logseq/graph_parser_test.cljs index 2e899d11e4..aa309df129 100644 --- a/deps/graph-parser/test/logseq/graph_parser_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser_test.cljs @@ -117,7 +117,7 @@ :where [?b :block/name ?name] [?b :block/type "whiteboard"]] - @conn)] + @conn)] (is (= pages #{["foo"] ["bar"]})))))) (defn- test-property-order [num-properties] @@ -153,11 +153,11 @@ "- desc:: \"#foo is not a ref\"" {:extract-options {:user-config {}}}) block (->> (d/q '[:find (pull ?b [* {:block/refs [*]}]) - :in $ - :where [?b :block/properties]] - @conn) - (map first) - first)] + :in $ + :where [?b :block/properties]] + @conn) + (map first) + first)] (is (= {:desc "\"#foo is not a ref\""} (:block/properties block)) "Quoted value is unparsed") @@ -274,9 +274,9 @@ set) (set refs)) ; pre-block/page has expected refs - db-properties (first (map :block/refs blocks)) + db-properties (first (map :block/refs blocks)) ;; block has expected refs - block-db-properties (second (map :block/refs blocks)))))) + block-db-properties (second (map :block/refs blocks)))))) (deftest property-relationships (let [properties {:single-link "[[bar]]" @@ -324,7 +324,7 @@ (map #(select-keys % [:block/properties :block/invalid-properties])))) "Has correct (in)valid page properties"))) -(deftest correct-page-names-created +(deftest correct-page-names-created-from-title (testing "from title" (let [conn (ldb/start-conn) built-in-pages (set (map string/lower-case default-db/built-in-pages-names))] @@ -358,22 +358,39 @@ @conn) (map (comp :block/original-name first)) (remove built-in-pages) - set))))) + set)))))) - (testing "for file, mailto, web and other uris" +(deftest correct-page-names-created-from-page-refs + (testing "for file, mailto, web and other uris in markdown" (let [conn (ldb/start-conn) built-in-pages (set (map string/lower-case default-db/built-in-pages-names))] (graph-parser/parse-file conn "foo.md" - (str "- [foo]([[bar]])\n" + (str "- [title]([[bar]])\n" ;; all of the uris below do not create pages "- ![image.png](../assets/image_1630480711363_0.png)\n" "- [Filename.txt](file:///E:/test/Filename.txt)\n" "- [mail](mailto:test@test.com?subject=TestSubject)\n" "- [onenote link](onenote:https://d.docs.live.net/b2127346582e6386a/blablabla/blablabla/blablabla%20blablabla.one#Etat%202019§ion-id={133DDF16-9A1F-4815-9A05-44303784442E6F94}&page-id={3AAB677F0B-328F-41D0-AFF5-66408819C085}&end)\n" "- [lock file](deps/graph-parser/yarn.lock)" - "- [example](https://example.com)") - {}) + "- [example](https://example.com)")) + (is (= #{"foo" "bar"} + (->> (d/q '[:find (pull ?b [*]) + :in $ + :where [?b :block/name]] + @conn) + (map (comp :block/name first)) + (remove built-in-pages) + set))))) + +(testing "for web and page uris in org" + (let [conn (ldb/start-conn) + built-in-pages (set (map string/lower-case default-db/built-in-pages-names))] + (graph-parser/parse-file conn + "foo.org" + (str "* [[bar][title]]\n" + ;; all of the uris below do not create pages + "* [[https://example.com][example]]")) (is (= #{"foo" "bar"} (->> (d/q '[:find (pull ?b [*]) :in $ diff --git a/src/test/frontend/handler/repo_conversion_test.cljs b/src/test/frontend/handler/repo_conversion_test.cljs index 576eb2f4ce..7768ee35c3 100644 --- a/src/test/frontend/handler/repo_conversion_test.cljs +++ b/src/test/frontend/handler/repo_conversion_test.cljs @@ -98,7 +98,7 @@ ;; only increase over time as the docs graph rarely has deletions (testing "Counts" (is (= 211 (count files)) "Correct file count") - (is (= 42296 (count (d/datoms db :eavt))) "Correct datoms count") + (is (= 42304 (count (d/datoms db :eavt))) "Correct datoms count") (is (= 3600 (ffirst From fe24b61bebd52c20236f6a390d2183a4b4918c5b Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 12 May 2023 17:13:23 -0400 Subject: [PATCH 54/81] Fix asset link creating invalid page for org mode --- deps/graph-parser/src/logseq/graph_parser/block.cljs | 1 + deps/graph-parser/test/logseq/graph_parser_test.cljs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/graph-parser/src/logseq/graph_parser/block.cljs b/deps/graph-parser/src/logseq/graph_parser/block.cljs index b4ee597207..f4bb4b3286 100644 --- a/deps/graph-parser/src/logseq/graph_parser/block.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/block.cljs @@ -56,6 +56,7 @@ (and (= url-type "Search") (= format :org) + (not (gp-config/local-asset? value)) value) (and diff --git a/deps/graph-parser/test/logseq/graph_parser_test.cljs b/deps/graph-parser/test/logseq/graph_parser_test.cljs index aa309df129..78478c1175 100644 --- a/deps/graph-parser/test/logseq/graph_parser_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser_test.cljs @@ -390,7 +390,8 @@ "foo.org" (str "* [[bar][title]]\n" ;; all of the uris below do not create pages - "* [[https://example.com][example]]")) + "* [[https://example.com][example]]\n" + "* [[../assets/conga_parrot.gif][conga]]")) (is (= #{"foo" "bar"} (->> (d/q '[:find (pull ?b [*]) :in $ From 8ba4667f044f94f1fdb3bfece51e0ce555e5ec80 Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 15 May 2023 14:35:40 +0800 Subject: [PATCH 55/81] enhance(ui): align the number list with the bullet list prefix marker --- src/main/frontend/components/block.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index 63634aaf14..90a317aad2 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -206,7 +206,7 @@ margin-top: 0; &.is-order-list { - @apply relative right-0 mr-0; + @apply relative right-[6px] mr-0; } } @@ -532,7 +532,7 @@ } &.as-order-list { - @apply w-[28px] whitespace-nowrap justify-start pl-[3px]; + @apply w-[28px] whitespace-nowrap justify-center pl-[3px]; } .bullet { From e9620959e0275c1135ddd3f36e164ed1805de192 Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 15 May 2023 15:07:13 +0800 Subject: [PATCH 56/81] enhance(ui): align the number list with the bullet list prefix marker --- src/main/frontend/components/block.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index 90a317aad2..f0523dedd9 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -202,11 +202,11 @@ .block-control-wrap { height: 24px; - min-width: 50px; + min-width: 44px; margin-top: 0; &.is-order-list { - @apply relative right-[6px] mr-0; + @apply relative right-[3px] mr-0; } } @@ -532,7 +532,7 @@ } &.as-order-list { - @apply w-[28px] whitespace-nowrap justify-center pl-[3px]; + @apply w-[22px] whitespace-nowrap justify-center pl-[3px]; } .bullet { From 7f56e83df72bc3dc788e865bc1361dddadcd9ffa Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 15 May 2023 15:54:00 +0800 Subject: [PATCH 57/81] fix: can't jump to the correct position when editing number list --- src/main/frontend/components/block.cljs | 13 ++++++++----- src/main/frontend/components/block.css | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index ee8ddcf878..011d6691af 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2212,7 +2212,10 @@ (editor-handler/clear-selection!) (editor-handler/unhighlight-blocks!) (let [f #(let [block (or (db/pull [:block/uuid (:block/uuid block)]) block) - cursor-range (util/caret-range (gdom/getElement block-id)) + cursor-range (some-> (gdom/getElement block-id) + (dom/by-class "block-content-wrapper") + first + util/caret-range) {:block/keys [content format]} block content (->> content (property/remove-built-in-properties format) @@ -2316,7 +2319,7 @@ mouse-down-key (if (util/ios?) :on-click :on-mouse-down) ; TODO: it seems that Safari doesn't work well with on-mouse-down - + attrs (cond-> {:blockid (str uuid) :data-type (name block-type) @@ -3024,8 +3027,8 @@ (defn table [config {:keys [header groups col_groups]}] - (case (get-shui-component-version :table config) - 2 (shui/table-v2 {:data (concat [[header]] groups)} + (case (get-shui-component-version :table config) + 2 (shui/table-v2 {:data (concat [[header]] groups)} (make-shui-context config inline)) 1 (let [tr (fn [elm cols] (->elem @@ -3072,7 +3075,7 @@ clocks (reverse (sort-by str clocks))] ;; TODO: display states change log ; states (filter #(not (string/starts-with? % "CLOCK:")) log) - + (when (seq clocks) (let [tr (fn [elm cols] (->elem :tr (mapv (fn [col] (->elem elm col)) cols))) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index f0523dedd9..f5f0adfadd 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -538,6 +538,8 @@ .bullet { @apply rounded-full w-[6px] h-[6px]; + font-size: 14px; + background-color: var(--ls-block-bullet-color, #394b59); transition: transform 0.2s; From d97d200b05f556ea996e07d23f1be8c0e00b3230 Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 15 May 2023 18:53:06 +0800 Subject: [PATCH 58/81] fix(mobile): incorrect padding between the bullet marker and the content boundary on mobile --- src/main/frontend/components/block.css | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index f5f0adfadd..c77319d88b 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -201,12 +201,10 @@ } .block-control-wrap { - height: 24px; - min-width: 44px; - margin-top: 0; + @apply h-[24px] mt-0 pr-[6px]; &.is-order-list { - @apply relative right-[3px] mr-0; + @apply relative right-[3px] mr-0 pr-0; } } From 7c8bc62a6871b0664feea33caf9c55d655abf96a Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 15 May 2023 19:06:56 +0800 Subject: [PATCH 59/81] fix(ui): incorrect position of the number list fold arrow on mobile --- src/main/frontend/components/block.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index c77319d88b..33441e031d 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -204,7 +204,11 @@ @apply h-[24px] mt-0 pr-[6px]; &.is-order-list { - @apply relative right-[3px] mr-0 pr-0; + @apply mr-0 pr-0; + + .bullet-link-wrap { + @apply relative left-[-3px]; + } } } From ba240bb48430f45b1d4261637435050b814eb2ec Mon Sep 17 00:00:00 2001 From: Sergey Kolesnik Date: Mon, 15 May 2023 17:42:25 +0300 Subject: [PATCH 60/81] docs: update templates/config.edn typos & spaces --- templates/config.edn | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/templates/config.edn b/templates/config.edn index e6f083f3d2..9da61e259e 100644 --- a/templates/config.edn +++ b/templates/config.edn @@ -102,7 +102,7 @@ ;; :custom-js-url "https://cdn.logseq.com/custom.js" ;; Set a custom Arweave gateway - ;; Default gateway: https://arweave.net + ;; Default value: https://arweave.net ;; :arweave/gateway "https://arweave.net" ;; Set bullet indentation when exporting @@ -110,22 +110,21 @@ ;; - `:eight-spaces` as eight spaces ;; - `:four-spaces` as four spaces ;; - `:two-spaces` as two spaces - ;; - `:tab` as a tab character (default) + ;; - `:tab` as a tab character (default) ;; :export/bullet-indentation :tab ;; Publish all pages within the Graph - ;; regardless of whether individual pages have been marked as public. + ;; Regardless of whether individual pages have been marked as public. ;; Default value: false ;; :publishing/all-pages-public? false - ;; Set the default home page and sidebar status. - ;; Define the default home page and sidebar status. - ;; If unspecified, Logseq will load the journal page by default on startup. - ;; The `:page` value represents the name of the page displayed at startup. - ;; Available options for `:sidebar` are: - ;; - "Contents" to display the Contents page in the right sidebar. - ;; - A specific page name to display in the right sidebar. - ;; - An array of multiple pages, e.g., ["Contents" "Page A" "Page B"]. + ;; Define the default home page and sidebar status. + ;; If unspecified, the journal page will be loaded on startup and the right sidebar will stay hidden. + ;; The `:page` value represents the name of the page displayed at startup. + ;; Available options for `:sidebar` are: + ;; - "Contents" to display the Contents page in the right sidebar. + ;; - A specific page name to display in the right sidebar. + ;; - An array of multiple pages, e.g., ["Contents" "Page A" "Page B"]. ;; If `:sidebar` remains unset, the right sidebar will stay hidden. ;; Examples: ;; 1. Set "Changelog" as the home page and display "Contents" in the right sidebar: @@ -144,7 +143,7 @@ ;; :journals-directory "journals" ;; Set the default location for storing whiteboards. - ;; If not specified, whiteboards will be stored in the 'whiteboards' subdirectory. + ;; Default value: "whiteboards" ;; :whiteboards-directory "whiteboards" ;; Enabling this option converts @@ -190,6 +189,7 @@ :ui/show-command-doc? true ;; Display empty bullet points. + ;; Default value: false :ui/show-empty-bullets? false ;; Pre-defined :view function to use with advanced queries. @@ -280,16 +280,16 @@ :ref/default-open-blocks-level 2 ;; Configure the threshold for linked references before collapsing. - ;; Default value: 100 + ;; Default value: 50 :ref/linked-references-collapsed-threshold 50 ;; Graph view configuration. ;; Example usage: ;; :graph/settings - ;; {:orphan-pages? true ; Default value: true - ;; :builtin-pages? false ; Default value: false - ;; :excluded-pages? false ; Default value: false - ;; :journal? false} ; Default value: false + ;; {:orphan-pages? true ; Default value: true + ;; :builtin-pages? false ; Default value: false + ;; :excluded-pages? false ; Default value: false + ;; :journal? false} ; Default value: false ;; Favorites to list on the left sidebar :favorites [] @@ -310,7 +310,7 @@ ;; :block-hidden-properties #{:public :icon} ;; Create a page for all properties. - ;; Default value: false + ;; Default value: true :property-pages/enabled? true ;; Properties to exclude from having property pages @@ -325,7 +325,7 @@ ;; Properties that are ignored when parsing property values for references ;; Example usage: ;; :ignored-page-references-keywords #{:author :website} - + ;; logbook configuration. ;; :logbook/settings ;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated @@ -404,7 +404,7 @@ ;; Warning: ;; This is a dangerous operation. To modify the setting, ;; access the 'Filename format' setting and follow the instructions. - ;; Othwerwise, You may need to manually rename all affected files and + ;; Otherwise, You may need to manually rename all affected files and ;; re-index them on all clients after synchronization. ;; Incorrect handling may result in messy page titles. ;; Available options: From 10da24e5b7178d7e629fe4c0fd67ab7e343f80b5 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 15 May 2023 13:56:59 -0400 Subject: [PATCH 61/81] Fix current block with disappearing path refs - close #9365 outliner-core/save-block and save-block-inner! were retracting block/path-refs aggressively, especially for cases when no path-refs had changed --- deps/db/src/logseq/db/schema.cljs | 1 - 1 file changed, 1 deletion(-) diff --git a/deps/db/src/logseq/db/schema.cljs b/deps/db/src/logseq/db/schema.cljs index a65e3893d8..8160955fbe 100644 --- a/deps/db/src/logseq/db/schema.cljs +++ b/deps/db/src/logseq/db/schema.cljs @@ -105,7 +105,6 @@ (def retract-attributes #{ :block/refs - :block/path-refs :block/tags :block/alias :block/marker From decbc12c53f461293279bfa34c13290b7e4fdc3c Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Mon, 15 May 2023 15:19:30 -0400 Subject: [PATCH 62/81] Add a test to ensure there's no regression on bug Also introduce helper fn for common db fixture setup --- src/test/frontend/handler/editor_test.cljs | 28 ++++++++++++++++++- src/test/frontend/handler/repo_test.cljs | 9 +----- .../modules/outliner/pipeline_test.cljs | 9 +----- src/test/frontend/test/helper.cljs | 13 +++++++++ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/test/frontend/handler/editor_test.cljs b/src/test/frontend/handler/editor_test.cljs index 5c89431be4..fe908cac1d 100644 --- a/src/test/frontend/handler/editor_test.cljs +++ b/src/test/frontend/handler/editor_test.cljs @@ -1,9 +1,14 @@ (ns frontend.handler.editor-test (:require [frontend.handler.editor :as editor] - [clojure.test :refer [deftest is testing are]] + [frontend.db :as db] + [clojure.test :refer [deftest is testing are use-fixtures]] + [datascript.core :as d] + [frontend.test.helper :as test-helper :refer [load-test-files]] [frontend.state :as state] [frontend.util.cursor :as cursor])) +(use-fixtures :each test-helper/start-and-destroy-db) + (deftest extract-nearest-link-from-text-test (testing "Page, block and tag links" (is (= "page1" @@ -213,3 +218,24 @@ "No page search within backticks")) ;; Reset state (state/set-editor-action! nil)) + +(deftest save-block-aux! + (load-test-files [{:file/path "pages/page1.md" + :file/content "\n +- b1 #foo"}]) + (testing "updating block's content changes content and preserves path-refs" + (let [conn (db/get-db test-helper/test-db false) + block (->> (d/q '[:find (pull ?b [* {:block/path-refs [:block/name]}]) + :where [?b :block/content "b1 #foo"]] + @conn) + ffirst) + prev-path-refs (set (map :block/name (:block/path-refs block))) + _ (assert (= #{"page1" "foo"} prev-path-refs) + "block has expected :block/path-refs") + ;; Use same options as edit-box-on-change! + _ (editor/save-block-aux! block "b12 #foo" {:skip-properties? true}) + updated-block (d/pull @conn '[* {:block/path-refs [:block/name]}] [:block/uuid (:block/uuid block)])] + (is (= "b12 #foo" (:block/content updated-block)) "Content updated correctly") + (is (= prev-path-refs + (set (map :block/name (:block/path-refs updated-block)))) + "Path-refs remain the same")))) \ No newline at end of file diff --git a/src/test/frontend/handler/repo_test.cljs b/src/test/frontend/handler/repo_test.cljs index 199723eb98..f59069930f 100644 --- a/src/test/frontend/handler/repo_test.cljs +++ b/src/test/frontend/handler/repo_test.cljs @@ -2,7 +2,6 @@ (:require [cljs.test :refer [deftest use-fixtures testing is]] [frontend.handler.repo :as repo-handler] [frontend.test.helper :as test-helper :refer [load-test-files]] - [frontend.state :as state] [logseq.graph-parser.cli :as gp-cli] [logseq.graph-parser.test.docs-graph-helper :as docs-graph-helper] [logseq.graph-parser.util.block-ref :as block-ref] @@ -12,13 +11,7 @@ ["path" :as node-path] ["fs" :as fs])) -(use-fixtures :each {:before (fn [] - ;; Set current-repo explicitly since it's not the default - (state/set-current-repo! test-helper/test-db) - (test-helper/start-test-db!)) - :after (fn [] - (state/set-current-repo! nil) - (test-helper/destroy-test-db!))}) +(use-fixtures :each test-helper/start-and-destroy-db) (deftest ^:integration parse-and-load-files-to-db (let [graph-dir "src/test/docs-0.9.2" diff --git a/src/test/frontend/modules/outliner/pipeline_test.cljs b/src/test/frontend/modules/outliner/pipeline_test.cljs index 698328f4af..2dcca1b49c 100644 --- a/src/test/frontend/modules/outliner/pipeline_test.cljs +++ b/src/test/frontend/modules/outliner/pipeline_test.cljs @@ -1,18 +1,11 @@ (ns frontend.modules.outliner.pipeline-test (:require [cljs.test :refer [deftest is use-fixtures testing]] [datascript.core :as d] - [frontend.state :as state] [frontend.db :as db] [frontend.modules.outliner.pipeline :as pipeline] [frontend.test.helper :as test-helper :refer [load-test-files]])) -(use-fixtures :each {:before (fn [] - ;; Set current-repo explicitly since it's not the default - (state/set-current-repo! test-helper/test-db) - (test-helper/start-test-db!)) - :after (fn [] - (state/set-current-repo! nil) - (test-helper/destroy-test-db!))}) +(use-fixtures :each test-helper/start-and-destroy-db) (defn- get-blocks [db] (->> (d/q '[:find (pull ?b [* {:block/path-refs [:block/name :db/id]}]) diff --git a/src/test/frontend/test/helper.cljs b/src/test/frontend/test/helper.cljs index 97849ab18d..e4c3d6e52a 100644 --- a/src/test/frontend/test/helper.cljs +++ b/src/test/frontend/test/helper.cljs @@ -1,6 +1,7 @@ (ns frontend.test.helper "Common helper fns for tests" (:require [frontend.handler.repo :as repo-handler] + [frontend.state :as state] [frontend.db.conn :as conn])) (defonce test-db "test-db") @@ -22,3 +23,15 @@ This can be called in synchronous contexts as no async fns should be invoked" files ;; Set :refresh? to avoid creating default files in after-parse {:re-render? false :verbose false :refresh? true})) + +(defn start-and-destroy-db + "Sets up a db connection and current repo like fixtures/reset-datascript. It + also seeds the db with the same default data that the app does and destroys a db + connection when done with it." + [f] + ;; Set current-repo explicitly since it's not the default + (state/set-current-repo! test-db) + (start-test-db!) + (f) + (state/set-current-repo! nil) + (destroy-test-db!)) From 48060cc758a80d3fc380564bf8e5f890d6c811bf Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 16 May 2023 11:57:56 +0800 Subject: [PATCH 63/81] fix: util/mobile? is a function --- src/main/frontend/extensions/tldraw.cljs | 2 +- src/main/frontend/util.cljc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/extensions/tldraw.cljs b/src/main/frontend/extensions/tldraw.cljs index ff96171fde..3b6ae9df5e 100644 --- a/src/main/frontend/extensions/tldraw.cljs +++ b/src/main/frontend/extensions/tldraw.cljs @@ -100,7 +100,7 @@ :getBlockPageName #(:block/name (model/get-block-page (state/get-current-repo) (parse-uuid %))) :exportToImage (fn [page-name options] (state/set-modal! #(export/export-blocks page-name (merge (js->clj options :keywordize-keys true) {:whiteboard? true})))) :isWhiteboardPage model/whiteboard-page? - :isMobile util/mobile? + :isMobile (util/mobile?) :saveAsset save-asset-handler :makeAssetUrl editor-handler/make-asset-url :copyToClipboard (fn [text, html] (util/copy-to-clipboard! text :html html)) diff --git a/src/main/frontend/util.cljc b/src/main/frontend/util.cljc index a7e1796598..5751635dc8 100644 --- a/src/main/frontend/util.cljc +++ b/src/main/frontend/util.cljc @@ -1269,7 +1269,7 @@ #?(:cljs (defn scroll-editor-cursor [^js/HTMLElement el & {:keys [to-vw-one-quarter?]}] - (when (and el (or (mobile-util/native-platform?) mobile?)) + (when (and el (or (mobile-util/native-platform?) (mobile?))) (let [box-rect (.getBoundingClientRect el) box-top (.-top box-rect) box-bottom (.-bottom box-rect) From 74728ae2bc7e5c81365a70e0e596c1c18a340dc4 Mon Sep 17 00:00:00 2001 From: Junyi Du Date: Tue, 16 May 2023 16:18:46 +0800 Subject: [PATCH 64/81] Enhance: version control settings description update (#9373) * enhance: remove version control entry blocker * ui: version control text box update Co-authored-by: Gabriel Horner <97210743+logseq-cldwalker@users.noreply.github.com> --------- Co-authored-by: Gabriel Horner <97210743+logseq-cldwalker@users.noreply.github.com> --- src/main/frontend/components/settings.cljs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/frontend/components/settings.cljs b/src/main/frontend/components/settings.cljs index 294947e25f..fa22c986df 100644 --- a/src/main/frontend/components/settings.cljs +++ b/src/main/frontend/components/settings.cljs @@ -667,14 +667,20 @@ [] [:div.panel-wrap [:div.text-sm.my-4 + (ui/admonition + :tip + [:p "If you have Logseq Sync enabled, you can view a page's edit history directly. This section is for tech-savvy only."]) + [:span.text-sm.opacity-50.my-4 + "To view page's edit history, click the three horizontal dots in the top-right corner and select \"View page history\"."] + [:br][:br] [:span.text-sm.opacity-50.my-4 - "You can view a page's edit history by clicking the three horizontal dots " - "in the top-right corner and selecting \"View page history\". " - "Logseq uses "] + "For professional users, Logseq also supports using "] [:a {:href "https://git-scm.com/" :target "_blank"} "Git"] [:span.text-sm.opacity-50.my-4 - " for version control."]] + " for version control."] + [:span.text-sm.opacity-50.my-4 + "Use Git at your own risk as general Git issues are not supported by the Logseq team"]] [:br] (switch-git-auto-commit-row t) (git-auto-commit-seconds t) @@ -827,9 +833,7 @@ [[:general "general" (t :settings-page/tab-general) (ui/icon "adjustments")] [:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing")] - (when (and - (util/electron?) - (not (file-sync-handler/synced-file-graph? current-repo))) + (when (util/electron?) [:git "git" (t :settings-page/tab-version-control) (ui/icon "history")]) ;; (when (util/electron?) From c119b1eeb58bc5c6a51ac405649bc9f981a4ae73 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Mon, 15 May 2023 18:22:06 +0300 Subject: [PATCH 65/81] fix multiselect right click on converted shape --- .../core/src/lib/tools/TLSelectTool/states/ContextMenuState.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ContextMenuState.ts b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ContextMenuState.ts index 0810525ee4..63bfe65098 100644 --- a/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ContextMenuState.ts +++ b/tldraw/packages/core/src/lib/tools/TLSelectTool/states/ContextMenuState.ts @@ -17,11 +17,10 @@ export class ContextMenuState< onEnter = (info: TLEventInfo) => { const { selectedIds, - selectedShapes, inputs: { shiftKey }, } = this.app - if (info.type === TLTargetType.Shape && !selectedShapes.has(info.shape)) { + if (info.type === TLTargetType.Shape && !selectedIds.has(info.shape.id)) { const shape = this.app.getParentGroup(info.shape) ?? info.shape if (shiftKey) { this.app.setSelectedShapes([...Array.from(selectedIds.values()), shape.id]) From ad5757de61f19a7337a0095fe0956c8538f63137 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Mon, 15 May 2023 18:22:22 +0300 Subject: [PATCH 66/81] fix: undo/redo of converted shapes --- tldraw/packages/core/src/lib/TLApi/TLApi.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tldraw/packages/core/src/lib/TLApi/TLApi.ts b/tldraw/packages/core/src/lib/TLApi/TLApi.ts index 78ff6d6258..90d91e113e 100644 --- a/tldraw/packages/core/src/lib/TLApi/TLApi.ts +++ b/tldraw/packages/core/src/lib/TLApi/TLApi.ts @@ -428,6 +428,7 @@ export class TLApi Date: Mon, 15 May 2023 18:22:44 +0300 Subject: [PATCH 67/81] fix: context bar actions of converted shapes --- .../src/components/ContextBar/contextBarActionFactory.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx index 5136393259..344690a971 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx @@ -103,7 +103,7 @@ const AutoResizingAction = observer(() => { className="tl-button" pressed={pressed} onPressedChange={v => { - shapes.forEach(s => { + app.selectedShapesArray.forEach(s => { if (s.props.type === 'logseq-portal') { s.update({ isAutoResizing: v, @@ -253,7 +253,7 @@ const NoFillAction = observer(() => { const app = useApp() const shapes = filterShapeByAction('NoFill') const handleChange = React.useCallback((v: boolean) => { - shapes.forEach(s => s.update({ noFill: v })) + app.selectedShapesArray.forEach(s => s.update({ noFill: v })) app.persist() }, []) @@ -279,14 +279,14 @@ const SwatchAction = observer(() => { >('Swatch') const handleSetColor = React.useCallback((color: string) => { - shapes.forEach(s => { + app.selectedShapesArray.forEach(s => { s.update({ fill: color, stroke: color }) }) app.persist() }, []) const handleSetOpacity = React.useCallback((opacity: number) => { - shapes.forEach(s => { + app.selectedShapesArray.forEach(s => { s.update({ opacity: opacity }) }) app.persist() From e5de374471c3c23726ae84965b39ff1ac8e5f370 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Mon, 15 May 2023 18:55:50 +0300 Subject: [PATCH 68/81] chore: add tests --- e2e-tests/whiteboards.spec.ts | 19 +++++++++++++++++++ .../src/lib/shapes/EllipseShape.tsx | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/e2e-tests/whiteboards.spec.ts b/e2e-tests/whiteboards.spec.ts index c012363c11..fd3c203398 100644 --- a/e2e-tests/whiteboards.spec.ts +++ b/e2e-tests/whiteboards.spec.ts @@ -159,6 +159,25 @@ test('undo the delete action', async ({ page }) => { await expect(page.locator('.logseq-tldraw .tl-line-container')).toHaveCount(1) }) +test('convert the first rectangle to ellipse', async ({ page }) => { + await page.keyboard.press('Escape') + await page.waitForTimeout(1000) + await page.click('.logseq-tldraw .tl-box-container:first-of-type') + await page.click('.tl-context-bar .tl-geometry-tools-pane-anchor') + await page.click('.tl-context-bar .tl-geometry-toolbar [data-tool=ellipse]') + + await expect(page.locator('.logseq-tldraw .tl-ellipse-container')).toHaveCount(1) + await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(1) +}) + +test('undo the conversion', async ({ page }) => { + await page.keyboard.press(modKey + '+z') + + await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2) + await expect(page.locator('.logseq-tldraw .tl-ellipse-container')).toHaveCount(0) +}) + + test('locked elements should not be removed', async ({ page }) => { await page.keyboard.press('Escape') await page.waitForTimeout(1000) diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx index 3fb4a3c512..3dd3019e0c 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx @@ -98,7 +98,8 @@ export class EllipseShape extends TLEllipseShape { ) return ( -
+
Date: Mon, 15 May 2023 19:27:19 +0300 Subject: [PATCH 69/81] revert unneeded change --- .../src/components/ContextBar/contextBarActionFactory.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx index 344690a971..e950737bfb 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx @@ -103,7 +103,7 @@ const AutoResizingAction = observer(() => { className="tl-button" pressed={pressed} onPressedChange={v => { - app.selectedShapesArray.forEach(s => { + shapes.forEach(s => { if (s.props.type === 'logseq-portal') { s.update({ isAutoResizing: v, From 25d1d9eae20fa64a8eea4098e823cb093a89cf0b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Tue, 16 May 2023 13:44:30 +0300 Subject: [PATCH 70/81] revert mobile? fn --- src/main/frontend/extensions/tldraw.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/extensions/tldraw.cljs b/src/main/frontend/extensions/tldraw.cljs index 3b6ae9df5e..ff96171fde 100644 --- a/src/main/frontend/extensions/tldraw.cljs +++ b/src/main/frontend/extensions/tldraw.cljs @@ -100,7 +100,7 @@ :getBlockPageName #(:block/name (model/get-block-page (state/get-current-repo) (parse-uuid %))) :exportToImage (fn [page-name options] (state/set-modal! #(export/export-blocks page-name (merge (js->clj options :keywordize-keys true) {:whiteboard? true})))) :isWhiteboardPage model/whiteboard-page? - :isMobile (util/mobile?) + :isMobile util/mobile? :saveAsset save-asset-handler :makeAssetUrl editor-handler/make-asset-url :copyToClipboard (fn [text, html] (util/copy-to-clipboard! text :html html)) From f5309270620855f112d2ec0f170b9bd20475f66b Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Tue, 16 May 2023 14:05:52 +0300 Subject: [PATCH 71/81] chore: add and fix e2e tests --- e2e-tests/whiteboards.spec.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/e2e-tests/whiteboards.spec.ts b/e2e-tests/whiteboards.spec.ts index fd3c203398..ff4c19a841 100644 --- a/e2e-tests/whiteboards.spec.ts +++ b/e2e-tests/whiteboards.spec.ts @@ -163,6 +163,7 @@ test('convert the first rectangle to ellipse', async ({ page }) => { await page.keyboard.press('Escape') await page.waitForTimeout(1000) await page.click('.logseq-tldraw .tl-box-container:first-of-type') + await page.mouse.move(0, 0) // move mouse to trigger a rerender of the context bar await page.click('.tl-context-bar .tl-geometry-tools-pane-anchor') await page.click('.tl-context-bar .tl-geometry-toolbar [data-tool=ellipse]') @@ -170,6 +171,19 @@ test('convert the first rectangle to ellipse', async ({ page }) => { await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(1) }) +test('change the color of the ellipse', async ({ page }) => { + await page.click('.tl-context-bar .tl-color-bg') + await page.click('.tl-context-bar .tl-color-palette .bg-red-500') + + await expect(page.locator('.logseq-tldraw .tl-ellipse-container ellipse:last-of-type')).toHaveAttribute('fill', 'var(--ls-wb-background-color-red)') +}) + +test('undo the color switch', async ({ page }) => { + await page.keyboard.press(modKey + '+z') + + await expect(page.locator('.logseq-tldraw .tl-ellipse-container ellipse:last-of-type')).toHaveAttribute('fill', 'var(--ls-wb-background-color-default)') +}) + test('undo the conversion', async ({ page }) => { await page.keyboard.press(modKey + '+z') @@ -177,7 +191,6 @@ test('undo the conversion', async ({ page }) => { await expect(page.locator('.logseq-tldraw .tl-ellipse-container')).toHaveCount(0) }) - test('locked elements should not be removed', async ({ page }) => { await page.keyboard.press('Escape') await page.waitForTimeout(1000) From afdb5c259b8339953fc5e95a7238731036471fe4 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Tue, 16 May 2023 14:06:40 +0300 Subject: [PATCH 72/81] fix: test description --- e2e-tests/whiteboards.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/whiteboards.spec.ts b/e2e-tests/whiteboards.spec.ts index ff4c19a841..36158ff680 100644 --- a/e2e-tests/whiteboards.spec.ts +++ b/e2e-tests/whiteboards.spec.ts @@ -184,7 +184,7 @@ test('undo the color switch', async ({ page }) => { await expect(page.locator('.logseq-tldraw .tl-ellipse-container ellipse:last-of-type')).toHaveAttribute('fill', 'var(--ls-wb-background-color-default)') }) -test('undo the conversion', async ({ page }) => { +test('undo the shape conversion', async ({ page }) => { await page.keyboard.press(modKey + '+z') await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2) From f8cc5996254c5c69f8f3cd4d118c76ac5e2ca377 Mon Sep 17 00:00:00 2001 From: Konstantinos Kaloutas Date: Tue, 16 May 2023 14:07:56 +0300 Subject: [PATCH 73/81] style: run prettier --- .../src/components/ContextBar/contextBarActionFactory.tsx | 4 +--- tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx index e950737bfb..ce6f2197f1 100644 --- a/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx +++ b/tldraw/apps/tldraw-logseq/src/components/ContextBar/contextBarActionFactory.tsx @@ -133,9 +133,7 @@ const LogseqPortalViewModeAction = observer(() => {
{collapsed ? 'Expand' : 'Collapse'}
) diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx index 3dd3019e0c..9930befbf7 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/EllipseShape.tsx @@ -98,8 +98,11 @@ export class EllipseShape extends TLEllipseShape { ) return ( -
+
Date: Tue, 16 May 2023 14:25:26 -0400 Subject: [PATCH 74/81] Document repl test workflow as a followup to #9372 Also organized unit test sections more --- docs/dev-practices.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/dev-practices.md b/docs/dev-practices.md index 1be7496a6e..281f23fb51 100644 --- a/docs/dev-practices.md +++ b/docs/dev-practices.md @@ -139,7 +139,17 @@ By convention, a namespace's tests are found at a corresponding namespace of the same name with an added `-test` suffix. For example, tests for `frontend.db.model` are found in `frontend.db.model-test`. -There are a couple different ways to develop with tests: +There are a couple different ways to run tests: + +* [Focus tests](#focus-tests) - Run one or more tests from the CLI +* [Autorun tests](#autorun-tests) - Autorun tests from the CLI +* [Repl tests](#repl-tests) - Run tests from REPL + +There a couple types of tests and they can overlap with each other: + +* [Database tests](#database-tests) - Tests that involve a datascript DB. +* [Performance tests](#performance-tests) - Tests that aim to measure and enforce a performance characteristic. +* [Async tests](#async-tests) - Tests that run async code and require some helpers. #### Focus Tests @@ -166,6 +176,15 @@ To run tests automatically on file save, run `clojure -M:test watch test the `:ns-regexp` option e.g. `clojure -M:test watch test --config-merge '{:autorun true :ns-regexp "frontend.util.page-property-test"}'`. +#### REPL tests + +Most unit tests e.g. ones that are browser compatible and don't require node libraries, can be run from the REPL. To do so: + +* Start a REPL for your editor. See [here for an example](https://github.com/logseq/logseq/blob/master/docs/develop-logseq.md#repl-setup). +* Load a test namespace. +* Run `(cljs.test/run-tests)` to run tests for the current test namespace. + + #### Database tests To write a test that uses a datascript db: @@ -188,7 +207,7 @@ To write a performance test: For examples of these tests, see `frontend.db.query-dsl-test` and `frontend.db.model-test`. -### Async Unit Testing +#### Async Tests Async unit testing is well supported in ClojureScript. https://clojurescript.org/tools/testing#async-testing is a good guide for how to From 6e06057e7b066c3d3fb22d58ac567e89d3739712 Mon Sep 17 00:00:00 2001 From: clstb Date: Sat, 29 Apr 2023 15:33:41 +0200 Subject: [PATCH 75/81] fix: preserve properties on update-block --- src/main/frontend/handler/editor.cljs | 9 ++++++++- src/main/logseq/api.cljs | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index f431a6f190..81670020db 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -1231,10 +1231,17 @@ (defn save-block! ([repo block-or-uuid content] + (save-block! repo block-or-uuid content {})) + ([repo block-or-uuid content {:keys [properties] :or {}}] (let [block (if (or (uuid? block-or-uuid) (string? block-or-uuid)) (db-model/query-block-by-uuid block-or-uuid) block-or-uuid)] - (save-block! {:block block :repo repo} content))) + (save-block! + {:block block :repo repo} + (if (seq properties) + (property/insert-properties (:block/format block) content properties) + content) + ))) ([{:keys [block repo] :as _state} value] (let [repo (or repo (state/get-current-repo))] (when (db/entity repo [:block/uuid (:block/uuid block)]) diff --git a/src/main/logseq/api.cljs b/src/main/logseq/api.cljs index 9f49d9255f..65b6c9d328 100644 --- a/src/main/logseq/api.cljs +++ b/src/main/logseq/api.cljs @@ -652,13 +652,13 @@ nil))) (def ^:export update_block - (fn [block-uuid content ^js _opts] + (fn [block-uuid content ^js opts] (let [repo (state/get-current-repo) edit-input (state/get-edit-input-id) editing? (and edit-input (string/ends-with? edit-input (str block-uuid)))] (if editing? (state/set-edit-content! edit-input content) - (editor-handler/save-block! repo (sdk-utils/uuid-or-throw-error block-uuid) content)) + (editor-handler/save-block! repo (sdk-utils/uuid-or-throw-error block-uuid) content (bean/->clj opts))) nil))) (def ^:export move_block From 7461d2bc4e64abf05ca7bdbdec8cd765eeae98fc Mon Sep 17 00:00:00 2001 From: clstb Date: Sat, 29 Apr 2023 23:06:27 +0200 Subject: [PATCH 76/81] feat: add test for save-block --- src/test/frontend/handler/editor_test.cljs | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/test/frontend/handler/editor_test.cljs b/src/test/frontend/handler/editor_test.cljs index fe908cac1d..c674281b6f 100644 --- a/src/test/frontend/handler/editor_test.cljs +++ b/src/test/frontend/handler/editor_test.cljs @@ -4,10 +4,17 @@ [clojure.test :refer [deftest is testing are use-fixtures]] [datascript.core :as d] [frontend.test.helper :as test-helper :refer [load-test-files]] + [frontend.db.model :as model] [frontend.state :as state] [frontend.util.cursor :as cursor])) -(use-fixtures :each test-helper/start-and-destroy-db) +(use-fixtures :each {:before (fn [] + ;; Set current-repo explicitly since it's not the default + (state/set-current-repo! test-helper/test-db) + (test-helper/start-test-db!)) + :after (fn [] + (state/set-current-repo! nil) + (test-helper/destroy-test-db!))}) (deftest extract-nearest-link-from-text-test (testing "Page, block and tag links" @@ -238,4 +245,20 @@ (is (= "b12 #foo" (:block/content updated-block)) "Content updated correctly") (is (= prev-path-refs (set (map :block/name (:block/path-refs updated-block)))) - "Path-refs remain the same")))) \ No newline at end of file + "Path-refs remain the same")))) + +(deftest save-block + (testing "Saving blocks" + (test-helper/load-test-files [{:file/path "foo.md" + :file/content "# foo"}]) + (let [repo test-helper/test-db + block-uuid (:block/uuid (model/get-block-by-page-name-and-block-route-name repo "foo" "foo")) + _ (let [_ (editor/save-block! repo block-uuid "# bar") + block (model/query-block-by-uuid block-uuid) + _ (is (= "# bar" (:block/content block)))]) + _ (let [_ (editor/save-block! repo block-uuid "# foo" {:properties {:foo "bar"}}) + block (model/query-block-by-uuid block-uuid) + _ (is (= "# foo\nfoo:: bar" (:block/content block)))]) + _ (let [_ (editor/save-block! repo block-uuid "# bar") + block (model/query-block-by-uuid block-uuid) + _ (is (= "# bar" (:block/content block)))])]))) From cf02fed0803cf0ea316956d69dd52b6ada6a3c10 Mon Sep 17 00:00:00 2001 From: clstb Date: Thu, 4 May 2023 22:53:12 +0200 Subject: [PATCH 77/81] feat: improve test comment --- src/test/frontend/handler/editor_test.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/frontend/handler/editor_test.cljs b/src/test/frontend/handler/editor_test.cljs index c674281b6f..5872d9ccf5 100644 --- a/src/test/frontend/handler/editor_test.cljs +++ b/src/test/frontend/handler/editor_test.cljs @@ -248,7 +248,7 @@ "Path-refs remain the same")))) (deftest save-block - (testing "Saving blocks" + (testing "Saving blocks with and without properties" (test-helper/load-test-files [{:file/path "foo.md" :file/content "# foo"}]) (let [repo test-helper/test-db From 7d50520f5d513cfdea710b3434220540d40f9f03 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 17 May 2023 10:48:01 -0400 Subject: [PATCH 78/81] test refactor Bring back helper and cleanup lets --- src/test/frontend/handler/editor_test.cljs | 29 ++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/test/frontend/handler/editor_test.cljs b/src/test/frontend/handler/editor_test.cljs index 5872d9ccf5..d30d6f31ed 100644 --- a/src/test/frontend/handler/editor_test.cljs +++ b/src/test/frontend/handler/editor_test.cljs @@ -8,13 +8,7 @@ [frontend.state :as state] [frontend.util.cursor :as cursor])) -(use-fixtures :each {:before (fn [] - ;; Set current-repo explicitly since it's not the default - (state/set-current-repo! test-helper/test-db) - (test-helper/start-test-db!)) - :after (fn [] - (state/set-current-repo! nil) - (test-helper/destroy-test-db!))}) +(use-fixtures :each test-helper/start-and-destroy-db) (deftest extract-nearest-link-from-text-test (testing "Page, block and tag links" @@ -247,18 +241,17 @@ (set (map :block/name (:block/path-refs updated-block)))) "Path-refs remain the same")))) -(deftest save-block +(deftest save-block! (testing "Saving blocks with and without properties" (test-helper/load-test-files [{:file/path "foo.md" :file/content "# foo"}]) (let [repo test-helper/test-db - block-uuid (:block/uuid (model/get-block-by-page-name-and-block-route-name repo "foo" "foo")) - _ (let [_ (editor/save-block! repo block-uuid "# bar") - block (model/query-block-by-uuid block-uuid) - _ (is (= "# bar" (:block/content block)))]) - _ (let [_ (editor/save-block! repo block-uuid "# foo" {:properties {:foo "bar"}}) - block (model/query-block-by-uuid block-uuid) - _ (is (= "# foo\nfoo:: bar" (:block/content block)))]) - _ (let [_ (editor/save-block! repo block-uuid "# bar") - block (model/query-block-by-uuid block-uuid) - _ (is (= "# bar" (:block/content block)))])]))) + block-uuid (:block/uuid (model/get-block-by-page-name-and-block-route-name repo "foo" "foo"))] + (editor/save-block! repo block-uuid "# bar") + (is (= "# bar" (:block/content (model/query-block-by-uuid block-uuid)))) + + (editor/save-block! repo block-uuid "# foo" {:properties {:foo "bar"}}) + (is (= "# foo\nfoo:: bar" (:block/content (model/query-block-by-uuid block-uuid)))) + + (editor/save-block! repo block-uuid "# bar") + (is (= "# bar" (:block/content (model/query-block-by-uuid block-uuid))))))) From 68da34ed0d08c77e960d6718a07e3f6bce6eb542 Mon Sep 17 00:00:00 2001 From: Bad3r Date: Wed, 17 May 2023 23:19:07 -0400 Subject: [PATCH 79/81] dev(playwright): Ignore conntection refused errors (#9426) * ignore connection refused errors * enhance: ignore connection errors --- e2e-tests/fixtures.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/e2e-tests/fixtures.ts b/e2e-tests/fixtures.ts index 79e923537a..16aea59a6b 100644 --- a/e2e-tests/fixtures.ts +++ b/e2e-tests/fixtures.ts @@ -21,22 +21,24 @@ export let graphDir = path.resolve(testTmpDir, "#e2e-test", repoName) // NOTE: This following is a console log watcher for error logs. // Save and print all logs when error happens. -let logs: string +let logs: string = ''; const consoleLogWatcher = (msg: ConsoleMessage) => { - // console.log(msg.text()) - const text = msg.text() - logs += text + '\n' + const text = msg.text(); - expect(text, logs).not.toMatch(/^(Failed to|Uncaught|Assert failed)/) + // List of error messages to ignore + const ignoreErrors = [ + /net::ERR_CONNECTION_REFUSED/, + /^Error with Permissions-Policy header:/ + ]; - // youtube video - // Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'ch-ua-reduced'. - if (!text.match(/^Error with Permissions-Policy header:/)) { - expect(text, logs).not.toMatch(/^Error/) + // If the text matches any of the ignoreErrors, return early + if (ignoreErrors.some(error => text.match(error))) { + return; } - // NOTE: React warnings will be logged as error. - // expect(msg.type()).not.toBe('error') + logs += text + '\n'; + expect(text, logs).not.toMatch(/^(Failed to|Uncaught|Assert failed)/); + expect(text, logs).not.toMatch(/^Error/); } base.beforeAll(async () => { From 51201124ffaecd5b472467f23021d25393748b92 Mon Sep 17 00:00:00 2001 From: Andelf Date: Wed, 17 May 2023 01:00:47 +0800 Subject: [PATCH 80/81] fix(fs): add unicode normalize to path-fn This is a catch-all type fix --- deps/common/src/logseq/common/path.cljs | 10 +++++----- src/main/frontend/fs/capacitor_fs.cljs | 3 +-- src/main/frontend/handler/common/file.cljs | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/deps/common/src/logseq/common/path.cljs b/deps/common/src/logseq/common/path.cljs index af22e2abc7..8553ef6dce 100644 --- a/deps/common/src/logseq/common/path.cljs +++ b/deps/common/src/logseq/common/path.cljs @@ -6,7 +6,7 @@ (defn- safe-decode-uri-component [uri] (try - (js/decodeURIComponent uri) + (.normalize (js/decodeURIComponent uri) "NFC") (catch :default _ (js/console.error "decode-uri-component-failed" uri) uri))) @@ -157,7 +157,6 @@ (defn path-join "Join path segments, or URL base and path segments" [base & segments] - (cond ;; For debugging ; (nil? base) @@ -190,9 +189,10 @@ (defn path-normalize "Normalize path or URL" [path] - (if (is-file-url? path) - (url-normalize path) - (path-normalize-internal path))) + (-> (if (is-file-url? path) + (url-normalize path) + (path-normalize-internal path)) + (.normalize "NFC"))) (defn url-to-path "Extract path part of a URL, decoded. diff --git a/src/main/frontend/fs/capacitor_fs.cljs b/src/main/frontend/fs/capacitor_fs.cljs index 8b87e0954c..9f1a42c0b3 100644 --- a/src/main/frontend/fs/capacitor_fs.cljs +++ b/src/main/frontend/fs/capacitor_fs.cljs @@ -238,8 +238,7 @@ (when-not contents-matched? (backup-file repo-dir :backup-dir fpath disk-content)) (db/set-file-last-modified-at! repo rpath mtime) - (p/let [content content] - (db/set-file-content! repo rpath content)) + (db/set-file-content! repo rpath content) (when ok-handler (ok-handler repo fpath result)) result) diff --git a/src/main/frontend/handler/common/file.cljs b/src/main/frontend/handler/common/file.cljs index b8f58f7198..337ee3281b 100644 --- a/src/main/frontend/handler/common/file.cljs +++ b/src/main/frontend/handler/common/file.cljs @@ -74,13 +74,13 @@ :fs/reset-event - the event that triggered the file update :fs/local-file-change - file changed on local disk :fs/remote-file-change - file changed on remote" - [repo-url file content {:fs/keys [event] :as options}] + [repo-url file-path content {:fs/keys [event] :as options}] (let [db-conn (db/get-db repo-url false)] (case event ;; the file is already in db, so we can use the existing file's blocks ;; to do the diff-merge :fs/local-file-change - (graph-parser/parse-file db-conn file content (assoc-in options [:extract-options :resolve-uuid-fn] diff-merge-uuids-2ways)) + (graph-parser/parse-file db-conn file-path content (assoc-in options [:extract-options :resolve-uuid-fn] diff-merge-uuids-2ways)) ;; TODO Junyi: 3 ways to handle remote file change ;; The file is on remote, so we should have @@ -90,7 +90,7 @@ ;; 2. a "remote version" just fetched from remote ;; default to parse the file - (graph-parser/parse-file db-conn file content options)))) + (graph-parser/parse-file db-conn file-path content options)))) (defn reset-file! "Main fn for updating a db with the results of a parsed file" From c917f2e087162502f9118cdf458c56f22f71db60 Mon Sep 17 00:00:00 2001 From: Andelf Date: Wed, 17 May 2023 01:02:19 +0800 Subject: [PATCH 81/81] fix(fs): use normalized relative path for mobile platform Fix #9378 --- .../main/java/com/logseq/app/FsWatcher.java | 9 +++-- ios/App/App/FsWatcher.swift | 36 +++++++++++++++++-- src/main/frontend/handler/events.cljs | 11 ++---- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/logseq/app/FsWatcher.java b/android/app/src/main/java/com/logseq/app/FsWatcher.java index 5bf70be0cd..3b07e9b5d9 100644 --- a/android/app/src/main/java/com/logseq/app/FsWatcher.java +++ b/android/app/src/main/java/com/logseq/app/FsWatcher.java @@ -10,6 +10,8 @@ import android.net.Uri; import java.io.*; +import java.net.URI; +import java.text.Normalizer; import java.util.HashMap; import java.util.Map; import java.util.Stack; @@ -90,8 +92,11 @@ public class FsWatcher extends Plugin { shouldRead = true; } - obj.put("path", Uri.fromFile(f)); - obj.put("dir", Uri.fromFile(new File(mPath))); + URI dir = (new File(mPath)).toURI(); + URI fpath = f.toURI(); + + obj.put("path", Normalizer.normalize(dir.relativize(fpath).toString(), Normalizer.Form.NFC)); + obj.put("dir", Uri.fromFile(new File(mPath))); // Uri is for Android. URI is for RFC compatible JSObject stat; switch (event) { diff --git a/ios/App/App/FsWatcher.swift b/ios/App/App/FsWatcher.swift index 578d389fbe..50c9ebded7 100644 --- a/ios/App/App/FsWatcher.swift +++ b/ios/App/App/FsWatcher.swift @@ -46,12 +46,16 @@ public class FsWatcher: CAPPlugin, PollingWatcherDelegate { } public func receivedNotification(_ url: URL, _ event: PollingWatcherEvent, _ metadata: SimpleFileMetadata?) { + guard let baseUrl = baseUrl else { + // unwatch, ignore incoming + return + } // NOTE: Event in js {dir path content stat{mtime}} switch event { case .Unlink: DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.notifyListeners("watcher", data: ["event": "unlink", - "dir": self.baseUrl?.description as Any, + "dir": baseUrl.description as Any, "path": url.description ]) } @@ -61,8 +65,8 @@ public class FsWatcher: CAPPlugin, PollingWatcherDelegate { content = try? String(contentsOf: url, encoding: .utf8) } self.notifyListeners("watcher", data: ["event": event.description, - "dir": baseUrl?.description as Any, - "path": url.description, + "dir": baseUrl.description as Any, + "path": url.relativePath(from: baseUrl)?.precomposedStringWithCanonicalMapping as Any, "content": content as Any, "stat": ["mtime": metadata?.contentModificationTimestamp ?? 0, "ctime": metadata?.creationTimestamp ?? 0, @@ -265,3 +269,29 @@ public class PollingWatcher { self.metaDb = newMetaDb } } + + +extension URL { + func relativePath(from base: URL) -> String? { + // Ensure that both URLs represent files: + guard self.isFileURL && base.isFileURL else { + return nil + } + + // Remove/replace "." and "..", make paths absolute: + let destComponents = self.standardizedFileURL.pathComponents + let baseComponents = base.standardizedFileURL.pathComponents + + // Find number of common path components: + var i = 0 + while i < destComponents.count && i < baseComponents.count + && destComponents[i] == baseComponents[i] { + i += 1 + } + + // Build relative path: + var relComponents = Array(repeating: "..", count: baseComponents.count - i) + relComponents.append(contentsOf: destComponents[i...]) + return relComponents.joined(separator: "/") + } +} diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index 368ae9ebbb..ef6f78390e 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -69,8 +69,7 @@ [logseq.db.schema :as db-schema] [logseq.graph-parser.config :as gp-config] [promesa.core :as p] - [rum.core :as rum] - [logseq.common.path :as path])) + [rum.core :as rum])) ;; TODO: should we move all events here? @@ -622,13 +621,7 @@ (defmethod handle :mobile-file-watcher/changed [[_ ^js event]] (let [type (.-event event) - payload (js->clj event :keywordize-keys true) - dir (:dir payload) - payload (-> payload - (update :path - (fn [path] - (when (string? path) - (path/relative-path dir path)))))] + payload (js->clj event :keywordize-keys true)] (fs-watcher/handle-changed! type payload) (when (file-sync-handler/enable-sync?) (sync/file-watch-handler type payload))))