@hunterchen/canvas 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -8
- package/dist/components/canvas/canvas.d.ts +3 -4
- package/dist/components/canvas/canvas.d.ts.map +1 -1
- package/dist/components/canvas/canvas.js +3 -6
- package/dist/components/canvas/canvas.js.map +1 -1
- package/dist/components/canvas/component.js +2 -2
- package/dist/components/canvas/component.js.map +1 -1
- package/dist/components/canvas/navbar/index.d.ts +4 -10
- package/dist/components/canvas/navbar/index.d.ts.map +1 -1
- package/dist/components/canvas/navbar/index.js +16 -18
- package/dist/components/canvas/navbar/index.js.map +1 -1
- package/dist/components/canvas/navbar/single-button.d.ts +3 -6
- package/dist/components/canvas/navbar/single-button.d.ts.map +1 -1
- package/dist/components/canvas/navbar/single-button.js +9 -8
- package/dist/components/canvas/navbar/single-button.js.map +1 -1
- package/dist/components/canvas/wrapper.d.ts.map +1 -1
- package/dist/components/canvas/wrapper.js +1 -2
- package/dist/components/canvas/wrapper.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/index.d.ts +28 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -9
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -2
- package/src/components/canvas/canvas.tsx +7 -14
- package/src/components/canvas/component.tsx +2 -2
- package/src/components/canvas/navbar/index.tsx +28 -64
- package/src/components/canvas/navbar/single-button.tsx +18 -33
- package/src/components/canvas/wrapper.tsx +1 -2
- package/src/index.ts +1 -2
- package/src/types/index.ts +27 -7
- package/dist/components/canvas/reset.d.ts +0 -5
- package/dist/components/canvas/reset.d.ts.map +0 -1
- package/dist/components/canvas/reset.js +0 -7
- package/dist/components/canvas/reset.js.map +0 -1
- package/src/components/canvas/reset.tsx +0 -21
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAGrE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACxG,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGxF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAG5F,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AAGpC,YAAY,EAAE,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAGrE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACxG,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGxF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAG5F,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AAGpC,YAAY,EAAE,kBAAkB,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,5 +15,4 @@ export { usePerformanceMode as usePerformanceModeLegacy } from './hooks/usePerfo
|
|
|
15
15
|
export * from './lib/canvas';
|
|
16
16
|
export * from './lib/constants';
|
|
17
17
|
export * from './utils/performance';
|
|
18
|
-
export { CanvasSection } from './types';
|
|
19
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAErE,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGxG,QAAQ;AACR,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE5F,YAAY;AACZ,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAErE,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGxG,QAAQ;AACR,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE5F,YAAY;AACZ,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--canvas-beige:#f7f1e5;--canvas-coral:#ffb5a7;--canvas-lilac:#d9c8e6;--canvas-salmon:#ffa585;--canvas-heavy:#3c204c;--canvas-emphasis:#513b7a;--canvas-active:#8f57ad;--canvas-tinted:#c9a7db;--canvas-medium:#776780;--canvas-light:#c3b8cb;--canvas-faint-lilac:#f5f2f7;--canvas-offwhite:#fdfcfd;--canvas-highlight:#f5f2f7;--canvas-border-light:0 0% 89%}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-top-10{top:-2.5rem}.bottom-12{bottom:3rem}.bottom-24{bottom:6rem}.bottom-4{bottom:1rem}.left-1\/2{left:50%}.left-4{left:1rem}.top-1\/2{top:50%}.top-24{top:6rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[1000\]{z-index:1000}.m-auto{margin:auto}.mb-4{margin-bottom:1rem}.block{display:block}.flex{display:flex}.hidden{display:none}.h-5{height:1.25rem}.h-auto{height:auto}.h-full{height:100%}.w-5{width:1.25rem}.w-full{width:100%}.flex-shrink-0{flex-shrink:0}.grow{flex-grow:1}.origin-center{transform-origin:center}.origin-top-left{transform-origin:top left}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-\[url\(\'\/customcursor\.svg\'\)\2c auto\]{cursor:url(/customcursor.svg),auto}.cursor-default{cursor:default}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.border,.border-\[1px\]{border-width:1px}.border-border{border-color:hsl(var(--border))}.bg-\[\#EEE2FB\]{--tw-bg-opacity:1;background-color:rgb(238 226 251/var(--tw-bg-opacity,1))}.bg-canvas-highlight{background-color:var(--canvas-highlight)}.bg-canvas-offwhite{background-color:var(--canvas-offwhite)}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.bg-\[radial-gradient\(\#776780_1\.5px\2c transparent_1px\)\]{background-image:radial-gradient(#776780 1.5px,transparent 0)}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.bg-none{background-image:none}.from-black\/10{--tw-gradient-from:rgba(0,0,0,.1) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-contain{-o-object-fit:contain;object-fit:contain}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-\[1px\]{padding-left:1px;padding-right:1px}.py-1{padding-top:.25rem;padding-bottom:.25rem}.pb-\[2\.5px\]{padding-bottom:2.5px}.pt-\[1px\]{padding-top:1px}.text-center{text-align:center}.font-canvas-figtree{font-family:var(--font-figtree)}.font-canvas-jetbrains-mono{font-family:var(--font-jetbrainsmono)}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.text-\[\#543C5AB2\]{color:#543c5ab2}.text-canvas-emphasis{color:var(--canvas-emphasis)}.text-canvas-heavy{color:var(--canvas-heavy)}.text-canvas-light{color:var(--canvas-light)}.text-canvas-medium{color:var(--canvas-medium)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-100{opacity:1}.opacity-35{opacity:.35}.opacity-60{opacity:.6}.shadow-\[0_20px_40px_rgba\(103\2c 86\2c 86\2c 0\.15\)\]{--tw-shadow:0 20px 40px hsla(0,9%,37%,.15);--tw-shadow-colored:0 20px 40px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-\[0_6px_12px_rgba\(0\2c 0\2c 0\2c 0\.10\)\]{--tw-shadow:0 6px 12px rgba(0,0,0,.1);--tw-shadow-colored:0 6px 12px var(--tw-shadow-color)}.shadow-\[0_6px_12px_rgba\(0\2c 0\2c 0\2c 0\.10\)\],.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0) scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1)) rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0) scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1)) rotate(var(--tw-exit-rotate,0))}}.duration-200{animation-duration:.2s}.running{animation-play-state:running}.\[background-size\:22px_22px\]{background-size:22px 22px}.hover\:bg-gray-600:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}@media (min-width:640px){.sm\:top-4{top:1rem}}@media (min-width:768px){.md\:bottom-4{bottom:1rem}.md\:inline{display:inline}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
|
1
|
+
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--canvas-beige:#f7f1e5;--canvas-coral:#ffb5a7;--canvas-lilac:#d9c8e6;--canvas-salmon:#ffa585;--canvas-heavy:#3c204c;--canvas-emphasis:#513b7a;--canvas-active:#8f57ad;--canvas-tinted:#c9a7db;--canvas-medium:#776780;--canvas-light:#c3b8cb;--canvas-faint-lilac:#f5f2f7;--canvas-offwhite:#fdfcfd;--canvas-highlight:#f5f2f7;--canvas-border-light:0 0% 89%}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-top-10{top:-2.5rem}.bottom-12{bottom:3rem}.bottom-24{bottom:6rem}.left-1\/2{left:50%}.left-4{left:1rem}.top-1\/2{top:50%}.top-24{top:6rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[1000\]{z-index:1000}.m-auto{margin:auto}.mb-4{margin-bottom:1rem}.block{display:block}.flex{display:flex}.hidden{display:none}.h-5{height:1.25rem}.h-auto{height:auto}.h-full{height:100%}.w-5{width:1.25rem}.w-full{width:100%}.flex-shrink-0{flex-shrink:0}.grow{flex-grow:1}.origin-center{transform-origin:center}.origin-top-left{transform-origin:top left}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-default{cursor:default}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded-\[10px\]{border-radius:10px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.border,.border-\[1px\]{border-width:1px}.border-border{border-color:hsl(var(--border))}.bg-\[\#EEE2FB\]{--tw-bg-opacity:1;background-color:rgb(238 226 251/var(--tw-bg-opacity,1))}.bg-canvas-highlight{background-color:var(--canvas-highlight)}.bg-canvas-offwhite{background-color:var(--canvas-offwhite)}.bg-\[radial-gradient\(\#776780_1\.5px\2c transparent_1px\)\]{background-image:radial-gradient(#776780 1.5px,transparent 0)}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.bg-none{background-image:none}.from-black\/10{--tw-gradient-from:rgba(0,0,0,.1) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-contain{-o-object-fit:contain;object-fit:contain}.p-1{padding:.25rem}.p-2{padding:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-\[1px\]{padding-left:1px;padding-right:1px}.py-1{padding-top:.25rem;padding-bottom:.25rem}.pb-\[2\.5px\]{padding-bottom:2.5px}.pt-\[1px\]{padding-top:1px}.text-center{text-align:center}.font-canvas-figtree{font-family:var(--font-figtree)}.font-canvas-jetbrains-mono{font-family:var(--font-jetbrainsmono)}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.text-\[\#543C5AB2\]{color:#543c5ab2}.text-canvas-emphasis{color:var(--canvas-emphasis)}.text-canvas-heavy{color:var(--canvas-heavy)}.text-canvas-light{color:var(--canvas-light)}.text-canvas-medium{color:var(--canvas-medium)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-100{opacity:1}.opacity-35{opacity:.35}.opacity-60{opacity:.6}.shadow-\[0_20px_40px_rgba\(103\2c 86\2c 86\2c 0\.15\)\]{--tw-shadow:0 20px 40px hsla(0,9%,37%,.15);--tw-shadow-colored:0 20px 40px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-\[0_6px_12px_rgba\(0\2c 0\2c 0\2c 0\.10\)\]{--tw-shadow:0 6px 12px rgba(0,0,0,.1);--tw-shadow-colored:0 6px 12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0) scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1)) rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0) scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1)) rotate(var(--tw-exit-rotate,0))}}.duration-200{animation-duration:.2s}.running{animation-play-state:running}.\[background-size\:22px_22px\]{background-size:22px 22px}@media (min-width:640px){.sm\:top-4{top:1rem}}@media (min-width:768px){.md\:bottom-4{bottom:1rem}.md\:inline{display:inline}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,12 +8,33 @@ export interface SectionCoordinates {
|
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
/**
|
|
12
|
+
* CanvasSection is now a generic string type.
|
|
13
|
+
* Apps define their own section IDs as strings.
|
|
14
|
+
*/
|
|
15
|
+
export type CanvasSection = string;
|
|
16
|
+
/**
|
|
17
|
+
* Configuration for a single navigation item.
|
|
18
|
+
* Combines section identity, display info, and coordinates.
|
|
19
|
+
*/
|
|
20
|
+
export interface NavItem {
|
|
21
|
+
/** Unique identifier for this section */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Display label shown in the navbar */
|
|
24
|
+
label: string;
|
|
25
|
+
/** Lucide icon name or a custom icon component */
|
|
26
|
+
icon: string | React.ComponentType<{
|
|
27
|
+
className?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/** X coordinate on the canvas */
|
|
30
|
+
x: number;
|
|
31
|
+
/** Y coordinate on the canvas */
|
|
32
|
+
y: number;
|
|
33
|
+
/** Width of the section viewport */
|
|
34
|
+
width: number;
|
|
35
|
+
/** Height of the section viewport */
|
|
36
|
+
height: number;
|
|
37
|
+
/** If true, clicking this section triggers the reset/home behavior */
|
|
38
|
+
isHome?: boolean;
|
|
18
39
|
}
|
|
19
40
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAEnC;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,iCAAiC;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,iCAAiC;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
|
package/dist/types/index.js
CHANGED
|
@@ -2,13 +2,5 @@
|
|
|
2
2
|
* Generic types for the canvas library
|
|
3
3
|
* Apps should extend these types with their specific enums and constants
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
6
|
-
(function (CanvasSection) {
|
|
7
|
-
CanvasSection["Home"] = "home";
|
|
8
|
-
CanvasSection["About"] = "about";
|
|
9
|
-
CanvasSection["Projects"] = "projects";
|
|
10
|
-
CanvasSection["Sponsors"] = "sponsors";
|
|
11
|
-
CanvasSection["FAQ"] = "faq";
|
|
12
|
-
CanvasSection["Team"] = "team";
|
|
13
|
-
})(CanvasSection || (CanvasSection = {}));
|
|
5
|
+
export {};
|
|
14
6
|
//# sourceMappingURL=index.js.map
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunterchen/canvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "A React-based canvas library for creating pannable, zoomable, and interactive canvas experiences.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -56,7 +56,6 @@
|
|
|
56
56
|
"@types/node": "^25.0.6",
|
|
57
57
|
"@types/react": "19.0.12",
|
|
58
58
|
"@types/react-dom": "19.0.4",
|
|
59
|
-
"next": "^16.1.1",
|
|
60
59
|
"tailwindcss": "^3.4.19",
|
|
61
60
|
"tailwindcss-animate": "^1.0.7",
|
|
62
61
|
"typescript": "^5.8.2"
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
import useWindowDimensions from "../../hooks/useWindowDimensions";
|
|
40
40
|
import Navbar from "./navbar";
|
|
41
41
|
import Toolbar from "./toolbar";
|
|
42
|
-
import { CanvasSection,
|
|
42
|
+
import type { CanvasSection, NavItem, SectionCoordinates } from "../../types";
|
|
43
43
|
import { CanvasWrapper } from "./wrapper";
|
|
44
44
|
import { usePerformanceMode } from "../../hooks/usePerformanceMode";
|
|
45
45
|
import type { ReactNode } from "react";
|
|
@@ -49,9 +49,8 @@ interface Props {
|
|
|
49
49
|
children: React.ReactNode;
|
|
50
50
|
|
|
51
51
|
// Navbar data (optional). If omitted, navbar is hidden.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
navbarHomeSection?: CanvasSection;
|
|
52
|
+
/** Array of navigation items for the navbar. If omitted, navbar is hidden. */
|
|
53
|
+
navItems?: NavItem[];
|
|
55
54
|
|
|
56
55
|
// ============== Intro Animation Customization ==============
|
|
57
56
|
/** Disable intro animation entirely */
|
|
@@ -83,9 +82,7 @@ const stopAllMotion = (
|
|
|
83
82
|
const Canvas: FC<Props> = ({
|
|
84
83
|
children,
|
|
85
84
|
homeCoordinates,
|
|
86
|
-
|
|
87
|
-
navbarSections,
|
|
88
|
-
navbarHomeSection,
|
|
85
|
+
navItems,
|
|
89
86
|
skipIntro = false,
|
|
90
87
|
introContent,
|
|
91
88
|
loadingText,
|
|
@@ -98,9 +95,7 @@ const Canvas: FC<Props> = ({
|
|
|
98
95
|
|
|
99
96
|
const { mode } = usePerformanceMode();
|
|
100
97
|
|
|
101
|
-
const
|
|
102
|
-
const navHomeSection = navbarHomeSection ?? CanvasSection.Home;
|
|
103
|
-
const hasNavbarData = Boolean(navbarCoordinates);
|
|
98
|
+
const hasNavbar = Boolean(navItems && navItems.length > 0);
|
|
104
99
|
|
|
105
100
|
const sceneWidth = canvasWidth;
|
|
106
101
|
const sceneHeight = canvasHeight;
|
|
@@ -616,13 +611,11 @@ const Canvas: FC<Props> = ({
|
|
|
616
611
|
{animationStage >= 2 && (
|
|
617
612
|
<>
|
|
618
613
|
<Toolbar homeCoordinates={offsetHomeCoordinates} />
|
|
619
|
-
{
|
|
614
|
+
{hasNavbar && navItems ? (
|
|
620
615
|
<Navbar
|
|
621
616
|
panToOffset={handlePanToOffset}
|
|
622
617
|
onReset={onResetViewAndItems}
|
|
623
|
-
|
|
624
|
-
sections={navSections as CanvasSection[]}
|
|
625
|
-
homeSection={navHomeSection}
|
|
618
|
+
items={navItems}
|
|
626
619
|
/>
|
|
627
620
|
) : null}
|
|
628
621
|
</>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FC, useEffect, useState } from "react";
|
|
2
2
|
import type { SectionCoordinates } from "../../types";
|
|
3
3
|
import { useCanvasContext } from "../../contexts/CanvasContext";
|
|
4
|
-
import
|
|
4
|
+
import { motion } from "framer-motion";
|
|
5
5
|
import useWindowDimensions from "../../hooks/useWindowDimensions";
|
|
6
6
|
import { usePerformanceMode } from "../../hooks/usePerformanceMode";
|
|
7
7
|
import {
|
|
@@ -210,7 +210,7 @@ export const CanvasComponent: FC<CanvasProps> = ({
|
|
|
210
210
|
}}
|
|
211
211
|
>
|
|
212
212
|
{shouldShowFallback ? (
|
|
213
|
-
<
|
|
213
|
+
<motion.img
|
|
214
214
|
src={imageFallback}
|
|
215
215
|
alt="Canvas Fallback"
|
|
216
216
|
width={offset?.width ?? 1920}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { motion, useMotionValueEvent } from "framer-motion";
|
|
2
|
-
import { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
+
import { useState, useRef, useEffect, useCallback, useMemo } from "react";
|
|
3
3
|
import SingleButton from "./single-button";
|
|
4
|
-
|
|
5
|
-
// For now, apps will need to re-export from this library
|
|
6
|
-
import { CanvasSection } from "../../../types";
|
|
4
|
+
import type { NavItem } from "../../../types";
|
|
7
5
|
import { useCanvasContext } from "../../../contexts/CanvasContext";
|
|
8
6
|
import useWindowDimensions from "../../../hooks/useWindowDimensions";
|
|
9
7
|
import { usePerformanceMode } from "../../../hooks/usePerformanceMode";
|
|
@@ -23,18 +21,14 @@ interface NavbarProps {
|
|
|
23
21
|
zoom?: number,
|
|
24
22
|
) => void;
|
|
25
23
|
onReset: () => void;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
sections: CanvasSection[];
|
|
29
|
-
homeSection: CanvasSection;
|
|
24
|
+
/** Array of navigation items defining sections, their icons, and coordinates */
|
|
25
|
+
items: NavItem[];
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
export default function Navbar({
|
|
33
29
|
panToOffset,
|
|
34
30
|
onReset,
|
|
35
|
-
|
|
36
|
-
sections,
|
|
37
|
-
homeSection,
|
|
31
|
+
items,
|
|
38
32
|
}: NavbarProps) {
|
|
39
33
|
const { x, y, scale, animationStage, setNextTargetSection } =
|
|
40
34
|
useCanvasContext();
|
|
@@ -56,6 +50,9 @@ export default function Navbar({
|
|
|
56
50
|
// Derive debounce duration from performance mode
|
|
57
51
|
const debounceMs = NAVBAR_DEBOUNCE_MS[mode] ?? 0;
|
|
58
52
|
|
|
53
|
+
// Find the home section from items
|
|
54
|
+
const homeItem = useMemo(() => items.find((item) => item.isHome), [items]);
|
|
55
|
+
|
|
59
56
|
// Leading-edge debounce handler
|
|
60
57
|
const handleDebouncedClick = useCallback(
|
|
61
58
|
(callback: () => void) => {
|
|
@@ -100,25 +97,22 @@ export default function Navbar({
|
|
|
100
97
|
useMotionValueEvent(scale, "change", updateExpandedButton);
|
|
101
98
|
|
|
102
99
|
const handlePan = useCallback(
|
|
103
|
-
function handlePan(
|
|
104
|
-
setExpandedButton(
|
|
100
|
+
function handlePan(item: NavItem) {
|
|
101
|
+
setExpandedButton(item.id);
|
|
105
102
|
activePans.current++;
|
|
106
103
|
|
|
107
104
|
// Predictive pre-render hint: mark the target section so its CanvasComponent can
|
|
108
105
|
// render even before it comes fully into view.
|
|
109
|
-
setNextTargetSection(
|
|
106
|
+
setNextTargetSection(item.id);
|
|
110
107
|
|
|
111
|
-
if (
|
|
108
|
+
if (item.isHome) {
|
|
112
109
|
onReset();
|
|
113
110
|
return;
|
|
114
111
|
}
|
|
115
112
|
|
|
116
|
-
const sectionCoords = coordinates[section];
|
|
117
|
-
if (!sectionCoords) return;
|
|
118
|
-
|
|
119
113
|
const panCoords = getSectionPanCoordinates({
|
|
120
114
|
windowDimensions: { width, height },
|
|
121
|
-
coords:
|
|
115
|
+
coords: { x: item.x, y: item.y, width: item.width, height: item.height },
|
|
122
116
|
targetZoom: defaultZoom,
|
|
123
117
|
negative: true,
|
|
124
118
|
});
|
|
@@ -134,16 +128,18 @@ export default function Navbar({
|
|
|
134
128
|
[panToOffset, onReset, width, height, defaultZoom, setNextTargetSection],
|
|
135
129
|
);
|
|
136
130
|
|
|
137
|
-
// Clean up timers on unmount
|
|
131
|
+
// Clean up timers on unmount and pan to home on animation complete
|
|
138
132
|
useEffect(() => {
|
|
139
133
|
if (animationStage < 2) return;
|
|
140
|
-
|
|
134
|
+
if (homeItem) {
|
|
135
|
+
handlePan(homeItem);
|
|
136
|
+
}
|
|
141
137
|
return () => {
|
|
142
138
|
if (panTimeout.current) clearTimeout(panTimeout.current);
|
|
143
139
|
if (debounceCooldownTimeout.current)
|
|
144
140
|
clearTimeout(debounceCooldownTimeout.current);
|
|
145
141
|
};
|
|
146
|
-
}, [handlePan, animationStage]);
|
|
142
|
+
}, [handlePan, animationStage, homeItem]);
|
|
147
143
|
|
|
148
144
|
return (
|
|
149
145
|
<div
|
|
@@ -163,48 +159,16 @@ export default function Navbar({
|
|
|
163
159
|
<div className="px-4 md:px-8">
|
|
164
160
|
<motion.div className="flex select-none items-center justify-center gap-1 rounded-[10px] border-[1px] border-border bg-canvas-offwhite p-1 shadow-[0_6px_12px_rgba(0,0,0,0.10)]">
|
|
165
161
|
<div className="flex items-center gap-1">
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
onClick={() => handlePan(CanvasSection.About)}
|
|
177
|
-
isPushed={expandedButton === CanvasSection.About}
|
|
178
|
-
onDebouncedClick={handleDebouncedClick}
|
|
179
|
-
/>
|
|
180
|
-
<SingleButton
|
|
181
|
-
label="Projects"
|
|
182
|
-
icon="LayoutDashboard"
|
|
183
|
-
onClick={() => handlePan(CanvasSection.Projects)}
|
|
184
|
-
isPushed={expandedButton === CanvasSection.Projects}
|
|
185
|
-
onDebouncedClick={handleDebouncedClick}
|
|
186
|
-
/>
|
|
187
|
-
<SingleButton
|
|
188
|
-
label="Sponsors"
|
|
189
|
-
icon="Handshake"
|
|
190
|
-
onClick={() => handlePan(CanvasSection.Sponsors)}
|
|
191
|
-
isPushed={expandedButton === CanvasSection.Sponsors}
|
|
192
|
-
onDebouncedClick={handleDebouncedClick}
|
|
193
|
-
/>
|
|
194
|
-
<SingleButton
|
|
195
|
-
label="FAQ"
|
|
196
|
-
icon="HelpCircle"
|
|
197
|
-
onClick={() => handlePan(CanvasSection.FAQ)}
|
|
198
|
-
isPushed={expandedButton === CanvasSection.FAQ}
|
|
199
|
-
onDebouncedClick={handleDebouncedClick}
|
|
200
|
-
/>
|
|
201
|
-
<SingleButton
|
|
202
|
-
label="Team"
|
|
203
|
-
icon="Users"
|
|
204
|
-
onClick={() => handlePan(CanvasSection.Team)}
|
|
205
|
-
isPushed={expandedButton === CanvasSection.Team}
|
|
206
|
-
onDebouncedClick={handleDebouncedClick}
|
|
207
|
-
/>
|
|
162
|
+
{items.map((item) => (
|
|
163
|
+
<SingleButton
|
|
164
|
+
key={item.id}
|
|
165
|
+
label={item.label}
|
|
166
|
+
icon={item.icon}
|
|
167
|
+
onClick={() => handlePan(item)}
|
|
168
|
+
isPushed={expandedButton === item.id}
|
|
169
|
+
onDebouncedClick={handleDebouncedClick}
|
|
170
|
+
/>
|
|
171
|
+
))}
|
|
208
172
|
</div>
|
|
209
173
|
</motion.div>
|
|
210
174
|
</div>
|
|
@@ -2,39 +2,37 @@ import { useState, useEffect } from "react";
|
|
|
2
2
|
import * as LucideIcons from "lucide-react";
|
|
3
3
|
import { AnimatePresence, motion } from "framer-motion";
|
|
4
4
|
|
|
5
|
-
type IconName = keyof typeof LucideIcons;
|
|
6
|
-
|
|
7
5
|
interface SingleButtonProps {
|
|
8
6
|
label: string;
|
|
9
|
-
icon
|
|
10
|
-
|
|
7
|
+
/** Lucide icon name or a custom icon component */
|
|
8
|
+
icon: string | React.ComponentType<{ className?: string }>;
|
|
11
9
|
onClick?: () => void;
|
|
12
10
|
isPushed: boolean;
|
|
13
11
|
link?: string;
|
|
14
|
-
emailAddress?: string;
|
|
15
12
|
onDebouncedClick?: (callback: () => void) => void;
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
export default function SingleButton({
|
|
19
16
|
label,
|
|
20
17
|
icon,
|
|
21
|
-
customIcon,
|
|
22
18
|
onClick,
|
|
23
19
|
isPushed,
|
|
24
20
|
link,
|
|
25
|
-
emailAddress,
|
|
26
21
|
onDebouncedClick,
|
|
27
22
|
}: SingleButtonProps) {
|
|
28
23
|
const [isHovered, setIsHovered] = useState(false);
|
|
29
24
|
const [showTag, setShowTag] = useState(false);
|
|
30
25
|
const [copiedEmail, setCopiedEmail] = useState(false);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
26
|
+
const isLucideIconName = typeof icon === "string";
|
|
27
|
+
const IconComponent = isLucideIconName
|
|
28
|
+
? (LucideIcons[icon as keyof typeof LucideIcons] as LucideIcons.LucideIcon | undefined)
|
|
29
|
+
: icon;
|
|
33
30
|
const TagDelay = 100;
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
if (!IconComponent) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"A valid 'icon' prop is required (Lucide icon name or custom icon component).",
|
|
35
|
+
);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
useEffect(() => {
|
|
@@ -105,16 +103,10 @@ export default function SingleButton({
|
|
|
105
103
|
{isPushed ? (
|
|
106
104
|
<div className="flex items-center gap-2">
|
|
107
105
|
<div>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
) : CustomIcon ? (
|
|
113
|
-
<CustomIcon
|
|
114
|
-
className={`h-5 w-5 flex-shrink-0 ${isPushed ? "text-white" : "text-canvas-medium"
|
|
115
|
-
}`}
|
|
116
|
-
/>
|
|
117
|
-
) : null}
|
|
106
|
+
<IconComponent
|
|
107
|
+
className={`h-5 w-5 flex-shrink-0 ${isPushed ? (isLucideIconName ? "text-canvas-emphasis" : "text-white") : "text-canvas-medium"
|
|
108
|
+
}`}
|
|
109
|
+
/>
|
|
118
110
|
</div>
|
|
119
111
|
<motion.span
|
|
120
112
|
initial={{ opacity: 0, width: 0 }}
|
|
@@ -131,17 +123,10 @@ export default function SingleButton({
|
|
|
131
123
|
</div>
|
|
132
124
|
) : (
|
|
133
125
|
<div>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
/>
|
|
139
|
-
) : CustomIcon ? (
|
|
140
|
-
<CustomIcon
|
|
141
|
-
className={`h-5 w-5 flex-shrink-0 ${isPushed ? "text-white" : "text-canvas-medium"
|
|
142
|
-
}`}
|
|
143
|
-
/>
|
|
144
|
-
) : null}
|
|
126
|
+
<IconComponent
|
|
127
|
+
className={`h-5 w-5 flex-shrink-0 ${isPushed ? (isLucideIconName ? "text-canvas-emphasis" : "text-white") : "text-canvas-medium"
|
|
128
|
+
}`}
|
|
129
|
+
/>
|
|
145
130
|
<AnimatePresence>
|
|
146
131
|
{showTag && !isPushed && (
|
|
147
132
|
<motion.div
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { motion, type MotionValue, type Transition, useMotionValue } from "framer-motion";
|
|
2
2
|
import { useState, useEffect, useRef, type ReactNode } from "react";
|
|
3
|
-
import Image from "next/image";
|
|
4
3
|
import {
|
|
5
4
|
MAX_DIM_RATIO,
|
|
6
5
|
GROW_TRANSITION,
|
|
@@ -41,7 +40,7 @@ interface CanvasWrapperProps {
|
|
|
41
40
|
*/
|
|
42
41
|
const DefaultIntroContent = () => (
|
|
43
42
|
<div className="absolute left-1/2 top-24 flex -translate-x-1/2 flex-col items-center text-center">
|
|
44
|
-
<
|
|
43
|
+
<motion.img
|
|
45
44
|
src="/horse.svg"
|
|
46
45
|
alt="Hack Western Logo"
|
|
47
46
|
width={64}
|
package/src/index.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -10,11 +10,31 @@ export interface SectionCoordinates {
|
|
|
10
10
|
height: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
/**
|
|
14
|
+
* CanvasSection is now a generic string type.
|
|
15
|
+
* Apps define their own section IDs as strings.
|
|
16
|
+
*/
|
|
17
|
+
export type CanvasSection = string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for a single navigation item.
|
|
21
|
+
* Combines section identity, display info, and coordinates.
|
|
22
|
+
*/
|
|
23
|
+
export interface NavItem {
|
|
24
|
+
/** Unique identifier for this section */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Display label shown in the navbar */
|
|
27
|
+
label: string;
|
|
28
|
+
/** Lucide icon name or a custom icon component */
|
|
29
|
+
icon: string | React.ComponentType<{ className?: string }>;
|
|
30
|
+
/** X coordinate on the canvas */
|
|
31
|
+
x: number;
|
|
32
|
+
/** Y coordinate on the canvas */
|
|
33
|
+
y: number;
|
|
34
|
+
/** Width of the section viewport */
|
|
35
|
+
width: number;
|
|
36
|
+
/** Height of the section viewport */
|
|
37
|
+
height: number;
|
|
38
|
+
/** If true, clicking this section triggers the reset/home behavior */
|
|
39
|
+
isHome?: boolean;
|
|
20
40
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../../src/components/canvas/reset.tsx"],"names":[],"mappings":"AAEA,QAAA,MAAM,KAAK,GAAI,0BAEZ;IACD,mBAAmB,EAAE,MAAM,IAAI,CAAC;CACjC,4CAYA,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import Image from "next/image";
|
|
3
|
-
const Reset = ({ onResetViewAndItems, }) => {
|
|
4
|
-
return (_jsx("div", { className: "absolute bottom-4 left-4 z-[1000] flex cursor-[url('/customcursor.svg'),auto] select-none", children: _jsx("button", { className: "rounded bg-gray-700 p-1.5 font-mono text-xs text-white shadow-md transition-colors hover:bg-gray-600 md:text-sm", onClick: onResetViewAndItems, onPointerDown: (e) => e.stopPropagation(), children: _jsx(Image, { src: "/images/reset.svg", alt: "Reset", width: 18, height: 18 }) }) }));
|
|
5
|
-
};
|
|
6
|
-
export default Reset;
|
|
7
|
-
//# sourceMappingURL=reset.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reset.js","sourceRoot":"","sources":["../../../src/components/canvas/reset.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,KAAK,GAAG,CAAC,EACb,mBAAmB,GAGpB,EAAE,EAAE;IACH,OAAO,CACL,cAAK,SAAS,EAAC,2FAA2F,YACxG,iBACE,SAAS,EAAC,iHAAiH,EAC3H,OAAO,EAAE,mBAAmB,EAC5B,aAAa,EAAE,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,YAE7D,KAAC,KAAK,IAAC,GAAG,EAAC,mBAAmB,EAAC,GAAG,EAAC,OAAO,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAI,GAC7D,GACL,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import Image from "next/image";
|
|
2
|
-
|
|
3
|
-
const Reset = ({
|
|
4
|
-
onResetViewAndItems,
|
|
5
|
-
}: {
|
|
6
|
-
onResetViewAndItems: () => void;
|
|
7
|
-
}) => {
|
|
8
|
-
return (
|
|
9
|
-
<div className="absolute bottom-4 left-4 z-[1000] flex cursor-[url('/customcursor.svg'),auto] select-none">
|
|
10
|
-
<button
|
|
11
|
-
className="rounded bg-gray-700 p-1.5 font-mono text-xs text-white shadow-md transition-colors hover:bg-gray-600 md:text-sm"
|
|
12
|
-
onClick={onResetViewAndItems}
|
|
13
|
-
onPointerDown={(e: React.PointerEvent) => e.stopPropagation()}
|
|
14
|
-
>
|
|
15
|
-
<Image src="/images/reset.svg" alt="Reset" width={18} height={18} />
|
|
16
|
-
</button>
|
|
17
|
-
</div>
|
|
18
|
-
);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default Reset;
|