feat: introduce global scale level option

This commit is contained in:
Konstantinos Kaloutas
2023-04-13 15:21:25 +03:00
committed by Gabriel Horner
parent a7fe7fa19d
commit e5ea451e42
18 changed files with 208 additions and 57 deletions

View File

@@ -13,7 +13,7 @@
"@radix-ui/react-context-menu": "^2.1.0",
"@radix-ui/react-dropdown-menu": "^2.0.1",
"@radix-ui/react-popover": "^1.0.0",
"@radix-ui/react-select": "^1.1.2",
"@radix-ui/react-select": "^1.2.1",
"@radix-ui/react-separator": "^1.0.1",
"@radix-ui/react-slider": "^1.1.0",
"@radix-ui/react-switch": "^1.0.1",

View File

@@ -19,7 +19,7 @@ import type {
import { Button } from '../Button'
import { TablerIcon } from '../icons'
import { ColorInput } from '../inputs/ColorInput'
import { SelectInput, type SelectOption } from '../inputs/SelectInput'
import { ScaleInput } from '../inputs/ScaleInput'
import { ShapeLinksInput } from '../inputs/ShapeLinksInput'
import { TextInput } from '../inputs/TextInput'
import {
@@ -211,44 +211,9 @@ const ScaleLevelAction = observer(() => {
const app = useApp<Shape>()
const shapes = filterShapeByAction<LogseqPortalShape>(app.selectedShapesArray, 'ScaleLevel')
const scaleLevel = new Set(shapes.map(s => s.scaleLevel)).size > 1 ? '' : shapes[0].scaleLevel
const sizeOptions: SelectOption[] = [
{
label: isMobile() ? 'XS' : 'Extra Small',
value: 'xs',
},
{
label: isMobile() ? 'SM' : 'Small',
value: 'sm',
},
{
label: isMobile() ? 'MD' : 'Medium',
value: 'md',
},
{
label: isMobile() ? 'LG' : 'Large',
value: 'lg',
},
{
label: isMobile() ? 'XL' : 'Extra Large',
value: 'xl',
},
{
label: isMobile() ? 'XXL' : 'Huge',
value: 'xxl',
},
]
return (
<SelectInput
tooltip="Scale level"
options={sizeOptions}
value={scaleLevel}
onValueChange={v => {
shapes.forEach(shape => {
shape.setScaleLevel(v as LogseqPortalShape['props']['scaleLevel'])
})
app.persist()
}}
/>
<ScaleInput scaleLevel={scaleLevel} compact={isMobile()} />
)
})

View File

@@ -4,6 +4,7 @@ import * as React from 'react'
import { ToolButton } from '../ToolButton'
import { GeometryTools } from '../GeometryTools'
import { ColorInput } from '../inputs/ColorInput'
import { ScaleInput } from '../inputs/ScaleInput'
import * as Separator from '@radix-ui/react-separator'
export const PrimaryTools = observer(function PrimaryTools() {
@@ -36,6 +37,7 @@ export const PrimaryTools = observer(function PrimaryTools() {
style={{ margin: '0 -4px' }}
/>
<ColorInput popoverSide="left" color={app.settings.color} setColor={handleSetColor} />
<ScaleInput scaleLevel={app.settings.scaleLevel} popoverSide="left" compact={true} />
</div>
</div>
)

View File

@@ -0,0 +1,59 @@
import { SelectInput, type SelectOption } from '../inputs/SelectInput'
import type { Side } from '@radix-ui/react-popper'
import type { SizeLevel } from '../../lib'
import { useApp } from '@tldraw/react'
interface ScaleInputProps extends React.HTMLAttributes<HTMLButtonElement> {
scaleLevel?: SizeLevel,
compact?: boolean,
popoverSide?: Side
}
export function ScaleInput({
scaleLevel,
compact,
popoverSide,
...rest
}: ScaleInputProps) {
const app = useApp<Shape>()
const sizeOptions: SelectOption[] = [
{
label: compact ? 'XS' : 'Extra Small',
value: 'xs',
},
{
label: compact ? 'SM' : 'Small',
value: 'sm',
},
{
label: compact ? 'MD' : 'Medium',
value: 'md',
},
{
label: compact ? 'LG' : 'Large',
value: 'lg',
},
{
label: compact ? 'XL' : 'Extra Large',
value: 'xl',
},
{
label: compact ? 'XXL' : 'Huge',
value: 'xxl',
},
]
return (
<SelectInput
tooltip="Scale level"
options={sizeOptions}
value={scaleLevel}
popoverSide={popoverSide}
chevron={!compact}
onValueChange={v => {
app.api.setScaleLevel(v)
}}
/>
)
}

View File

@@ -2,6 +2,7 @@ import * as React from 'react'
import * as Select from '@radix-ui/react-select'
import { TablerIcon } from '../icons'
import { Tooltip } from '../Tooltip'
import type { Side } from '@radix-ui/react-popper'
export interface SelectOption {
value: string
@@ -11,11 +12,13 @@ export interface SelectOption {
interface SelectInputProps extends React.HTMLAttributes<HTMLElement> {
options: SelectOption[]
value: string
tooltip?: React.ReactNode
tooltip?: React.ReactNode,
popoverSide?: Side,
chevron?: boolean,
onValueChange: (value: string) => void
}
export function SelectInput({ options, tooltip, value, onValueChange, ...rest }: SelectInputProps) {
export function SelectInput({ options, tooltip, popoverSide, chevron = true, value, onValueChange, ...rest }: SelectInputProps) {
const [isOpen, setIsOpen] = React.useState(false)
return (
<div {...rest} className="tl-select-input">
@@ -25,19 +28,21 @@ export function SelectInput({ options, tooltip, value, onValueChange, ...rest }:
value={value}
onValueChange={onValueChange}
>
<Tooltip content={tooltip}>
<Tooltip content={tooltip} side={popoverSide}>
<Select.Trigger className="tl-select-input-trigger">
<div className="tl-select-input-trigger-value">
<Select.Value />
</div>
<Select.Icon style={{ lineHeight: 1 }}>
<TablerIcon name={isOpen ? 'chevron-up' : 'chevron-down'} />
</Select.Icon>
{chevron &&
<Select.Icon style={{ lineHeight: 1 }} className="ml-1 md:ml-3">
<TablerIcon name={isOpen ? 'chevron-up' : 'chevron-down'} />
</Select.Icon>
}
</Select.Trigger>
</Tooltip>
<Select.Portal className="tl-select-input-portal">
<Select.Content className="tl-select-input-content">
<Select.Content className="tl-select-input-content" align="center">
<Select.ScrollUpButton />
<Select.Viewport className="tl-select-input-viewport">
{options.map(option => {

View File

@@ -330,6 +330,7 @@ const handleCreatingShapes = async (
pageId: blockRef,
fill: app.settings.color,
stroke: app.settings.color,
scaleLevel: app.settings.scaleLevel,
blockType: 'B' as 'B',
},
]
@@ -346,6 +347,7 @@ const handleCreatingShapes = async (
pageId: pageName,
fill: app.settings.color,
stroke: app.settings.color,
scaleLevel: app.settings.scaleLevel,
blockType: 'P' as 'P',
},
]
@@ -370,6 +372,7 @@ const handleCreatingShapes = async (
pageId: uuid,
fill: app.settings.color,
stroke: app.settings.color,
scaleLevel: app.settings.scaleLevel,
blockType: 'B' as 'B',
compact: true,
},

View File

@@ -152,6 +152,7 @@ export class BoxShape extends TLBoxShape<BoxShapeProps> {
this.update({
scaleLevel: v,
fontSize: levelToScale[v ?? 'md'],
strokeWidth: levelToScale[v ?? 'md'] / 10,
})
this.onResetBounds()
}

View File

@@ -146,6 +146,7 @@ export class EllipseShape extends TLEllipseShape<EllipseShapeProps> {
this.update({
scaleLevel: v,
fontSize: levelToScale[v ?? 'md'],
strokeWidth: levelToScale[v ?? 'md'] / 10,
})
this.onResetBounds()
}

View File

@@ -160,6 +160,7 @@ export class PolygonShape extends TLPolygonShape<PolygonShapeProps> {
this.update({
scaleLevel: v,
fontSize: levelToScale[v ?? 'md'],
strokeWidth: levelToScale[v ?? 'md'] / 10,
})
this.onResetBounds()
}

View File

@@ -301,6 +301,17 @@ html[data-theme='light'] {
.tl-tools-floating-panel {
flex-flow: column;
.tl-select-input-trigger {
@apply p-0 text-xs;
height: 32px;
min-width: 32px;
}
.tl-select-input-trigger-value {
@apply font-semibold justify-center;
}
}
button.tl-select-input-trigger {
@@ -314,7 +325,7 @@ button.tl-select-input-trigger {
}
.tl-select-input-trigger-value {
@apply flex items-center justify-start flex-1 mr-1 md:mr-3;
@apply flex items-center justify-start flex-1;
}
.tl-select-input-viewport {

View File

@@ -181,6 +181,19 @@ export class TLApi<S extends TLShape = TLShape, K extends TLEventMap = TLEventMa
return this
}
setScaleLevel = (scaleLevel: string): this => {
const { settings } = this.app
settings.update({ scaleLevel })
this.app.selectedShapes.forEach(shape => {
shape.setScaleLevel(scaleLevel)
})
this.app.persist()
return this
}
save = () => {
this.app.save()
return this

View File

@@ -5,6 +5,7 @@ export interface TLSettingsProps {
mode: 'light' | 'dark'
showGrid: boolean
color: string
scaleLevel: string
}
export class TLSettings implements TLSettingsProps {
@@ -14,6 +15,7 @@ export class TLSettings implements TLSettingsProps {
@observable mode: 'dark' | 'light' = 'light'
@observable showGrid = true
@observable scaleLevel = 'md'
@observable color = ''
@action update(props: Partial<TLSettingsProps>): void {

View File

@@ -30,6 +30,7 @@ export interface TLShapeProps {
name?: string
fill?: string
stroke?: string
scaleLevel?: string
refs?: string[] // block id or page name
point: number[]
size?: number[]

View File

@@ -58,6 +58,7 @@ export class CreatingState<
this.initialBounds.maxY = this.initialBounds.minY + this.initialBounds.height
}
this.creatingShape = shape
this.creatingShape.setScaleLevel(this.app.settings.scaleLevel)
this.app.currentPage.addShapes(shape as unknown as S)
this.app.setSelectedShapes([shape as unknown as S])
}

View File

@@ -77,6 +77,7 @@ export class CreatingState<
fill: this.app.settings.color,
stroke: this.app.settings.color,
})
this.shape.setScaleLevel(this.app.settings.scaleLevel)
this.app.currentPage.addShapes(this.shape)
}
}

View File

@@ -34,6 +34,7 @@ export class CreatingState<
point: originPoint,
fill: this.app.settings.color,
stroke: this.app.settings.color,
scaleLevel: this.app.settings.scaleLevel,
})
this.initialShape = toJS(shape.props)
this.currentShape = shape

View File

@@ -40,6 +40,7 @@ export class CreatingState<
stroke: this.app.settings.color,
})
this.creatingShape = shape
this.creatingShape.setScaleLevel(this.app.settings.scaleLevel)
transaction(() => {
this.app.currentPage.addShapes(shape as unknown as S)
const { bounds } = shape

View File

@@ -573,6 +573,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-arrow@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz#93b0ff95f65e2264a05b14ef1031ec798243dd6f"
integrity sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-collection@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.1.tgz#259506f97c6703b36291826768d3c1337edd1de5"
@@ -584,6 +592,17 @@
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-slot" "1.0.1"
"@radix-ui/react-collection@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.2.tgz#d50da00bfa2ac14585319efdbbb081d4c5a29a97"
integrity sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-slot" "1.0.1"
"@radix-ui/react-compose-refs@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz#37595b1f16ec7f228d698590e78eeed18ff218ae"
@@ -630,6 +649,18 @@
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-escape-keydown" "1.0.2"
"@radix-ui/react-dismissable-layer@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.3.tgz#63844d8e6bbcd010a513e7176d051c3c4044e09e"
integrity sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-escape-keydown" "1.0.2"
"@radix-ui/react-dropdown-menu@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.1.tgz#dbc90676df7fb313d6b1eb204fdb434dbb724d15"
@@ -661,6 +692,16 @@
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-focus-scope@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.2.tgz#5fe129cbdb5986d0a3ae16d14c473c243fe3bc79"
integrity sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-id@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e"
@@ -732,6 +773,23 @@
"@radix-ui/react-use-size" "1.0.0"
"@radix-ui/rect" "1.0.0"
"@radix-ui/react-popper@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.1.tgz#54f060941c981e965ff5d6b64e152d6298d2326e"
integrity sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==
dependencies:
"@babel/runtime" "^7.13.10"
"@floating-ui/react-dom" "0.7.2"
"@radix-ui/react-arrow" "1.0.2"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-layout-effect" "1.0.0"
"@radix-ui/react-use-rect" "1.0.0"
"@radix-ui/react-use-size" "1.0.0"
"@radix-ui/rect" "1.0.0"
"@radix-ui/react-portal@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.1.tgz#169c5a50719c2bb0079cf4c91a27aa6d37e5dd33"
@@ -740,6 +798,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-portal@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.2.tgz#102370b1027a767a371cab0243be4bc664f72330"
integrity sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-presence@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a"
@@ -757,6 +823,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "1.0.1"
"@radix-ui/react-primitive@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz#54e22f49ca59ba88d8143090276d50b93f8a7053"
integrity sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "1.0.1"
"@radix-ui/react-roving-focus@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.1.tgz#475621f63aee43faa183a5270f35d49e530de3d7"
@@ -773,30 +847,31 @@
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-controllable-state" "1.0.0"
"@radix-ui/react-select@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.1.2.tgz#675bb9c17970da74be95bd9804fdd2b9cf3a010b"
integrity sha512-pQmfz7T6oR5m27E3NgKOo6DLs5U1qMZaUcfTENXZnNPeyyRN8pEb6Z+xXE6zomP5sg9pgLOtir4R2Q3f2kkF9w==
"@radix-ui/react-select@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-1.2.1.tgz#0c8fadc9a134709036add7c9c7c8581e17962040"
integrity sha512-GULRMITaOHNj79BZvQs3iZO0+f2IgI8g5HDhMi7Bnc13t7IlG86NFtOCfTLme4PNZdEtU+no+oGgcl6IFiphpQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/number" "1.0.0"
"@radix-ui/primitive" "1.0.0"
"@radix-ui/react-collection" "1.0.1"
"@radix-ui/react-collection" "1.0.2"
"@radix-ui/react-compose-refs" "1.0.0"
"@radix-ui/react-context" "1.0.0"
"@radix-ui/react-direction" "1.0.0"
"@radix-ui/react-dismissable-layer" "1.0.2"
"@radix-ui/react-dismissable-layer" "1.0.3"
"@radix-ui/react-focus-guards" "1.0.0"
"@radix-ui/react-focus-scope" "1.0.1"
"@radix-ui/react-focus-scope" "1.0.2"
"@radix-ui/react-id" "1.0.0"
"@radix-ui/react-portal" "1.0.1"
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-popper" "1.1.1"
"@radix-ui/react-portal" "1.0.2"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/react-slot" "1.0.1"
"@radix-ui/react-use-callback-ref" "1.0.0"
"@radix-ui/react-use-controllable-state" "1.0.0"
"@radix-ui/react-use-layout-effect" "1.0.0"
"@radix-ui/react-use-previous" "1.0.0"
"@radix-ui/react-visually-hidden" "1.0.1"
"@radix-ui/react-visually-hidden" "1.0.2"
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
@@ -952,6 +1027,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.1"
"@radix-ui/react-visually-hidden@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.2.tgz#29b117a59ef09a984bdad12cb98d81e8350be450"
integrity sha512-qirnJxtYn73HEk1rXL12/mXnu2rwsNHDID10th2JGtdK25T9wX+mxRmGt7iPSahw512GbZOc0syZX1nLQGoEOg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.2"
"@radix-ui/rect@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.0.tgz#0dc8e6a829ea2828d53cbc94b81793ba6383bf3c"