mirror of https://github.com/logseq/logseq
Merge branch 'master' into perf/search
commit
57b9e7f937
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": [
|
||||
"stylelint-config-standard"
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignoreAtRules": [
|
||||
"tailwind",
|
||||
"apply",
|
||||
"variants",
|
||||
"responsive",
|
||||
"screen"
|
||||
]
|
||||
}
|
||||
],
|
||||
"declaration-block-trailing-semicolon": null,
|
||||
"no-descending-specificity": null,
|
||||
"declaration-empty-line-before": null,
|
||||
"block-no-empty": null
|
||||
}
|
||||
}
|
15
package.json
15
package.json
|
@ -3,8 +3,7 @@
|
|||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@tailwindcss/ui": "^0.1.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"@tailwindcss/ui": "0.7.2",
|
||||
"cssnano": "^4.1.10",
|
||||
"del": "^6.0.0",
|
||||
"gulp": "^4.0.2",
|
||||
|
@ -12,11 +11,14 @@
|
|||
"gulp-concat": "^2.6.1",
|
||||
"gulp-postcss": "^9.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^7.0.21",
|
||||
"postcss-cli": "^6.1.3",
|
||||
"purgecss": "^2.1.0",
|
||||
"postcss": "8.2.1",
|
||||
"postcss-cli": "8.3.0",
|
||||
"postcss-nested": "^5.0.1",
|
||||
"purgecss": "3.0.0",
|
||||
"shadow-cljs": "2.8.81",
|
||||
"tailwindcss": "^1.3.4"
|
||||
"stylelint": "^13.8.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"tailwindcss": "2.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "run-p cljs:watch gulp:build gulp:watch",
|
||||
|
@ -28,6 +30,7 @@
|
|||
"clean": "gulp clean",
|
||||
"test": "run-s cljs:test cljs:run-test",
|
||||
"report": "run-s cljs:report",
|
||||
"style:lint": "stylelint \"src/**/*.css\" ",
|
||||
"gulp:watch": "gulp watch",
|
||||
"gulp:build": "cross-env NODE_ENV=production gulp build",
|
||||
"cljs:watch": "clojure -M:cljs watch app publishing",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module.exports = (ctx) => ({
|
||||
plugins: [
|
||||
require("autoprefixer"),
|
||||
require("tailwindcss")("tailwind.config.js"),
|
||||
ctx.env === "production" ? require("cssnano")({ preset: "default" }) : null,
|
||||
require('postcss-nested'),
|
||||
require('tailwindcss')('tailwind.config.js'),
|
||||
ctx.env === 'production' ? require('cssnano')({ preset: 'default' }) : null,
|
||||
],
|
||||
});
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -313,7 +313,7 @@
|
|||
(rum/defc block-embed < rum/reactive db-mixins/query
|
||||
[config id]
|
||||
(let [blocks (db/get-block-and-children (state/get-current-repo) id)]
|
||||
[:div.ls-embed-block.bg-base-2
|
||||
[:div.color-level.embed-block.bg-base-2 {:style {:z-index 2}}
|
||||
[:div.px-3.pt-1.pb-2
|
||||
(blocks-container blocks (assoc config
|
||||
:embed? true
|
||||
|
@ -324,8 +324,9 @@
|
|||
(let [page-name (string/lower-case page-name)
|
||||
page-original-name (:page/original-name (db/entity [:page/name page-name]))
|
||||
current-page (state/get-current-page)]
|
||||
[:div.ls-embed-page.bg-base-2
|
||||
[:div.flex.items-center.p-1.embed-header
|
||||
[:div.color-level.embed.embed-page.bg-base-2
|
||||
{:class (if (:sidebar? config) "in-sidebar")}
|
||||
[:section.flex.items-center.p-1.embed-header
|
||||
[:div.mr-3 svg/page]
|
||||
(page-cp config {:page/name page-name})]
|
||||
(when (and
|
||||
|
@ -1100,9 +1101,7 @@
|
|||
(editor-handler/unhighlight-block!))}]
|
||||
[:div.flex.relative
|
||||
[:div.flex-1.flex-col.relative.block-content
|
||||
(cond-> {:id (str "block-content-" uuid)
|
||||
:style {:cursor "text"
|
||||
:min-height 24}}
|
||||
(cond-> {:id (str "block-content-" uuid)}
|
||||
(not slide?)
|
||||
(merge attrs))
|
||||
|
||||
|
@ -1158,8 +1157,7 @@
|
|||
(when (and start-time finish-time (> finish-time start-time))
|
||||
[:div.text-sm.absolute.time-spent {:style {:top 0
|
||||
:right 0
|
||||
:padding-left 2
|
||||
:z-index 4}
|
||||
:padding-left 2}
|
||||
:title (str (date/int->local-time start-time) " ~ " (date/int->local-time finish-time))}
|
||||
[:span.opacity-70
|
||||
(utils/timeConversion (- finish-time start-time))]])))]))
|
||||
|
@ -1624,7 +1622,7 @@
|
|||
;; TODO: speedup
|
||||
(if (re-find #"\"Export_Snippet\" \"embed\"" (str l))
|
||||
(->elem :div (map-inline config l))
|
||||
(->elem :p (map-inline config l)))
|
||||
(->elem :div.is-paragraph (map-inline config l)))
|
||||
|
||||
["Horizontal_Rule"]
|
||||
(when-not (:slide? config)
|
||||
|
@ -1812,7 +1810,7 @@
|
|||
sidebar?
|
||||
0
|
||||
:else
|
||||
-18)}}
|
||||
-10)}}
|
||||
(let [first-block (first blocks)
|
||||
blocks' (if (and (:block/pre-block? first-block)
|
||||
(db/pre-block-with-only-title? (:block/repo first-block) (:block/uuid first-block)))
|
||||
|
|
|
@ -2,16 +2,130 @@
|
|||
}
|
||||
|
||||
.block-content {
|
||||
min-height: 24px;
|
||||
max-width: 100%;
|
||||
overflow: initial;
|
||||
cursor: text;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.block-children {
|
||||
}
|
||||
|
||||
.ls-block {
|
||||
.embed-page {
|
||||
@apply py-2 my-2 px-2;
|
||||
|
||||
> section {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
&.in-sidebar {
|
||||
background-color: var(--ls-tertiary-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
.block-content img {
|
||||
width: 100%;
|
||||
.color-level {
|
||||
background-color: var(--color-level-1);
|
||||
}
|
||||
|
||||
.color-level .color-level {
|
||||
background-color: var(--color-level-2);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
|
||||
.ls-block {
|
||||
min-height: 24px;
|
||||
|
||||
img {
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
.ls-block,
|
||||
.foldable-title {
|
||||
max-width: var(--ls-main-content-max-width);
|
||||
}
|
||||
|
||||
.ls-block,
|
||||
.editor-wrapper {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.ls-block h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0
|
||||
}
|
||||
|
||||
.ls-block h2 {
|
||||
font-size: 1.5em;
|
||||
margin: 0.75em 0
|
||||
}
|
||||
|
||||
.ls-block h3 {
|
||||
font-size: 1.17em;
|
||||
margin: 0.83em 0
|
||||
}
|
||||
|
||||
.ls-block h4 {
|
||||
margin: 1.12em 0
|
||||
}
|
||||
|
||||
.ls-block h5 {
|
||||
font-size: 0.83em;
|
||||
margin: 1.5em 0
|
||||
}
|
||||
|
||||
.ls-block h6 {
|
||||
font-size: 0.75em;
|
||||
margin: 1.67em 0
|
||||
}
|
||||
|
||||
.ls-block h1,
|
||||
.ls-block h2,
|
||||
.ls-block h3,
|
||||
.ls-block h4,
|
||||
.ls-block h5,
|
||||
.ls-block h6 {
|
||||
font-weight: 600
|
||||
}
|
||||
|
||||
/* copied from https://github.com/drdogbot7/tailwindcss-responsive-embed */
|
||||
|
@ -35,7 +149,6 @@
|
|||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.embed {
|
||||
|
@ -45,117 +158,3 @@
|
|||
.embed-header {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.ls-embed-page {
|
||||
@apply color-level embed py-2 my-2 px-3;
|
||||
}
|
||||
|
||||
.ls-embed-block {
|
||||
@apply color-level embed;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
--color-level-1: var(--ls-secondary-background-color);
|
||||
--color-level-2: var(--ls-tertiary-background-color);
|
||||
--color-level-3: var(--ls-quaternary-background-color);
|
||||
--color-level-4: #195D6C;
|
||||
--color-level-5: #266C7D;
|
||||
--color-level-6: #3A7E8E;
|
||||
}
|
||||
|
||||
.white-theme {
|
||||
--color-level-1: var(--ls-secondary-background-color);
|
||||
--color-level-2: var(--ls-tertiary-background-color);
|
||||
--color-level-3: var(--ls-quaternary-background-color);
|
||||
--color-level-4: #d0e6fa;
|
||||
--color-level-5: #bbdaf6;
|
||||
/* --color-level-4: #b7d7c9;
|
||||
--color-level-5: #a5cdbc;
|
||||
--color-level-6: #92c2af; */
|
||||
}
|
||||
|
||||
.color-level {
|
||||
background-color: var(--color-level-1);
|
||||
}
|
||||
.color-level .color-level {
|
||||
background-color: var(--color-level-2);
|
||||
}
|
||||
.color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-3);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-4);
|
||||
}
|
||||
.color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level .color-level {
|
||||
background-color: var(--color-level-5);
|
||||
}
|
||||
|
||||
.ls-block {
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.ls-block, .foldable-title {
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.ls-block, .editor-wrapper {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.ls-block img {
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 10px 10px -5px rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
|
||||
.ls-block h1 {
|
||||
font-size: 2em;
|
||||
margin: .67em 0
|
||||
}
|
||||
|
||||
.ls-block h2 {
|
||||
font-size: 1.5em;
|
||||
margin: .75em 0
|
||||
}
|
||||
|
||||
.ls-block h3 {
|
||||
font-size: 1.17em;
|
||||
margin: .83em 0
|
||||
}
|
||||
|
||||
.ls-block h4 {
|
||||
margin: 1.12em 0
|
||||
}
|
||||
|
||||
.ls-block h5 {
|
||||
font-size: .83em;
|
||||
margin: 1.5em 0
|
||||
}
|
||||
|
||||
.ls-block h6 {
|
||||
font-size: .75em;
|
||||
margin: 1.67em 0
|
||||
}
|
||||
|
||||
.ls-block h1, .ls-block h2, .ls-block h3, .ls-block h4, .ls-block h5, .ls-block h6 {
|
||||
font-weight: 600
|
||||
}
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.non-block-editor textarea, pre {
|
||||
.non-block-editor textarea,
|
||||
pre {
|
||||
display: block;
|
||||
padding: 0.5rem;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, .02);
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.02);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.non-block-editor textarea {
|
||||
background: #F6F8FA;
|
||||
background: #f6f8fa;
|
||||
background: var(--ls-secondary-background-color);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
.cp__header {
|
||||
@apply shadow z-10 h-16 pr-4;
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
@apply shadow z-10 h-12 pr-4;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.cp__header-left-menu {
|
||||
@apply px-4 mr-4;
|
||||
border-right: 1px solid var(--ls-secondary-background-color);
|
||||
color: var(--ls-link-text-color);
|
||||
display: block;
|
||||
height: 100%;
|
||||
@apply px-4 mr-4;
|
||||
border-right: 1px solid var(--ls-secondary-background-color);
|
||||
color: var(--ls-link-text-color);
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.cp__header-left-menu:focus {
|
||||
@apply outline-none;
|
||||
background: var(--ls-menu-hover-color);
|
||||
@apply outline-none;
|
||||
background: var(--ls-menu-hover-color);
|
||||
}
|
||||
|
||||
.cp__header-logo {
|
||||
@apply px-4 mr-3;
|
||||
height: 100%;
|
||||
@apply px-4 mr-3;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.cp__header-logo,
|
||||
.cp__right-menu-button {
|
||||
opacity: 0.7;
|
||||
display: none;
|
||||
opacity: 0.7;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cp__header-logo:hover,
|
||||
.cp__right-menu-button:hover {
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cp__header-logo-img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.cp__right-menu-button {
|
||||
@apply ml-3;
|
||||
@apply ml-3;
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
.cp__header {
|
||||
@apply h-12 shadow-none;
|
||||
}
|
||||
.cp__header {
|
||||
@apply shadow-none;
|
||||
}
|
||||
|
||||
.cp__header-left-menu {
|
||||
display: none;
|
||||
}
|
||||
.cp__header-left-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cp__header-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.cp__header-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cp__right-menu-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.cp__right-menu-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
last-pulled-at (db/sub-key-value repo :git/last-pulled-at)
|
||||
;; db-persisted? (state/sub [:db/persisted? repo])
|
||||
editing? (seq (state/sub :editor/editing?))]
|
||||
[:div.flex-row.flex.items-center
|
||||
[:div.flex-row.flex.items-center.cp__repo-indicator
|
||||
(when pushing?
|
||||
[:span.lds-dual-ring.mt-1])
|
||||
(ui/dropdown
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.cp__repo-indicator {
|
||||
.sync-content {
|
||||
max-height: 80vh;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
|
@ -226,36 +226,28 @@
|
|||
dark? (= "dark" theme)
|
||||
t (i18n/use-tongue)]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div#right-sidebar.flex-col {:style {:height "100%"
|
||||
:overflow "hidden"
|
||||
:flex (if sidebar-open?
|
||||
"1 0 40%"
|
||||
"0 0 0px")}}
|
||||
[:div#right-sidebar.cp__right-sidebar
|
||||
{:class (if sidebar-open? "is-open")}
|
||||
(if sidebar-open?
|
||||
[:div.hide-scrollbar {:style {:flex "1 1 auto"
|
||||
:padding 12
|
||||
:height "100%"
|
||||
:overflow-y "auto"
|
||||
:overflow-x "hidden"
|
||||
:box-sizing "content-box"}}
|
||||
[:div.flex.flex-row.mb-2 {:key "right-sidebar-settings"}
|
||||
[:div.mr-4.text-sm
|
||||
[:a.right-sidebar-button {:on-click (fn [e]
|
||||
[:div.cp__right-sidebar-inner
|
||||
[:div.cp__right-sidebar-settings.hide-scrollbar {:key "right-sidebar-settings"}
|
||||
[:div.ml-4.text-sm
|
||||
[:a.cp__right-sidebar-settings-btn {:on-click (fn [e]
|
||||
(state/sidebar-add-block! repo "contents" :contents nil))}
|
||||
(t :right-side-bar/contents)]]
|
||||
|
||||
[:div.mr-4.text-sm
|
||||
[:a.right-sidebar-button {:on-click (fn [_e]
|
||||
[:div.ml-4.text-sm
|
||||
[:a.cp__right-sidebar-settings-btn {:on-click (fn [_e]
|
||||
(state/sidebar-add-block! repo "recent" :recent nil))}
|
||||
(t :right-side-bar/recent)]]
|
||||
|
||||
(when config/publishing?
|
||||
[:div.mr-4.text-sm
|
||||
[:div.ml-4.text-sm
|
||||
[:a {:href (rfe/href :all-pages)}
|
||||
(t :all-pages)]])
|
||||
|
||||
[:div.mr-4.text-sm
|
||||
[:a.right-sidebar-button {:on-click (fn []
|
||||
[:div.ml-4.text-sm
|
||||
[:a.cp__right-sidebar-settings-btn {:on-click (fn []
|
||||
(when-let [page (get-current-page)]
|
||||
(state/sidebar-add-block!
|
||||
repo
|
||||
|
@ -264,16 +256,16 @@
|
|||
page)))}
|
||||
(t :right-side-bar/page)]]
|
||||
|
||||
[:div.mr-4.text-sm
|
||||
[:div.ml-4.text-sm
|
||||
(let [theme (if dark? "white" "dark")]
|
||||
[:a.right-sidebar-button {:title (t :right-side-bar/switch-theme theme)
|
||||
[:a.cp__right-sidebar-settings-btn {:title (t :right-side-bar/switch-theme theme)
|
||||
:on-click (fn []
|
||||
(state/set-theme! theme))}
|
||||
(t :right-side-bar/theme (t (keyword theme)))])]
|
||||
|
||||
(when-not config/publishing?
|
||||
[:div.mr-4.text-sm
|
||||
[:a.right-sidebar-button {:on-click (fn [_e]
|
||||
[:div.ml-4.text-sm
|
||||
[:a.cp__right-sidebar-settings-btn {:on-click (fn [_e]
|
||||
(state/sidebar-add-block! repo "help" :help nil))}
|
||||
(t :right-side-bar/help)]])]
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
{:for "enable_timetracking"}
|
||||
(t :settings-page/enable-timetracking)]
|
||||
[:div.mt-1.sm:mt-0.sm:col-span-2
|
||||
[:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
|
||||
[:div.max-w-lg.rounded-md.sm:max-w-xs
|
||||
(ui/toggle enable-timetracking?
|
||||
(fn []
|
||||
(let [value (not enable-timetracking?)]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns frontend.components.sidebar
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.components.theme :as theme]
|
||||
[frontend.mixins :as mixins]
|
||||
[frontend.db-mixins :as db-mixins]
|
||||
[frontend.db :as db]
|
||||
|
@ -38,8 +39,8 @@
|
|||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d svg-d
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-width "2"
|
||||
:stroke-linejoin "round"
|
||||
:stroke-linecap "round"}]]
|
||||
title])
|
||||
|
||||
|
@ -52,7 +53,7 @@
|
|||
right-sidebar? (state/sub :ui/sidebar-open?)
|
||||
left-sidebar? (state/sub :ui/left-sidebar-open?)]
|
||||
(when left-sidebar?
|
||||
[:nav.flex-1
|
||||
[:nav.flex-1.left-sidebar-inner
|
||||
(nav-item "Journals" "/"
|
||||
"M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10M9 21h6"
|
||||
(active? :home)
|
||||
|
@ -97,7 +98,7 @@
|
|||
:stroke-linejoin "round"
|
||||
:stroke-linecap "round"}]]]])
|
||||
[:div.flex-shrink-0.flex.items-center.px-4.h-16 {:style {:background-color "#002b36"}}
|
||||
(repo/repos-dropdown false)]
|
||||
(repo/repos-dropdown false nil)]
|
||||
[:div.flex-1.h-0.overflow-y-auto
|
||||
(sidebar-nav route-match close-fn)]]])
|
||||
|
||||
|
@ -236,9 +237,8 @@
|
|||
(when-not (state/sub :ui/sidebar-open?)
|
||||
;; TODO: remove with-context usage
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div#help.font-bold.absolute.bottom-4.bg-base-2.rounded-full.h-8.w-8.flex.items-center.justify-center.font-bold.cursor.opacity-70.hover:opacity-100
|
||||
{:style {:right 24}
|
||||
:title (t :help-shortcut-title)
|
||||
[:div.cp__sidebar-help
|
||||
{:title (t :help-shortcut-title)
|
||||
:on-click (fn []
|
||||
(state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
|
||||
"?"])))
|
||||
|
@ -300,6 +300,7 @@
|
|||
current-repo (state/sub :git/current-repo)
|
||||
theme (state/sub :ui/theme)
|
||||
white? (= "white" (state/sub :ui/theme))
|
||||
sidebar-open? (state/sub :ui/sidebar-open?)
|
||||
route-name (get-in route-match [:data :name])
|
||||
global-graph-pages? (= :graph route-name)
|
||||
logged? (:name me)
|
||||
|
@ -309,44 +310,49 @@
|
|||
home? (= :home route-name)
|
||||
default-home (get-default-home-if-valid)]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div {:class (if white? "white-theme" "dark-theme")
|
||||
:on-click editor-handler/unhighlight-block!}
|
||||
(sidebar-mobile-sidebar {:open? open?
|
||||
:close-fn close-fn
|
||||
:route-match route-match})
|
||||
(theme/container
|
||||
{:theme theme
|
||||
:on-click editor-handler/unhighlight-block!}
|
||||
|
||||
[:div.cp__sidebar-layout.h-screen
|
||||
(header/header {:open-fn open-fn
|
||||
:white? white?
|
||||
:current-repo current-repo
|
||||
:logged? logged?
|
||||
:page? page?
|
||||
:route-match route-match
|
||||
:me me
|
||||
:default-home default-home
|
||||
:new-block-mode new-block-mode})
|
||||
[:div.theme-inner
|
||||
(sidebar-mobile-sidebar
|
||||
{:open? open?
|
||||
:close-fn close-fn
|
||||
:route-match route-match})
|
||||
[:div.#app-container.cp__sidebar-layout
|
||||
{:class (if sidebar-open? "is-right-sidebar-open")}
|
||||
(header/header {:open-fn open-fn
|
||||
:white? white?
|
||||
:current-repo current-repo
|
||||
:logged? logged?
|
||||
:page? page?
|
||||
:route-match route-match
|
||||
:me me
|
||||
:default-home default-home
|
||||
:new-block-mode new-block-mode})
|
||||
|
||||
(sidebar-main {:route-match route-match
|
||||
:global-graph-pages? global-graph-pages?
|
||||
:logged? logged?
|
||||
:home? home?
|
||||
:route-name route-name
|
||||
:indexeddb-support? indexeddb-support?
|
||||
:white? white?
|
||||
:db-restoring? db-restoring?
|
||||
:main-content main-content})]
|
||||
(sidebar-main {:route-match route-match
|
||||
:global-graph-pages? global-graph-pages?
|
||||
:logged? logged?
|
||||
:home? home?
|
||||
:route-name route-name
|
||||
:indexeddb-support? indexeddb-support?
|
||||
:white? white?
|
||||
:db-restoring? db-restoring?
|
||||
:main-content main-content})]
|
||||
|
||||
(ui/notification)
|
||||
(ui/modal)
|
||||
(custom-context-menu)
|
||||
[:a#download.hidden]
|
||||
(when (and (not config/mobile?)
|
||||
(not config/publishing?))
|
||||
(help-button)
|
||||
(ui/notification)
|
||||
(ui/modal)
|
||||
(custom-context-menu)
|
||||
[:a#download.hidden]
|
||||
(when
|
||||
(and (not config/mobile?)
|
||||
(not config/publishing?))
|
||||
(help-button)
|
||||
;; [:div.font-bold.absolute.bottom-4.bg-base-2.rounded-full.h-8.w-8.flex.items-center.justify-center.font-bold.cursor.opacity-70.hover:opacity-100
|
||||
;; {:style {:left 24}
|
||||
;; :title "Click to show/hide sidebar"
|
||||
;; :on-click (fn []
|
||||
;; (state/set-left-sidebar-open! (not (state/get-left-sidebar-open?))))}
|
||||
;; (if (state/sub :ui/left-sidebar-open?) "<" ">")]
|
||||
)])))
|
||||
)]))))
|
||||
|
|
|
@ -1,36 +1,160 @@
|
|||
#left-sidebar {
|
||||
width: 240px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: -240px;
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
opacity: 0;
|
||||
transition: all 0.25s;
|
||||
-webkit-transition: all 0.25s;
|
||||
background-color: #002b36;
|
||||
|
||||
.enter {
|
||||
opacity: 1;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#left-bar {
|
||||
.left-sidebar-inner {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.cp__sidebar-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.cp__sidebar-main-layout {
|
||||
flex: 1 1 0;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
background-color: var(--ls-primary-background-color);
|
||||
}
|
||||
|
||||
.cp__sidebar-layout.is-right-sidebar-open {
|
||||
.cp__sidebar-main-layout {
|
||||
margin-right: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
.cp__sidebar-main-content-container {
|
||||
position: relative;
|
||||
flex: 1 1 65%;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cp__sidebar-main-content {
|
||||
padding: 3rem 1.5rem;
|
||||
margin: 0 auto;
|
||||
max-width: 700px;
|
||||
padding: 3rem 1.5rem;
|
||||
max-width: var(--ls-main-content-max-width);
|
||||
min-height: 100vh;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.cp__sidebar-main-content {
|
||||
max-width: 100vw;
|
||||
.cp__sidebar-help {
|
||||
@apply font-bold fixed bottom-4
|
||||
rounded-full h-8 w-8 flex items-center justify-center font-bold
|
||||
opacity-70 hover:opacity-100;
|
||||
|
||||
user-select: none;
|
||||
cursor: help;
|
||||
right: 24px;
|
||||
background-color: var(--ls-secondary-background-color);
|
||||
}
|
||||
|
||||
.cp__right-sidebar {
|
||||
position: fixed;
|
||||
top: 3rem;
|
||||
right: 0;
|
||||
width: 0;
|
||||
opacity: 0.5;
|
||||
height: calc(100vh - 3rem);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
z-index: 9;
|
||||
transition: width 0.3s, opacity 0.2s;
|
||||
border-radius: var(--ls-border-radius-low) 0 0 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
background-color: var(--ls-secondary-background-color, #d8e1e8);
|
||||
padding-bottom: 48px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-inner {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
&-settings {
|
||||
@apply flex flex-row mb-2;
|
||||
margin: -15px;
|
||||
margin-bottom: 0;
|
||||
overflow: auto;
|
||||
|
||||
&-btn {
|
||||
display: block;
|
||||
padding: 10px 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
display: block;
|
||||
width: 40%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.page {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.non-block-editor textarea,
|
||||
pre,
|
||||
pre.code {
|
||||
background: var(--ls-right-sidebar-code-bg-color);
|
||||
}
|
||||
|
||||
pre.CodeMirror-line {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.references {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.sidebar-item {
|
||||
border-top: 1px solid;
|
||||
border-top-color: #ccc;
|
||||
border-top-color: var(--ls-border-color);
|
||||
margin-bottom: 24px;
|
||||
padding-top: 24px;
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.close {
|
||||
transform: scale(0.8);
|
||||
transition: transform 0.1s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp__sidebar-main-content[data-is-full-width="true"] {
|
||||
max-width: 100vw;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
.cp__sidebar-main-content[data-is-global-graph-pages="true"] {
|
||||
padding: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,17 @@
|
|||
[:path
|
||||
{:d
|
||||
"M64.177 100.069a7.889 7.889 0 01-5.6-2.316l-55.98-55.98a7.92 7.92 0 010-11.196c3.086-3.085 8.105-3.092 11.196 0l50.382 50.382 50.382-50.382a7.92 7.92 0 0111.195 0c3.086 3.086 3.092 8.104 0 11.196l-55.98 55.98a7.892 7.892 0 01-5.595 2.316z"}]])
|
||||
|
||||
(defonce loading
|
||||
[:svg.h-5.w-5.animate-spin
|
||||
{:version "1.1"
|
||||
:view-box "0 0 24 24"
|
||||
:fill "none"
|
||||
:display "inline-block"}
|
||||
[:circle.opacity-25 {:cx 12 :cy 12 :r 10 :stroke "currentColor" :stroke-width 4}]
|
||||
[:path.opacity-75 {:fill "currentColor"
|
||||
:d "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"}]])
|
||||
|
||||
(defn- hero-icon
|
||||
([d]
|
||||
(hero-icon d {}))
|
||||
|
@ -169,7 +180,6 @@
|
|||
:stroke-linecap "round"
|
||||
:stroke-width "2"
|
||||
:d "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"}]])
|
||||
|
||||
(def save
|
||||
[:svg
|
||||
{:fill "currentColor", :view-box "0 0 448 512", :height "24", :width "24"}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
(ns frontend.components.theme
|
||||
(:require [rum.core :as rum]))
|
||||
|
||||
(rum/defc container
|
||||
[{:keys [theme on-click] :as props} child]
|
||||
rum/use-effect! (let [doc js/document.documentElement
|
||||
cls (.-classList doc)]
|
||||
(.setAttribute doc "data-theme" (if (= theme "white") "light" theme))
|
||||
(if (= theme "dark") ;; for tailwind dark mode
|
||||
(.add cls "dark")
|
||||
(.remove cls "dark")))
|
||||
|
||||
[theme]
|
||||
[:div
|
||||
{:class (str theme "-theme")
|
||||
:on-click on-click}
|
||||
child])
|
|
@ -0,0 +1,40 @@
|
|||
:root {
|
||||
scrollbar-color: var(--ls-scrollbar-foreground-color) var(--ls-scrollbar-background-color) !important;
|
||||
scrollbar-width: thin !important;
|
||||
}
|
||||
|
||||
html:not(.is-mac)[data-theme=dark] {
|
||||
&::-webkit-scrollbar,
|
||||
html::-webkit-scrollbar-track-piece {
|
||||
background-color: var(--ls-scrollbar-background-color);
|
||||
border: 4px solid;
|
||||
border-color: var(--ls-scrollbar-background-color);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--ls-scrollbar-foreground-color);
|
||||
background-clip: padding-box;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--ls-scrollbar-thumb-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme=dark] {
|
||||
input {
|
||||
color: var(--ls-secondary-text-color);
|
||||
}
|
||||
|
||||
input.form-input {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.form-checkbox {
|
||||
color: var(--ls-page-checkbox-color, #6093a0);
|
||||
background-color: var(--ls-page-checkbox-color, #6093a0);
|
||||
border-color: var(--ls-page-checkbox-border-color, #6093a0);
|
||||
border: none;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
"The File System Access API, https://web.dev/file-system-access/."
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[promesa.core :as p]
|
||||
[medley.core :as medley]
|
||||
[goog.object :as gobj]
|
||||
[goog.dom :as gdom]
|
||||
[frontend.util :as util]
|
||||
|
@ -57,12 +58,30 @@
|
|||
(keyword (util/get-file-ext (:file/path file)))))
|
||||
files))
|
||||
|
||||
(defn- set-batch!
|
||||
[handles]
|
||||
(let [handles (map (fn [[path handle]]
|
||||
{:key path
|
||||
:value handle}) handles)]
|
||||
(idb/set-batch! handles)))
|
||||
|
||||
(defn- set-files-aux!
|
||||
[handles]
|
||||
(if (seq handles)
|
||||
(let [[h t] (split-at 50 handles)]
|
||||
(p/let [_ (p/promise (fn [_]
|
||||
(js/setTimeout (fn []
|
||||
(p/resolved nil)) 10)))
|
||||
_ (set-batch! h)]
|
||||
(when (seq t)
|
||||
(set-files-aux! t))))))
|
||||
|
||||
(defn- set-files!
|
||||
[handles]
|
||||
(doseq [[path handle] handles]
|
||||
(let [handle-path (str config/local-handle-prefix path)]
|
||||
(idb/set-item! handle-path handle)
|
||||
(fs/add-nfs-file-handle! handle-path handle))))
|
||||
(fs/add-nfs-file-handle! handle-path handle)))
|
||||
(set-files-aux! handles))
|
||||
|
||||
(defn ls-dir-files
|
||||
[]
|
||||
|
@ -223,7 +242,7 @@
|
|||
(rename-f "modify" modified))]
|
||||
(when (or (and (seq diffs) (seq modified-files))
|
||||
(seq diffs) ; delete
|
||||
)
|
||||
)
|
||||
(repo-handler/load-repo-to-db! repo
|
||||
{:diffs diffs
|
||||
:nfs-files modified-files})))))))))
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
(ns frontend.idb
|
||||
(:require ["localforage" :as localforage]
|
||||
[cljs-bean.core :as bean]
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[goog.object :as gobj]
|
||||
[promesa.core :as p]
|
||||
[clojure.string :as string]
|
||||
[frontend.config :as config]
|
||||
[frontend.util :as util]
|
||||
[frontend.storage :as storage]))
|
||||
[frontend.storage :as storage]
|
||||
["/frontend/idbkv" :as idb-keyval :refer [Store]]))
|
||||
|
||||
|
||||
;; offline db
|
||||
(def store-name "dbs")
|
||||
(.config localforage
|
||||
(bean/->js
|
||||
{:name "logseq-datascript"
|
||||
:version 1.0
|
||||
:storeName store-name}))
|
||||
|
||||
(defonce localforage-instance (.createInstance localforage store-name))
|
||||
;; To maintain backward compatibility
|
||||
|
||||
|
||||
(defonce store (Store. "localforage" "keyvaluepairs" 2))
|
||||
|
||||
(defn clear-idb!
|
||||
[]
|
||||
(p/let [_ (.clear localforage-instance)
|
||||
(p/let [_ (idb-keyval/clear store)
|
||||
dbs (js/window.indexedDB.databases)]
|
||||
(doseq [db dbs]
|
||||
(js/window.indexedDB.deleteDatabase (gobj/get db "name")))))
|
||||
|
@ -33,21 +31,26 @@
|
|||
(defn remove-item!
|
||||
[key]
|
||||
(when key
|
||||
(.removeItem localforage-instance key)))
|
||||
(idb-keyval/del key store)))
|
||||
|
||||
(defn set-item!
|
||||
[key value]
|
||||
(when key
|
||||
(.setItem localforage-instance key value)))
|
||||
(idb-keyval/set key value store)))
|
||||
|
||||
(defn set-batch!
|
||||
[items]
|
||||
(when (seq items)
|
||||
(idb-keyval/setBatch (clj->js items) store)))
|
||||
|
||||
(defn get-item
|
||||
[key]
|
||||
(when key
|
||||
(.getItem localforage-instance key)))
|
||||
(idb-keyval/get key store)))
|
||||
|
||||
(defn get-keys
|
||||
[]
|
||||
(.keys localforage-instance))
|
||||
(idb-keyval/keys store))
|
||||
|
||||
(defn get-nfs-dbs
|
||||
[]
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
class Store {
|
||||
constructor(dbName = 'keyval-store', storeName = 'keyval', version = 1) {
|
||||
this.storeName = storeName;
|
||||
this._dbName = dbName;
|
||||
this._storeName = storeName;
|
||||
this._version = version;
|
||||
this.id = `dbName:${dbName};;storeName:${storeName}`;
|
||||
this._init();
|
||||
}
|
||||
_init() {
|
||||
if (this._dbp) {
|
||||
return;
|
||||
}
|
||||
this._dbp = new Promise((resolve, reject) => {
|
||||
const openreq = indexedDB.open(this._dbName, this._version);
|
||||
openreq.onerror = () => reject(openreq.error);
|
||||
openreq.onsuccess = () => resolve(openreq.result);
|
||||
// First time setup: create an empty object store
|
||||
openreq.onupgradeneeded = () => {
|
||||
openreq.result.createObjectStore(this._storeName);
|
||||
};
|
||||
});
|
||||
}
|
||||
_withIDBStore(type, callback) {
|
||||
this._init();
|
||||
return this._dbp.then(db => new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction(this.storeName, type);
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onabort = transaction.onerror = () => reject(transaction.error);
|
||||
callback(transaction.objectStore(this.storeName));
|
||||
}));
|
||||
}
|
||||
_close() {
|
||||
this._init();
|
||||
return this._dbp.then(db => {
|
||||
db.close();
|
||||
this._dbp = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
class Batcher {
|
||||
constructor(executor) {
|
||||
this.executor = executor;
|
||||
this.items = [];
|
||||
}
|
||||
async process() {
|
||||
const toProcess = this.items;
|
||||
this.items = [];
|
||||
await this.executor(toProcess.map(({ item }) => item));
|
||||
toProcess.map(({ onProcessed }) => onProcessed());
|
||||
if (this.items.length) {
|
||||
this.ongoing = this.process();
|
||||
}
|
||||
else {
|
||||
this.ongoing = undefined;
|
||||
}
|
||||
}
|
||||
async queue(item) {
|
||||
const result = new Promise((resolve) => this.items.push({ item, onProcessed: resolve }));
|
||||
if (!this.ongoing)
|
||||
this.ongoing = this.process();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
let store;
|
||||
function getDefaultStore() {
|
||||
if (!store)
|
||||
store = new Store();
|
||||
return store;
|
||||
}
|
||||
function get(key, store = getDefaultStore()) {
|
||||
let req;
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
req = store.get(key);
|
||||
}).then(() => req.result);
|
||||
}
|
||||
const setBatchers = {};
|
||||
function set(key, value, store = getDefaultStore()) {
|
||||
if (!setBatchers[store.id]) {
|
||||
setBatchers[store.id] = new Batcher((items) => store._withIDBStore('readwrite', store => {
|
||||
for (const item of items) {
|
||||
store.put(item.value, item.key);
|
||||
}
|
||||
}));
|
||||
}
|
||||
return setBatchers[store.id].queue({ key, value });
|
||||
}
|
||||
function setBatch(items, store = getDefaultStore()) {
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
for (const item of items) {
|
||||
store.put(item.value, item.key);
|
||||
}
|
||||
});
|
||||
}
|
||||
function update(key, updater, store = getDefaultStore()) {
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
const req = store.get(key);
|
||||
req.onsuccess = () => {
|
||||
store.put(updater(req.result), key);
|
||||
};
|
||||
});
|
||||
}
|
||||
function del(key, store = getDefaultStore()) {
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
store.delete(key);
|
||||
});
|
||||
}
|
||||
function clear(store = getDefaultStore()) {
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
store.clear();
|
||||
});
|
||||
}
|
||||
function keys(store = getDefaultStore()) {
|
||||
const keys = [];
|
||||
return store._withIDBStore('readwrite', store => {
|
||||
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
|
||||
// And openKeyCursor isn't supported by Safari.
|
||||
(store.openKeyCursor || store.openCursor).call(store).onsuccess = function () {
|
||||
if (!this.result)
|
||||
return;
|
||||
keys.push(this.result.key);
|
||||
this.result.continue();
|
||||
};
|
||||
}).then(() => keys);
|
||||
}
|
||||
function close(store = getDefaultStore()) {
|
||||
return store._close();
|
||||
}
|
||||
|
||||
exports.Store = Store;
|
||||
exports.get = get;
|
||||
exports.set = set;
|
||||
exports.setBatch = setBatch;
|
||||
exports.update = update;
|
||||
exports.del = del;
|
||||
exports.clear = clear;
|
||||
exports.keys = keys;
|
||||
exports.close = close;
|
|
@ -93,7 +93,7 @@
|
|||
[:div {:style {:margin-right "8px"}} title]
|
||||
;; [:div {:style {:position "absolute" :right "8px"}}
|
||||
;; icon]
|
||||
]]
|
||||
]]
|
||||
(rum/with-key
|
||||
(menu-link new-options child)
|
||||
title)))])
|
||||
|
@ -123,7 +123,7 @@
|
|||
(let [[color-class svg]
|
||||
(case status
|
||||
:success
|
||||
["text-gray-900"
|
||||
["text-gray-900 dark:text-gray-300 "
|
||||
[:svg.h-6.w-6.text-green-400
|
||||
{:stroke "currentColor", :viewBox "0 0 24 24", :fill "none"}
|
||||
[:path
|
||||
|
@ -149,7 +149,7 @@
|
|||
:d
|
||||
"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
||||
:fill-rule "evenodd"}]]])]
|
||||
[:div.inset-0.flex.items-end.justify-center.px-4.py-3.pointer-events-none.sm:px-6.sm:py-3.sm:items-start.sm:justify-end
|
||||
[:div.ui__notifications-content
|
||||
{:style {:z-index (if (or (= state "exiting")
|
||||
(= state "exited"))
|
||||
-1
|
||||
|
@ -186,7 +186,7 @@
|
|||
[]
|
||||
(let [contents (state/sub :notification/contents)]
|
||||
(transition-group
|
||||
{:class-name "notifications"}
|
||||
{:class-name "notifications ui__notifications"}
|
||||
(doall (map (fn [el]
|
||||
(let [k (first el)
|
||||
v (second el)]
|
||||
|
@ -209,6 +209,9 @@
|
|||
text])
|
||||
|
||||
;; scroll
|
||||
(defn get-doc-scroll-top []
|
||||
(.-scrollTop js/document.documentElement))
|
||||
|
||||
(defn main-node
|
||||
[]
|
||||
(gdom/getElement "main-content"))
|
||||
|
@ -223,6 +226,7 @@
|
|||
(defn inject-document-devices-envs!
|
||||
[]
|
||||
(let [cl (.-classList js/document.documentElement)]
|
||||
(if (util/mac?) (.add cl "is-mac"))
|
||||
(if (util/ios?) (.add cl "is-ios"))
|
||||
(if (util/safari?) (.add cl "is-safari"))))
|
||||
|
||||
|
@ -268,7 +272,7 @@
|
|||
;; FIXME: compute the right scroll position when scrolling back to the top
|
||||
(defn on-scroll
|
||||
[on-load on-top-reached]
|
||||
(let [node (main-node)
|
||||
(let [node js/document.documentElement
|
||||
full-height (gobj/get node "scrollHeight")
|
||||
scroll-top (gobj/get node "scrollTop")
|
||||
client-height (gobj/get node "clientHeight")
|
||||
|
@ -286,7 +290,7 @@
|
|||
debounced-on-scroll (util/debounce 500 #(on-scroll
|
||||
(:on-load opts) ; bottom reached
|
||||
(:on-top-reached opts)))]
|
||||
(mixins/listen state (main-node) :scroll debounced-on-scroll)))
|
||||
(mixins/listen state js/document :scroll debounced-on-scroll)))
|
||||
|
||||
(rum/defcs infinite-list <
|
||||
(mixins/event-mixin attach-listeners)
|
||||
|
@ -353,7 +357,7 @@
|
|||
(let [current-idx (get state ::current-idx)]
|
||||
[:div#ui__ac {:class class}
|
||||
(if (seq matched)
|
||||
[:div#ui__ac-inner
|
||||
[:div#ui__ac-inner.hide-scrollbar
|
||||
(for [[idx item] (medley/indexed matched)]
|
||||
(rum/with-key
|
||||
(menu-link
|
||||
|
@ -389,7 +393,7 @@
|
|||
([label children {:keys [label-style]}]
|
||||
[:div.Tooltip {:style {:display "inline"}}
|
||||
[:div (cond->
|
||||
{:class "Tooltip__label"}
|
||||
{:class "Tooltip__label"}
|
||||
label-style
|
||||
(assoc :style label-style))
|
||||
label]
|
||||
|
@ -448,10 +452,9 @@
|
|||
|
||||
(defn loading
|
||||
[content]
|
||||
[:div.flex.flex-row.align-center
|
||||
[:span.lds-dual-ring.mr-2]
|
||||
[:span {:style {:margin-top 2}}
|
||||
content]])
|
||||
[:div.flex.flex-row.items-center
|
||||
[:span.icon.flex.items-center svg/loading]
|
||||
[:span.text.pl-2 content]])
|
||||
|
||||
(rum/defcs foldable <
|
||||
(rum/local false ::control?)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
#ui__ac {
|
||||
&-inner {
|
||||
max-height: 400px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
> .menu-link {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__notifications {
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
width: 100%;
|
||||
top: 3.2em;
|
||||
|
||||
&-content {
|
||||
@apply inset-0 flex items-end justify-center px-4 py-3
|
||||
pointer-events-none sm:px-6 sm:py-3 sm:items-start
|
||||
sm:justify-end;
|
||||
}
|
||||
|
||||
.notification-area {
|
||||
background-color: var(--ls-tertiary-background-color, #fff);
|
||||
color: var(--ls-primary-text-color);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,14 @@
|
|||
(-pr-writer [sym writer _]
|
||||
(-write writer (str "\"" (.toString sym) "\""))))
|
||||
|
||||
;; doms
|
||||
(defn html-node [] js/document.documentElement)
|
||||
|
||||
;; envs
|
||||
(defn mac?
|
||||
[]
|
||||
(string/includes? js/navigator.appVersion "Mac"))
|
||||
|
||||
(defn ios?
|
||||
[]
|
||||
(not (nil? (re-find #"iPad|iPhone|iPod" js/navigator.userAgent))))
|
||||
|
@ -324,7 +331,7 @@
|
|||
(when-not (re-find #"^/\d+$" elem-id)
|
||||
(when elem-id
|
||||
(when-let [elem (gdom/getElement elem-id)]
|
||||
(.scroll (gdom/getElement "main-content")
|
||||
(.scroll (html-node)
|
||||
#js {:top (let [top (element-top elem 0)]
|
||||
(if (> top 68)
|
||||
(- top 68)
|
||||
|
@ -333,10 +340,9 @@
|
|||
|
||||
(defn scroll-to
|
||||
[pos]
|
||||
(when-let [main-content (gdom/getElement "main-content")]
|
||||
(.scroll main-content
|
||||
#js {:top pos
|
||||
:behavior "smooth"})))
|
||||
(.scroll (html-node)
|
||||
#js {:top pos
|
||||
:behavior "smooth"}))
|
||||
|
||||
(defn scroll-to-top
|
||||
[]
|
||||
|
|
|
@ -4,5 +4,6 @@ module.exports = {
|
|||
'./src/**/*.cljs',
|
||||
'./resources/**/*.html',
|
||||
],
|
||||
plugins: [require("@tailwindcss/ui")],
|
||||
};
|
||||
plugins: [require('@tailwindcss/ui')],
|
||||
darkMode: 'class',
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue