feat: 9-position dock grid (4 corners + 4 edges + center)

This commit is contained in:
Hermes Agent committed 2026-09-09 17:54:53 +02:00
1 parent 0aeaf9f831
commit d29654b8d5
2 files changed
+36 -12

No files matched your search

+19 -7
View File
@@ -12,25 +12,37 @@ export default function () {
// Пока не null — позиция пересчитывается при каждом изменении viewport // Пока не null — позиция пересчитывается при каждом изменении viewport
// (через поллинг, т.к. события viewportchange в API нет), иначе // (через поллинг, т.к. события viewportchange в API нет), иначе
// canvas-space-точка "уплывает" на экране при смене зума/пана. // canvas-space-точка "уплывает" на экране при смене зума/пана.
let dockedPosition: 'left' | 'right' | 'center' | null = null let dockedPosition: DockPosition | null = null
// 9 позиций докинга: 4 угла + 4 края + центр.
type DockPosition =
| 'top-left' | 'top-center' | 'top-right'
| 'center-left' | 'center' | 'center-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
// Прижать окно к краю видимой области canvas (bounds) в canvas-space. // Прижать окно к краю видимой области canvas (bounds) в canvas-space.
// ВАЖНО: reposition()/getPosition() и bounds — в canvas-space (единицы документа), // ВАЖНО: reposition()/getPosition() и bounds — в canvas-space (единицы документа),
// а figma.ui.resize(width,height) — в ЭКРАННЫХ пикселях. Размер окна в canvas-units = // а figma.ui.resize(width,height) — в ЭКРАННЫХ пикселях. Размер окна в canvas-units =
// width / zoom. Без этого деления при zoom≠100% окно прижимается с ошибкой // width / zoom. Без этого деления при zoom≠100% окно прижимается с ошибкой
// (px-размер вычитается из canvas-ширины → уезжает пропорционально 1/zoom). // (px-размер вычитается из canvas-ширины → уезжает пропорционально 1/zoom).
function applyDock (position: 'left' | 'right' | 'center', width: number, height: number) { function applyDock (position: DockPosition, width: number, height: number) {
const b = figma.viewport.bounds const b = figma.viewport.bounds
const zoom = figma.viewport.zoom || 1 const zoom = figma.viewport.zoom || 1
const wCanvas = width / zoom const wCanvas = width / zoom
const hCanvas = height / zoom const hCanvas = height / zoom
let x = b.x let x = b.x
let y = b.y let y = b.y
if (position === 'right') { // По горизонтали
x = b.x + b.width - wCanvas if (position === 'top-center' || position === 'center' || position === 'bottom-center') {
} else if (position === 'center') {
x = b.x + (b.width - wCanvas) / 2 x = b.x + (b.width - wCanvas) / 2
} else if (position === 'top-right' || position === 'center-right' || position === 'bottom-right') {
x = b.x + b.width - wCanvas
}
// По вертикали
if (position === 'center-left' || position === 'center' || position === 'center-right') {
y = b.y + (b.height - hCanvas) / 2 y = b.y + (b.height - hCanvas) / 2
} else if (position === 'bottom-left' || position === 'bottom-center' || position === 'bottom-right') {
y = b.y + b.height - hCanvas
} }
figma.ui.reposition(x, y) figma.ui.reposition(x, y)
} }
@@ -77,8 +89,8 @@ export default function () {
} }
}) })
// Эмуляция докинга: прижать окно к краям canvas (left/right/center). // Эмуляция докинга: прижать окно к краям canvas (9 позиций).
on('DOCK_WINDOW', function (payload: { position: 'left' | 'right' | 'center'; width: number; height: number }) { on('DOCK_WINDOW', function (payload: { position: DockPosition; width: number; height: number }) {
const { position } = payload const { position } = payload
const { width, height } = clampWindowSize(payload) const { width, height } = clampWindowSize(payload)
lastSize = { width, height } lastSize = { width, height }
+17 -5
View File
@@ -201,7 +201,13 @@ function Plugin () {
refreshInfo() refreshInfo()
} }
function dockWindow (position: 'left' | 'right' | 'center') { // 9 позиций докинга: 4 угла + 4 края + центр.
type DockPosition =
| 'top-left' | 'top-center' | 'top-right'
| 'center-left' | 'center' | 'center-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
function dockWindow (position: DockPosition) {
emit('DOCK_WINDOW', { emit('DOCK_WINDOW', {
position, position,
width: currentWindowSize.width, width: currentWindowSize.width,
@@ -240,10 +246,16 @@ function Plugin () {
</IconButton> </IconButton>
</div> </div>
</div> </div>
<div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4px' }}>
<Button onClick={function () { dockWindow('left') }}>◧ Лево</Button> <Button onClick={function () { dockWindow('top-left') }}>◤</Button>
<Button onClick={function () { dockWindow('center') }}>▣ Центр</Button> <Button onClick={function () { dockWindow('top-center') }}>▬</Button>
<Button onClick={function () { dockWindow('right') }}>Право ◨</Button> <Button onClick={function () { dockWindow('top-right') }}>◥</Button>
<Button onClick={function () { dockWindow('center-left') }}>▏</Button>
<Button onClick={function () { dockWindow('center') }}>⊕</Button>
<Button onClick={function () { dockWindow('center-right') }}>▕</Button>
<Button onClick={function () { dockWindow('bottom-left') }}>◣</Button>
<Button onClick={function () { dockWindow('bottom-center') }}>▭</Button>
<Button onClick={function () { dockWindow('bottom-right') }}>◢</Button>
</div> </div>
<div <div
style={{ style={{