您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
adjust-figma-toolbelt 是一个用于增强 Figma 体验的脚本,可以轻松地将工具栏调整到想要的位置。
/* eslint-disable */ // ==UserScript== // @name adjust-figma-toolbelt // @name:zh-CN adjust-figma-toolbelt // @namespace https://github.com/palmcivet/adjust-figma-toolbelt // @version 1.0.6 // @license MIT // @author Palm Civet // @description adjust-figma-toolbelt is a versatile script designed to enhance your Figma experience by allowing you to reposition the toolbelt with ease. // @description:zh-CN adjust-figma-toolbelt 是一个用于增强 Figma 体验的脚本,可以轻松地将工具栏调整到想要的位置。 // @match https://www.figma.com/design/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // ==/UserScript== (function() { "use strict"; // @license MIT const PREFIX = "adjust"; const STORAGE_LEFT = `__${PREFIX.toUpperCase()}_LEFT__`; const STORAGE_BOTTOM = `__${PREFIX.toUpperCase()}_BOTTOM__`; const TOOLBELT_SELECTOR = `[class*="positioned_design_toolbelt--root--"]`; const FLOAT_MENU_STYLE = ` ${TOOLBELT_SELECTOR} [class*="dropdown--dropdown--"] { margin-top: 6px; bottom: unset !important; } ${TOOLBELT_SELECTOR} [class*="scroll_container--clipContainer--"] { height: auto !important; } ${TOOLBELT_SELECTOR} [class*="pointing_dropdown--scrollIndicator--"] { display: none !important; }`; const DEFAULT_PADDING = 12; const DEFAULT_TOP = 48 + DEFAULT_PADDING; const FLOAT_MENU_TOP = 184; const LABEL_PIN_DEFAULT_TOP = "⬆️ Pin the toolbelt to the top"; const LABEL_UNPIN_DEFAULT_TOP = "🔝 The toolbelt is already at the top"; const LABEL_START_CUSTOM_POSITION = "🎨 Customize the toolbelt position"; const LABEL_STOP_CUSTOM_POSITION = "💾 Save the position and exit"; // @license MIT function findToolbeltElement() { const element = window.document.querySelector(TOOLBELT_SELECTOR); if (!element) { return null; } return element; } // @license MIT async function getToolbeltPosition() { const left = await GM.getValue(STORAGE_LEFT); const bottom = await GM.getValue(STORAGE_BOTTOM); console.info(`[${PREFIX}] Read persistent data: ${left}, ${bottom}.`); return { left: left ?? null, bottom: bottom ?? DEFAULT_PADDING }; } async function setToolbeltPosition({ left, bottom }) { console.info(`[${PREFIX}] Save persistent data: ${left}, ${bottom}.`); await GM.setValue(STORAGE_LEFT, left); await GM.setValue(STORAGE_BOTTOM, bottom); } // @license MIT function createMenuStore() { const menuStore2 = /* @__PURE__ */ new Map(); const _removeMenus = () => { for (const menu of menuStore2.values()) { GM_unregisterMenuCommand(menu.id); } }; const _registerMenus = () => { for (const menu of menuStore2.values()) { const newId = GM_registerMenuCommand(menu.label, menu.callback); menu.id = newId; } }; const update = (type, label, callback) => { _removeMenus(); menuStore2.set(type, { id: 0, label, callback }); _registerMenus(); }; return { update }; } function createFloatMenuStore() { let styleElement; const update = (element) => { setTimeout(() => { const { top, bottom } = element.getBoundingClientRect(); const toolbeltBottom = window.innerHeight - bottom; console.log(top, FLOAT_MENU_TOP, toolbeltBottom, FLOAT_MENU_TOP); if (top < FLOAT_MENU_TOP && toolbeltBottom > FLOAT_MENU_TOP) { styleElement = GM_addStyle(FLOAT_MENU_STYLE); } else { styleElement == null ? void 0 : styleElement.remove(); } }, 1e3); }; return { update }; } function createTransitionStore() { let transitionStyle = null; const enable = (element) => { if (transitionStyle === null) { transitionStyle = element.style.transition; } element.style.transition = "bottom 0.3s ease-in-out"; }; const disable = (element) => { if (transitionStyle !== null) { element.style.transition = transitionStyle; } }; return { enable, disable }; } const menuStore = createMenuStore(); const floatMenuStore = createFloatMenuStore(); const transitionStore = createTransitionStore(); // @license MIT function moveToolbeltToTop(element, top) { const { height: toolbeltHeight } = element.getBoundingClientRect(); const { innerHeight: viewportHeight } = window; const bottom = viewportHeight - toolbeltHeight - top; element.style.bottom = `${bottom}px`; return { left: null, bottom }; } function moveToolbeltToBottom(element, bottom) { element.style.bottom = `${bottom}px`; return { left: null, bottom }; } async function resizeWindow(element) { const { height } = element.getBoundingClientRect(); const position = await getToolbeltPosition(); if (position.bottom + height + DEFAULT_PADDING > window.innerHeight) { moveToolbeltToTop(element, DEFAULT_TOP); } else { moveToolbeltToBottom(element, position.bottom); } } async function registerInitialize(element) { transitionStore.enable(element); const data = await getToolbeltPosition(); if (data.bottom !== null) { moveToolbeltToBottom(element, data.bottom); resizeWindow(element); } floatMenuStore.update(element); } function registerResizeWindow(element) { const onResize = () => { resizeWindow(element); }; window.addEventListener("resize", onResize); return { unregister: () => { window.removeEventListener("resize", onResize); } }; } function bindMouseEvent(element) { let isDragging = false; let startY = 0; let toolbeltY = 0; let position; const onMouseDown = (event) => { event.stopPropagation(); startY = event.clientY; const { y } = element.getBoundingClientRect(); toolbeltY = y; window.document.addEventListener("mousemove", onMouseMove); window.document.addEventListener("mouseup", onMouseUp); isDragging = true; }; const onMouseMove = (event) => { if (!isDragging) { return; } const { clientY } = event; const offsetY = clientY - startY; position = moveToolbeltToTop(element, toolbeltY + offsetY); }; const onMouseUp = (event) => { onMouseMove(event); isDragging = false; window.document.removeEventListener("mousemove", onMouseMove); window.document.removeEventListener("mouseup", onMouseUp); }; return { enable: () => { element.addEventListener("mousedown", onMouseDown); }, disable: () => { element.removeEventListener("mousedown", onMouseDown); return position; } }; } function bindCursorStyle(element) { let cursorStyle = "default"; const enable = () => { cursorStyle = element.style.cursor; element.style.cursor = "move"; }; const disable = () => { element.style.cursor = cursorStyle; }; return { enable, disable }; } // @license MIT function registerDefaultMenu(element) { const onPin = () => { menuStore.update("DEFAULT", LABEL_UNPIN_DEFAULT_TOP, onUnpin); const position = moveToolbeltToTop(element, DEFAULT_TOP); setToolbeltPosition(position); floatMenuStore.update(element); }; const onUnpin = () => { menuStore.update("DEFAULT", LABEL_PIN_DEFAULT_TOP, onPin); const position = moveToolbeltToBottom(element, DEFAULT_PADDING); setToolbeltPosition(position); floatMenuStore.update(element); }; menuStore.update("DEFAULT", LABEL_PIN_DEFAULT_TOP, onPin); } function registerCustomizeMenu(element) { const cursorStyle = bindCursorStyle(element); const mouseEvent = bindMouseEvent(element); const onStart = () => { transitionStore.disable(element); menuStore.update("CUSTOMIZE", LABEL_STOP_CUSTOM_POSITION, onStop); cursorStyle.enable(); mouseEvent.enable(); }; const onStop = () => { menuStore.update("CUSTOMIZE", LABEL_START_CUSTOM_POSITION, onStart); cursorStyle.disable(); const position = mouseEvent.disable(); setToolbeltPosition(position); floatMenuStore.update(element); transitionStore.enable(element); }; menuStore.update("CUSTOMIZE", LABEL_START_CUSTOM_POSITION, onStart); } // @license MIT (() => { function onReady() { const element = findToolbeltElement(); if (!element) { console.error( `[${PREFIX}] Can not find figma toolbelt: \`${TOOLBELT_SELECTOR}\`.` ); return; } registerInitialize(element); registerResizeWindow(element); registerDefaultMenu(element); registerCustomizeMenu(element); console.info(`[${PREFIX}] The script is enabled.`); } const _onload_ = window.onload || function() { }; window.onload = (event) => { _onload_(event); setTimeout(onReady, 1e3); }; })(); })();