mirror of https://github.com/logseq/logseq
feat: whiteboard preview & nesting
parent
7cb60d6896
commit
61a717830b
|
@ -24,7 +24,6 @@
|
|||
[frontend.handler.page :as page-handler]
|
||||
[frontend.handler.plugin :as plugin-handler]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.handler.whiteboard :as whiteboard-handler]
|
||||
[frontend.mixins :as mixins]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.search :as search]
|
||||
|
@ -314,6 +313,8 @@
|
|||
"control-show cursor-pointer" "control-hide")}
|
||||
(ui/rotating-arrow @*all-collapsed?)]])
|
||||
|
||||
(def get-tldraw-preview #(resolve 'frontend.components.whiteboard/tldraw-preview))
|
||||
|
||||
;; A page is just a logical block
|
||||
(rum/defcs page < rum/reactive
|
||||
(rum/local false ::all-collapsed?)
|
||||
|
@ -335,6 +336,7 @@
|
|||
fmt-journal? (boolean (date/journal-title->int page-name))
|
||||
sidebar? (:sidebar? option)
|
||||
whiteboard? (:whiteboard? option)
|
||||
whiteboard-page? (model/whiteboard-page? page-name)
|
||||
route-page-name path-page-name
|
||||
page (if block?
|
||||
(->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
|
||||
|
@ -363,37 +365,39 @@
|
|||
{:key path-page-name
|
||||
:class (util/classnames [{:is-journals (or journal? fmt-journal?)}])})
|
||||
|
||||
[:div.relative
|
||||
(when (and (not sidebar?) (not block?))
|
||||
[:div.flex.flex-row.space-between
|
||||
(when (or (mobile-util/native-platform?) (util/mobile?))
|
||||
[:div.flex.flex-row.pr-2
|
||||
{:style {:margin-left -15}
|
||||
:on-mouse-over (fn [e]
|
||||
(page-mouse-over e *control-show? *all-collapsed?))
|
||||
:on-mouse-leave (fn [e]
|
||||
(page-mouse-leave e *control-show?))}
|
||||
(page-blocks-collapse-control title *control-show? *all-collapsed?)])
|
||||
(when-not whiteboard?
|
||||
[:div.flex-1.flex-row
|
||||
[:h1.title.ls-page-title (page-title page-name icon title format fmt-journal?)]])
|
||||
(when (not config/publishing?)
|
||||
[:div.flex.flex-row
|
||||
(when plugin-handler/lsp-enabled?
|
||||
(plugins/hook-ui-slot :page-head-actions-slotted nil)
|
||||
(plugins/hook-ui-items :pagebar))])])
|
||||
[:div
|
||||
(when (and block? (not sidebar?) (not whiteboard?))
|
||||
(let [config {:id "block-parent"
|
||||
:block? true}]
|
||||
[:div.mb-4
|
||||
(component-block/breadcrumb config repo block-id {:level-limit 3})]))
|
||||
(if whiteboard-page?
|
||||
[:div ((get-tldraw-preview) page-name)]
|
||||
[:div.relative
|
||||
(when (and (not sidebar?) (not block?))
|
||||
[:div.flex.flex-row.space-between
|
||||
(when (or (mobile-util/native-platform?) (util/mobile?))
|
||||
[:div.flex.flex-row.pr-2
|
||||
{:style {:margin-left -15}
|
||||
:on-mouse-over (fn [e]
|
||||
(page-mouse-over e *control-show? *all-collapsed?))
|
||||
:on-mouse-leave (fn [e]
|
||||
(page-mouse-leave e *control-show?))}
|
||||
(page-blocks-collapse-control title *control-show? *all-collapsed?)])
|
||||
(when-not whiteboard?
|
||||
[:div.flex-1.flex-row
|
||||
[:h1.title.ls-page-title (page-title page-name icon title format fmt-journal?)]])
|
||||
(when (not config/publishing?)
|
||||
[:div.flex.flex-row
|
||||
(when plugin-handler/lsp-enabled?
|
||||
(plugins/hook-ui-slot :page-head-actions-slotted nil)
|
||||
(plugins/hook-ui-items :pagebar))])])
|
||||
[:div
|
||||
(when (and block? (not sidebar?) (not whiteboard?))
|
||||
(let [config {:id "block-parent"
|
||||
:block? true}]
|
||||
[:div.mb-4
|
||||
(component-block/breadcrumb config repo block-id {:level-limit 3})]))
|
||||
|
||||
;; blocks
|
||||
(let [page (if block?
|
||||
(db/entity repo [:block/uuid block-id])
|
||||
page)]
|
||||
(page-blocks-cp repo page {:sidebar? sidebar?}))]]
|
||||
(let [page (if block?
|
||||
(db/entity repo [:block/uuid block-id])
|
||||
page)]
|
||||
(page-blocks-cp repo page {:sidebar? sidebar?}))]])
|
||||
|
||||
(when-not block?
|
||||
(today-queries repo today? sidebar?))
|
||||
|
|
|
@ -30,8 +30,9 @@
|
|||
(p/let [_ (loader/load :tldraw)]
|
||||
(reset! tldraw-loaded? true))
|
||||
state)}
|
||||
[tldr]
|
||||
[page-name]
|
||||
(let [loaded? (rum/react tldraw-loaded?)
|
||||
tldr (whiteboard-handler/page-name->tldr! page-name)
|
||||
generate-preview (when loaded?
|
||||
(resolve 'frontend.extensions.tldraw/generate-preview))]
|
||||
(when generate-preview
|
||||
|
@ -39,15 +40,14 @@
|
|||
|
||||
(rum/defc dashboard-card
|
||||
[page-name]
|
||||
(let [tldr (whiteboard-handler/page-name->tldr! page-name)]
|
||||
[:div.rounded.text-lg.cursor-pointer.flex.flex-col.gap-1.overflow-hidden.dashboard-card
|
||||
{:on-mouse-down
|
||||
(fn [e]
|
||||
(util/stop e)
|
||||
(route-handler/redirect-to-whiteboard! page-name))}
|
||||
[:div.truncate.bg-white.px-4.py-1.dashboard-card-title page-name]
|
||||
[:div.p-4.h-64.flex.justify-center
|
||||
(tldraw-preview tldr)]]))
|
||||
[:div.rounded.text-lg.cursor-pointer.flex.flex-col.gap-1.overflow-hidden.dashboard-card
|
||||
{:on-mouse-down
|
||||
(fn [e]
|
||||
(util/stop e)
|
||||
(route-handler/redirect-to-whiteboard! page-name))}
|
||||
[:div.truncate.px-4.py-1.dashboard-card-title page-name]
|
||||
[:div.p-4.h-64.flex.justify-center
|
||||
(tldraw-preview page-name)]])
|
||||
|
||||
(rum/defc whiteboard-dashboard
|
||||
[]
|
||||
|
@ -70,25 +70,32 @@
|
|||
[:button.border.text-sm.bg-gray-500.text-white.px-2 {:on-click (fn [] (set-show not))} "references"]
|
||||
(when show (reference/block-linked-references uuid))]))
|
||||
|
||||
(rum/defc whiteboard
|
||||
(rum/defc whiteboard-page
|
||||
[name block-id]
|
||||
[:div.absolute.w-full.h-full.whiteboard-page
|
||||
|
||||
;; makes sure the whiteboard will not cover the borders
|
||||
{:key name
|
||||
:style {:padding "0.5px" :z-index 0
|
||||
:transform "translateZ(0)"
|
||||
:text-rendering "geometricPrecision"
|
||||
:-webkit-font-smoothing "subpixel-antialiased"}}
|
||||
|
||||
[:div.absolute.p-4.flex.items-start
|
||||
{:style {:z-index 2000}}
|
||||
[:span.inline-flex.color-level.text-xl.px-2
|
||||
{:style {:color "var(--ls-primary-text-color)"}}
|
||||
(page/page-title name [:<>
|
||||
[:span.ti.ti-artboard
|
||||
{:style {:font-size "0.9em"}}]]
|
||||
name nil false)]
|
||||
|
||||
(whiteboard-references name)]
|
||||
|
||||
(tldraw-app name block-id)])
|
||||
|
||||
(rum/defc whiteboard-route
|
||||
[route-match]
|
||||
(let [name (get-in route-match [:parameters :path :name])
|
||||
{:keys [block-id]} (get-in route-match [:parameters :query])]
|
||||
|
||||
[:div.absolute.w-full.h-full.whiteboard-page
|
||||
|
||||
;; makes sure the whiteboard will not cover the borders
|
||||
{:key name
|
||||
:style {:padding "0.5px" :z-index 0 :transform "translateZ(0)" :text-rendering "geometricPrecision" :-webkit-font-smoothing "subpixel-antialiased"}}
|
||||
|
||||
[:div.absolute.p-4.flex.items-start
|
||||
{:style {:z-index 2000}}
|
||||
[:span.inline-flex.color-level.text-xl.px-2
|
||||
(page/page-title name [:<>
|
||||
[:span.text-gray-500.ti.ti-artboard
|
||||
{:style {:font-size "0.9em"}}]]
|
||||
name nil false)]
|
||||
|
||||
(whiteboard-references name)]
|
||||
|
||||
(tldraw-app name block-id)]))
|
||||
(whiteboard-page name block-id)))
|
||||
|
|
|
@ -4,5 +4,7 @@
|
|||
}
|
||||
|
||||
.dashboard-card-title {
|
||||
color: var(--ls-primary-text-color);
|
||||
border-bottom: 1px solid var(--ls-border-color);
|
||||
background-color: var(--ls-secondary-background-color);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
["/whiteboard/:name"
|
||||
{:name :whiteboard
|
||||
:view whiteboard/whiteboard}]
|
||||
:view whiteboard/whiteboard-route}]
|
||||
|
||||
["/whiteboards"
|
||||
{:name :whiteboards
|
||||
|
|
|
@ -30,7 +30,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
|
|||
start: { id: 'start', canBind: true, point: [0, 0] },
|
||||
end: { id: 'end', canBind: true, point: [1, 1] },
|
||||
},
|
||||
stroke: 'var(--tl-foreground, #000)',
|
||||
stroke: 'var(--ls-primary-text-color, #000)',
|
||||
fill: '#ffffff',
|
||||
strokeWidth: 1,
|
||||
opacity: 1,
|
||||
|
|
|
@ -260,9 +260,9 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
|||
: 'var(--shadow-medium)',
|
||||
color: stroke,
|
||||
// @ts-expect-error ???
|
||||
'--ls-primary-background-color': fill,
|
||||
'--ls-primary-text-color': stroke,
|
||||
'--ls-title-text-color': stroke,
|
||||
'--ls-primary-background-color': !fill?.startsWith('var') ? fill : undefined,
|
||||
'--ls-primary-text-color': !stroke?.startsWith('var') ? stroke : undefined,
|
||||
'--ls-title-text-color': !stroke?.startsWith('var') ? stroke : undefined,
|
||||
}}
|
||||
>
|
||||
<LogseqPortalShapeHeader type={this.props.blockType ?? 'P'}>
|
||||
|
@ -313,4 +313,42 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
|||
}
|
||||
return withClampedStyles(props)
|
||||
}
|
||||
|
||||
getShapeSVGJsx(preview = false) {
|
||||
// Do not need to consider the original point here
|
||||
const bounds = this.getBounds()
|
||||
return (
|
||||
<>
|
||||
<rect
|
||||
stroke={this.props.stroke}
|
||||
strokeWidth={this.props.strokeWidth ?? 2}
|
||||
fill="#aaa"
|
||||
width={bounds.width}
|
||||
height={HEADER_HEIGHT}
|
||||
/>
|
||||
<rect
|
||||
y={HEADER_HEIGHT}
|
||||
fill={this.props.fill}
|
||||
stroke={this.props.stroke}
|
||||
strokeWidth={this.props.strokeWidth ?? 2}
|
||||
fillOpacity={this.props.opacity ?? 0.2}
|
||||
width={bounds.width}
|
||||
height={bounds.height - HEADER_HEIGHT}
|
||||
/>
|
||||
<text
|
||||
style={{
|
||||
transformOrigin: 'top left',
|
||||
}}
|
||||
transform={`translate(${bounds.width / 2}, ${10 + bounds.height / 2})`}
|
||||
textAnchor="middle"
|
||||
fontFamily="var(--ls-font-family)"
|
||||
fontSize="32"
|
||||
fill={this.props.stroke}
|
||||
stroke={this.props.stroke}
|
||||
>
|
||||
{this.props.pageId}
|
||||
</text>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
.logseq-tldraw .action-bar {
|
||||
position: absolute;
|
||||
bottom: 0;;
|
||||
bottom: 0;
|
||||
border-radius: 0 10px 0 0;
|
||||
float: left;
|
||||
left: 0;
|
||||
|
@ -66,7 +66,7 @@
|
|||
padding: 8px;
|
||||
color: black;
|
||||
border: none;
|
||||
height:fit-content;
|
||||
height: fit-content;
|
||||
z-index: 100000;
|
||||
user-select: none;
|
||||
background: var(--color-panel);
|
||||
|
@ -79,7 +79,7 @@
|
|||
|
||||
.logseq-tldraw .action-bar button {
|
||||
border-radius: 4px;
|
||||
color: var(--ls-secondary-text-color)
|
||||
color: var(--ls-secondary-text-color);
|
||||
}
|
||||
|
||||
.dropdown-menu-button {
|
||||
|
@ -570,7 +570,6 @@
|
|||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--ls-secondary-background-color);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ export interface TLShapeProps {
|
|||
clipping?: number | number[]
|
||||
fill?: string
|
||||
stroke?: string
|
||||
strokeWidth?: number
|
||||
opacity?: number
|
||||
assetId?: string
|
||||
children?: string[]
|
||||
|
@ -362,6 +363,7 @@ export abstract class TLShape<P extends TLShapeProps = TLShapeProps, M = any> {
|
|||
<rect
|
||||
fill={this.props.fill}
|
||||
stroke={this.props.stroke}
|
||||
strokeWidth={this.props.strokeWidth ?? 2}
|
||||
fillOpacity={this.props.opacity ?? 0.2}
|
||||
width={bounds.width}
|
||||
height={bounds.height}
|
||||
|
|
Loading…
Reference in New Issue