[feature]初步實現了Overlay Panel機制;禁用了HMR並修改了@apply的寫法以確保UnoCSS正常轉換styles
This commit is contained in:
parent
0bf3133a3d
commit
47dc80afe6
@ -11,6 +11,9 @@ export default defineConfig({
|
||||
plugins: [externalizeDepsPlugin()]
|
||||
},
|
||||
renderer: {
|
||||
server: {
|
||||
hmr: false,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@renderer': resolve('src/renderer/src')
|
||||
|
@ -29,10 +29,12 @@ import {
|
||||
} from './Imports'
|
||||
import { createSignal } from 'solid-js'
|
||||
import "./styles/index.css"
|
||||
import "./styles/animations.css"
|
||||
import MainToolbar from './components/MainToolbar'
|
||||
import MainToolbarSideContainer from './components/MainToolbarSideContainer'
|
||||
import BottomSidebar from './components/BottomSidebar'
|
||||
import ScreenSidebar from './components/ScreenSidebar'
|
||||
import PenOverlays from './overlays/PenOverlays'
|
||||
|
||||
function App() {
|
||||
|
||||
@ -44,7 +46,7 @@ function App() {
|
||||
|
||||
const [toolbarItems, setToolbarItems] = createSignal([
|
||||
{type: 'button', icon: iconCursor, solidIcon: iconSolidCursor, name: "鼠標模式", action: "mouse"},
|
||||
{type: 'button', icon: iconPen, solidIcon: iconSolidPen, name: "批註模式", action: "pen"},
|
||||
{type: 'button', icon: iconPen, solidIcon: iconSolidPen, name: "批註模式", action: "pen", overlay: PenOverlays},
|
||||
{type: 'button', icon: iconEraser, name: "橡皮擦模式", solidIcon:iconSolidEraser, action: "eraser"},
|
||||
{type: 'button', icon: iconTrash, name: "清空畫布", action: "clear"},
|
||||
{type: "separator"},
|
||||
|
@ -1,35 +1,94 @@
|
||||
// noinspection ES6UnusedImports
|
||||
import gest from "../utils/gest"
|
||||
import { createEffect, createSignal, on, Show, splitProps } from 'solid-js'
|
||||
import { Dynamic } from 'solid-js/web'
|
||||
|
||||
/**
|
||||
* 定義單個工具欄按鈕的Solid組件
|
||||
* @param props{{
|
||||
* item: {
|
||||
* name:string, icon, solidIcon,
|
||||
* type: "button" | "separator" | "pagination-indicator",
|
||||
* type: "button" | "separator" | "pagination-indicator"| "pagination-indicator-sidebar",
|
||||
* action: string,
|
||||
* }, toolbarSignal, setToolbarSignal,
|
||||
* }} 傳入工具欄按鈕的相關選項。
|
||||
* */
|
||||
export default function ToolBarButton(props) {
|
||||
const v = props.item;
|
||||
const toolbarSignal = props.toolbarSignal;
|
||||
const setToolbarSignal = props.setToolbarSignal;
|
||||
let toolButtonRef;
|
||||
const [boundingRect, updateBoundingRect] = createSignal({x:0,y:0});
|
||||
const [isOverlayDisplay, setOverlayDisplay] = createSignal(false);
|
||||
const [isAnimating, setAnimating] = createSignal(false);
|
||||
const [className, setClassName] = createSignal({})
|
||||
const [timerID, setTimerID] = createSignal(0);
|
||||
const [{item:v,toolbarSignal,setToolbarSignal},_] = splitProps(props,["item","toolbarSignal","setToolbarSignal"])
|
||||
|
||||
const overlayVisibleFalseTimerFn = ()=>{
|
||||
setOverlayDisplay(false)
|
||||
setAnimating(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 用於animate Overlay的顯示與隱藏效果
|
||||
* @param isVisible{boolean} 手動指定是要顯示還是隱藏Overlay,
|
||||
* 未指定該param時,根據當前Signal切換狀態
|
||||
* */
|
||||
const changeOverlayVisibility = function(isVisible) {
|
||||
// 防抖處理
|
||||
if (isAnimating()===true) return 0;
|
||||
// 移除現有的Timer
|
||||
clearTimeout(timerID());
|
||||
setTimerID(0);
|
||||
// 清空className,移除所有animation
|
||||
setClassName("")
|
||||
// isVisible===true
|
||||
if (isVisible!==undefined&&isVisible!==null&&isVisible===true) {
|
||||
if (isOverlayDisplay()&&isOverlayDisplay()===true) return 0;
|
||||
setAnimating(true);
|
||||
setClassName("animate-fade-in");
|
||||
setOverlayDisplay(true);
|
||||
} else if (isVisible!==undefined&&isVisible!==null&&isVisible===false) {
|
||||
if (isOverlayDisplay()&&isOverlayDisplay()===false) return 0;
|
||||
setClassName("animate-fade-out");
|
||||
setTimerID(setTimeout(overlayVisibleFalseTimerFn,90))
|
||||
} else {
|
||||
// no isVisible param
|
||||
if (isOverlayDisplay()===true) {
|
||||
// to false
|
||||
setAnimating(true);
|
||||
setClassName("animate-fade-out");
|
||||
setTimerID(setTimeout(overlayVisibleFalseTimerFn,90))
|
||||
} else if (isOverlayDisplay()===false) {
|
||||
setClassName("animate-fade-in");
|
||||
setOverlayDisplay(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createEffect(on(toolbarSignal,(tbsignal)=>{
|
||||
if (tbsignal.activeTool!==v.action) changeOverlayVisibility(false)
|
||||
}))
|
||||
|
||||
// noinspection HtmlUnknownAttribute
|
||||
return (
|
||||
<>
|
||||
<div onClick={() => {
|
||||
if (v.action === "drawer") {
|
||||
setToolbarSignal({
|
||||
...toolbarSignal(),
|
||||
isDrawerOpen: !toolbarSignal().isDrawerOpen
|
||||
});
|
||||
} else if (v.action&&v.action===toolbarSignal().activeTool&&v.overlay) {
|
||||
// 傳入BoundingRect讓Overlay更新位置
|
||||
updateBoundingRect(JSON.parse(JSON.stringify(toolButtonRef.getBoundingClientRect())))
|
||||
// 切換Overlay的顯示
|
||||
changeOverlayVisibility();
|
||||
} else if (!(["clear"].includes(v.action))&&v.action){
|
||||
setToolbarSignal({
|
||||
...toolbarSignal(),
|
||||
activeTool: v.action,
|
||||
})
|
||||
}
|
||||
}}
|
||||
}} ref={toolButtonRef}
|
||||
classList={{
|
||||
"toolbar-item": v.type !== "pagination-indicator"&&v.type!=="pagination-indicator-sidebar",
|
||||
"toolbar-item-separator": v.type === "separator",
|
||||
@ -60,5 +119,12 @@ export default function ToolBarButton(props) {
|
||||
</div>
|
||||
</> : void 0}
|
||||
</div>
|
||||
<Show when={v.type==="button"&&isOverlayDisplay()===true}>
|
||||
<Dynamic component={v.overlay??null}
|
||||
boundingRect={boundingRect()}
|
||||
animateClass={className}
|
||||
/>
|
||||
</Show>
|
||||
</>
|
||||
)
|
||||
}
|
0
src/renderer/src/i18n/manifest.js
Normal file
0
src/renderer/src/i18n/manifest.js
Normal file
18
src/renderer/src/overlays/PenOverlays.jsx
Normal file
18
src/renderer/src/overlays/PenOverlays.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { Portal } from 'solid-js/web'
|
||||
import { splitProps } from 'solid-js'
|
||||
|
||||
export default function PenOverlays(props) {
|
||||
const [{toolbarSignal,setToolbarSignal,boundingRect,animateClass},_] = splitProps(props,["toolbarSignal","setToolbarSignal","boundingRect","animateClass"]);
|
||||
return (
|
||||
<>
|
||||
<Portal>
|
||||
<div class={`pen-overlays ${animateClass()}`} style={{
|
||||
left: `${(boundingRect.left-(boundingRect.width/4)).toFixed(3)}px`,
|
||||
bottom: `${(boundingRect.bottom-boundingRect.y).toFixed(3)}px`,
|
||||
}}>
|
||||
<div class="h-9 w-full bg-zinc-800 border-b border-zinc-600"></div>
|
||||
</div>
|
||||
</Portal>
|
||||
</>
|
||||
)
|
||||
}
|
17
src/renderer/src/styles/animations.css
Normal file
17
src/renderer/src/styles/animations.css
Normal file
@ -0,0 +1,17 @@
|
||||
@keyframes fade-in {
|
||||
from {opacity: 0}
|
||||
to {opacity: 1}
|
||||
}
|
||||
@keyframes fade-out {
|
||||
from {opacity: 1}
|
||||
to {opacity: 0}
|
||||
}
|
||||
.animate-fade-in {
|
||||
animation-name: fade-in !important;
|
||||
animation-duration: 100ms !important;
|
||||
}
|
||||
.animate-fade-out {
|
||||
animation-name: fade-out !important;
|
||||
animation-duration: 100ms !important;
|
||||
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
||||
}
|
@ -13,10 +13,10 @@
|
||||
user-select: none;
|
||||
}
|
||||
.zph-container.window-border {
|
||||
@apply ring-1 ring-inset ring-red-600 ;
|
||||
@apply "ring-1 ring-inset ring-red-600";
|
||||
}
|
||||
.zph-container.window-black {
|
||||
background-color: black !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
/*Main Toolbar*/
|
||||
@ -31,7 +31,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 50;
|
||||
@apply bottom-1;
|
||||
@apply "bottom-1";
|
||||
}
|
||||
.main-toolbar-container>div {
|
||||
flex-shrink: 0 !important;
|
||||
@ -39,17 +39,17 @@
|
||||
pointer-events: auto;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
@apply rounded-md shadow-md ring-1 ring-inset ring-zinc-700;
|
||||
transition-duration: 200ms;
|
||||
transition-property: max-height;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
@apply "rounded-md shadow-md ring-1 ring-inset ring-zinc-700";
|
||||
}
|
||||
|
||||
.main-toolbar-container[data-mode="default"]>div {
|
||||
@apply max-h-9;
|
||||
@apply "max-h-9";
|
||||
}
|
||||
.main-toolbar-container[data-mode="drawer"]>div {
|
||||
@apply max-h-48;
|
||||
@apply "max-h-48";
|
||||
}
|
||||
.absolute-toolbar-space {
|
||||
position: absolute;
|
||||
@ -60,7 +60,7 @@
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
@apply h-48;
|
||||
@apply "h-48";
|
||||
}
|
||||
.absolute-toolbar-space .toolbar-buttons {
|
||||
display: flex;
|
||||
@ -71,13 +71,13 @@
|
||||
transition-duration: 200ms;
|
||||
transition-property: padding-bottom;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
@apply h-9 w-fit px-1;
|
||||
@apply "h-9 w-fit px-1";
|
||||
}
|
||||
.main-toolbar-container[data-mode="default"] .absolute-toolbar-space .toolbar-buttons {
|
||||
@apply pb-0;
|
||||
@apply "pb-0";
|
||||
}
|
||||
.main-toolbar-container[data-mode="drawer"] .absolute-toolbar-space .toolbar-buttons {
|
||||
@apply pb-1.5;
|
||||
@apply "pb-1.5";
|
||||
}
|
||||
.toolbar-item {
|
||||
display: flex;
|
||||
@ -85,20 +85,20 @@
|
||||
justify-content: center;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
@apply h-9 w-8 ;
|
||||
@apply "h-9 w-8";
|
||||
}
|
||||
.toolbar-item>img , .toolbar-item img {
|
||||
-webkit-user-drag: none !important;
|
||||
@apply h-5 w-5;
|
||||
@apply "h-5 w-5";
|
||||
}
|
||||
.toolbar-item-separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@apply h-9 w-1.5;
|
||||
@apply "h-9 w-1.5";
|
||||
}
|
||||
.toolbar-item-separator>div {
|
||||
@apply h-5 w-px bg-white/50
|
||||
@apply "h-5 w-px bg-white/50";
|
||||
}
|
||||
|
||||
/*Drawer*/
|
||||
@ -110,7 +110,7 @@
|
||||
justify-content: center;
|
||||
padding: 0.75rem;
|
||||
width: 100%;
|
||||
@apply mb-1 grow;
|
||||
@apply "mb-1 grow";
|
||||
}
|
||||
.drawer-bottom-separator {
|
||||
position: absolute;
|
||||
@ -129,38 +129,38 @@
|
||||
transition-duration: 200ms;
|
||||
transition-property: width;
|
||||
transition-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
||||
@apply bg-zinc-500 rounded-full ;
|
||||
@apply "bg-zinc-500 rounded-full";
|
||||
}
|
||||
.drawer-open-button-state {
|
||||
@apply h-8 w-8 bg-blue-500/50 rounded-md flex items-center justify-center;
|
||||
@apply "h-8 w-8 bg-blue-500/50 rounded-md flex items-center justify-center";
|
||||
}
|
||||
|
||||
.main-toolbar-container[data-mode="default"] .drawer-bottom-separator>div {
|
||||
@apply w-0;
|
||||
@apply "w-0";
|
||||
}
|
||||
.main-toolbar-container[data-mode="drawer"] .drawer-bottom-separator>div {
|
||||
@apply w-100%;
|
||||
@apply "w-100%";
|
||||
}
|
||||
.drawer-items {
|
||||
display: grid;
|
||||
grid-template-columns:repeat(5, minmax(0, 1fr));
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@apply p-2 gap-2;
|
||||
@apply "p-2 gap-2";
|
||||
}
|
||||
.drawer-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@apply h-full w-full;
|
||||
@apply "h-full w-full";
|
||||
}
|
||||
.drawer-item img {
|
||||
-webkit-user-drag: none !important;
|
||||
}
|
||||
.drawer-item .drawer-item-text {
|
||||
font-size: 0.72rem;
|
||||
@apply text-white mt-1;
|
||||
@apply "text-white mt-1";
|
||||
}
|
||||
|
||||
/*Toolbar Left Right Containers*/
|
||||
@ -175,10 +175,10 @@
|
||||
width: 100vw;
|
||||
z-index: 50;
|
||||
pointer-events: none;
|
||||
@apply bottom-1;
|
||||
@apply "bottom-1";
|
||||
}
|
||||
.toolbar-right-container:nth-child(0) , .toolbar-left-container:last-child {
|
||||
@apply shrink-0 h-9 bg-transparent;
|
||||
@apply "shrink-0 h-9 bg-transparent";
|
||||
}
|
||||
.end-slideshow-button *,.mainmenu-button * {
|
||||
-webkit-user-drag: none !important;
|
||||
@ -190,7 +190,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
@apply h-9 w-9 rounded-md bg-red-700/75 ring-1 ring-inset ring-red-500 shadow-md;
|
||||
@apply "h-9 w-9 rounded-md bg-red-700/75 ring-1 ring-inset ring-red-500 shadow-md";
|
||||
}
|
||||
.mainmenu-button {
|
||||
pointer-events: auto;
|
||||
@ -199,7 +199,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
@apply h-9 w-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700;
|
||||
@apply "h-9 w-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700";
|
||||
}
|
||||
|
||||
/*BottomSidebar*/
|
||||
@ -212,7 +212,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 50;
|
||||
@apply bottom-1
|
||||
@apply "bottom-1";
|
||||
}
|
||||
.bottom-sidebar-container._left {
|
||||
justify-content: start;
|
||||
@ -227,10 +227,10 @@
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
@apply h-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700;
|
||||
transition-duration: 200ms;
|
||||
transition-property: max-height;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
@apply "h-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700";
|
||||
}
|
||||
.absolute-bottom-sidebar-space {
|
||||
position: absolute;
|
||||
@ -241,7 +241,7 @@
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
@apply h-9;
|
||||
@apply "h-9";
|
||||
}
|
||||
.absolute-bottom-sidebar-space .toolbar-buttons {
|
||||
display: flex;
|
||||
@ -252,7 +252,7 @@
|
||||
transition-duration: 200ms;
|
||||
transition-property: padding-bottom;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
@apply h-9 w-fit px-1;
|
||||
@apply "h-9 w-fit px-1";
|
||||
}
|
||||
|
||||
/*Pagination Indicator*/
|
||||
@ -261,13 +261,13 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 4.5rem;
|
||||
@apply h-9;
|
||||
@apply "h-9";
|
||||
}
|
||||
.pagination-indicator .now-page-text {
|
||||
@apply text-white text-3.5 font-bold leading-none mr-0.5;
|
||||
@apply "text-white text-3.5 font-bold leading-none mr-0.5";
|
||||
}
|
||||
.pagination-indicator .total-page-text {
|
||||
@apply text-white text-3 leading-none;
|
||||
@apply "text-white text-3 leading-none";
|
||||
}
|
||||
|
||||
/*Toolbar Item Animation*/
|
||||
@ -280,19 +280,19 @@
|
||||
transition-property: all;
|
||||
z-index: 0;
|
||||
transition-timing-function: cubic-bezier(0.85, 0, 0.15, 1); !important;
|
||||
@apply duration-100 scale-75 opacity-0;
|
||||
@apply "duration-100 scale-75 opacity-0";
|
||||
}
|
||||
.toolbar-item>img.icon-solid , .toolbar-item img.icon-solid {
|
||||
display: none;
|
||||
}
|
||||
.toolbar-item .tb-animate-bg>div {
|
||||
@apply h-7.5 w-7.5 bg-zinc-300/12 rounded-0.275rem;
|
||||
@apply "h-7.5 w-7.5 bg-zinc-300/12 rounded-0.275rem";
|
||||
}
|
||||
.toolbar-item.toolbar-item-active .tb-animate-bg>div {
|
||||
@apply bg-blue-300/15 ring-1 ring-inset ring-blue-400/50
|
||||
@apply "bg-blue-300/15 ring-1 ring-inset ring-blue-400/50";
|
||||
}
|
||||
.toolbar-item.gest-pointer-down .tb-animate-bg , .toolbar-item.toolbar-item-active .tb-animate-bg{
|
||||
@apply scale-100 opacity-100;
|
||||
@apply "scale-100 opacity-100";
|
||||
}
|
||||
.toolbar-item.gest-pointer-down>img.icon-solid , .toolbar-item.gest-pointer-down img.icon-solid ,
|
||||
.toolbar-item.toolbar-item-active>img.icon-solid , .toolbar-item.toolbar-item-active img.icon-solid{
|
||||
@ -314,7 +314,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 50;
|
||||
@apply bottom-35vh
|
||||
@apply "bottom-35vh";
|
||||
}
|
||||
.screen-sidebar-container._left {
|
||||
justify-content: start;
|
||||
@ -329,7 +329,7 @@
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
@apply w-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700;
|
||||
@apply "w-9 rounded-md shadow-md ring-1 ring-inset ring-zinc-700";
|
||||
}
|
||||
.absolute-screen-sidebar-space {
|
||||
position: absolute;
|
||||
@ -340,7 +340,7 @@
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@apply w-9;
|
||||
@apply "w-9";
|
||||
}
|
||||
.absolute-screen-sidebar-space .toolbar-buttons {
|
||||
display: flex;
|
||||
@ -351,7 +351,7 @@
|
||||
transition-duration: 200ms;
|
||||
transition-property: padding-bottom;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
@apply w-9 h-fit py-1;
|
||||
@apply "w-9 h-fit py-1";
|
||||
}
|
||||
|
||||
.absolute-screen-sidebar-space .toolbar-item {
|
||||
@ -360,16 +360,16 @@
|
||||
justify-content: center;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
@apply h-8 w-9 ;
|
||||
@apply "h-8 w-9";
|
||||
}
|
||||
.absolute-screen-sidebar-space .toolbar-item-separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@apply h-1.5 w-9;
|
||||
@apply "h-1.5 w-9";
|
||||
}
|
||||
.absolute-screen-sidebar-space .toolbar-item-separator>div {
|
||||
@apply h-px w-5 bg-white/50
|
||||
@apply "h-px w-5 bg-white/50";
|
||||
}
|
||||
|
||||
.absolute-screen-sidebar-space .pagination-indicator {
|
||||
@ -377,20 +377,34 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@apply w-9 h-10;
|
||||
@apply "w-9 h-10";
|
||||
}
|
||||
.absolute-screen-sidebar-space .pagination-indicator .now-page-text {
|
||||
@apply text-white text-3.35 font-normal leading-none;
|
||||
@apply "text-white text-3.35 font-normal leading-none";
|
||||
}
|
||||
.absolute-screen-sidebar-space .pagination-indicator .total-page-text {
|
||||
@apply text-white/75 mt-1 text-2.25 leading-none;
|
||||
@apply "text-white/75 mt-1 text-2.25 leading-none";
|
||||
}
|
||||
|
||||
|
||||
/*Watermark*/
|
||||
.brand-watermark {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
left: 0.25rem;
|
||||
@apply h-6;
|
||||
@apply "h-6";
|
||||
}
|
||||
|
||||
/*Pen Overlays*/
|
||||
.pen-overlays {
|
||||
z-index: 60;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
overflow: clip;
|
||||
@apply "w-56 h-48 mb-2.5 bg-zinc-900/80 rounded-md ring-1 ring-zinc-700";
|
||||
}
|
||||
.pen-overlays * {
|
||||
user-select: none !important;
|
||||
-webkit-user-drag: none !important;
|
||||
}
|
Loading…
Reference in New Issue
Block a user