@togo-framework/ui 0.1.6 → 0.1.7
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/dist/index.d.ts +4 -2
- package/dist/index.js +128 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/togo-brand-ui.svg +38 -0
package/dist/index.d.ts
CHANGED
|
@@ -4104,10 +4104,12 @@ interface TypingTerminalProps {
|
|
|
4104
4104
|
typeMs?: number;
|
|
4105
4105
|
/** ms between streamed output lines. */
|
|
4106
4106
|
lineMs?: number;
|
|
4107
|
-
/** Loop the playback
|
|
4107
|
+
/** Loop the playback. Default false — plays once, then offers Replay. */
|
|
4108
4108
|
loop?: boolean;
|
|
4109
|
+
/** Fixed body height (px). The window never grows/jumps while typing. */
|
|
4110
|
+
height?: number;
|
|
4109
4111
|
}
|
|
4110
|
-
declare function TypingTerminal({ steps, endSlot, title, className, typeMs, lineMs, loop }: TypingTerminalProps): React$1.JSX.Element;
|
|
4112
|
+
declare function TypingTerminal({ steps, endSlot, title, className, typeMs, lineMs, loop, height }: TypingTerminalProps): React$1.JSX.Element;
|
|
4111
4113
|
declare namespace TypingTerminal {
|
|
4112
4114
|
var displayName: string;
|
|
4113
4115
|
}
|
package/dist/index.js
CHANGED
|
@@ -16269,6 +16269,7 @@ CommandPalette.displayName = "CommandPalette";
|
|
|
16269
16269
|
|
|
16270
16270
|
// src/components/marketing/Terminal.tsx
|
|
16271
16271
|
import * as React32 from "react";
|
|
16272
|
+
import { RotateCcw as RotateCcw3 } from "lucide-react";
|
|
16272
16273
|
import { jsx as jsx101, jsxs as jsxs89 } from "react/jsx-runtime";
|
|
16273
16274
|
function fullFrame(steps) {
|
|
16274
16275
|
const lines = [];
|
|
@@ -16284,16 +16285,25 @@ function fullFrame(steps) {
|
|
|
16284
16285
|
return { lines, showEnd: true };
|
|
16285
16286
|
}
|
|
16286
16287
|
var keepStaticFrame = () => typeof window !== "undefined" && (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches || navigator?.webdriver === true);
|
|
16287
|
-
function TypingTerminal({ steps, endSlot, title = "~/myapp \u2014 togo", className, typeMs = 26, lineMs = 110, loop =
|
|
16288
|
+
function TypingTerminal({ steps, endSlot, title = "~/myapp \u2014 togo", className, typeMs = 26, lineMs = 110, loop = false, height = 360 }) {
|
|
16288
16289
|
const [frame, setFrame] = React32.useState(() => fullFrame(steps));
|
|
16290
|
+
const [done, setDone] = React32.useState(false);
|
|
16291
|
+
const [runId, setRunId] = React32.useState(0);
|
|
16289
16292
|
const scrollRef = React32.useRef(null);
|
|
16290
16293
|
React32.useEffect(() => {
|
|
16291
|
-
if (keepStaticFrame())
|
|
16294
|
+
if (keepStaticFrame()) {
|
|
16295
|
+
setDone(true);
|
|
16296
|
+
return;
|
|
16297
|
+
}
|
|
16292
16298
|
let alive = true;
|
|
16293
16299
|
const timers = [];
|
|
16294
16300
|
const wait = (ms) => new Promise((res) => timers.push(setTimeout(res, ms)));
|
|
16301
|
+
const toBottom = () => {
|
|
16302
|
+
if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
16303
|
+
};
|
|
16295
16304
|
async function run() {
|
|
16296
|
-
|
|
16305
|
+
setDone(false);
|
|
16306
|
+
do {
|
|
16297
16307
|
const lines = [];
|
|
16298
16308
|
setFrame({ lines: [], showEnd: false });
|
|
16299
16309
|
for (let i = 0; i < steps.length && alive; i++) {
|
|
@@ -16308,6 +16318,7 @@ function TypingTerminal({ steps, endSlot, title = "~/myapp \u2014 togo", classNa
|
|
|
16308
16318
|
] }, `c${i}`)],
|
|
16309
16319
|
showEnd: false
|
|
16310
16320
|
});
|
|
16321
|
+
toBottom();
|
|
16311
16322
|
await wait(typeMs);
|
|
16312
16323
|
}
|
|
16313
16324
|
lines.push(/* @__PURE__ */ jsxs89("div", { className: "whitespace-pre-wrap break-words", children: [
|
|
@@ -16318,31 +16329,47 @@ function TypingTerminal({ steps, endSlot, title = "~/myapp \u2014 togo", classNa
|
|
|
16318
16329
|
for (let j = 0; j < (s.out?.length || 0) && alive; j++) {
|
|
16319
16330
|
lines.push(/* @__PURE__ */ jsx101("div", { className: "whitespace-pre-wrap break-words text-muted-foreground", children: s.out[j] }, `o${i}-${j}`));
|
|
16320
16331
|
setFrame({ lines: [...lines], showEnd: false });
|
|
16321
|
-
|
|
16332
|
+
toBottom();
|
|
16322
16333
|
await wait(lineMs);
|
|
16323
16334
|
}
|
|
16324
16335
|
}
|
|
16325
16336
|
if (!alive) return;
|
|
16326
16337
|
setFrame({ lines: [...lines], showEnd: true });
|
|
16327
|
-
|
|
16328
|
-
if (!loop)
|
|
16338
|
+
toBottom();
|
|
16339
|
+
if (!loop) {
|
|
16340
|
+
setDone(true);
|
|
16341
|
+
return;
|
|
16342
|
+
}
|
|
16329
16343
|
await wait(4200);
|
|
16330
|
-
}
|
|
16344
|
+
} while (alive);
|
|
16331
16345
|
}
|
|
16332
16346
|
run();
|
|
16333
16347
|
return () => {
|
|
16334
16348
|
alive = false;
|
|
16335
16349
|
timers.forEach(clearTimeout);
|
|
16336
16350
|
};
|
|
16337
|
-
}, [steps, typeMs, lineMs, loop]);
|
|
16351
|
+
}, [steps, typeMs, lineMs, loop, runId]);
|
|
16338
16352
|
return /* @__PURE__ */ jsxs89("div", { className: cn("rounded-2xl border border-border overflow-hidden bg-[#080b0f] shadow-2xl", className), children: [
|
|
16339
16353
|
/* @__PURE__ */ jsxs89("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-border", children: [
|
|
16340
16354
|
/* @__PURE__ */ jsx101("span", { className: "w-3 h-3 rounded-full bg-[#ff5f57]" }),
|
|
16341
16355
|
/* @__PURE__ */ jsx101("span", { className: "w-3 h-3 rounded-full bg-[#febc2e]" }),
|
|
16342
16356
|
/* @__PURE__ */ jsx101("span", { className: "w-3 h-3 rounded-full bg-[#28c840]" }),
|
|
16343
|
-
/* @__PURE__ */ jsx101("span", { className: "ms-2 font-mono text-xs text-muted-foreground", children: title })
|
|
16357
|
+
/* @__PURE__ */ jsx101("span", { className: "ms-2 font-mono text-xs text-muted-foreground", children: title }),
|
|
16358
|
+
done && !loop && /* @__PURE__ */ jsxs89(
|
|
16359
|
+
"button",
|
|
16360
|
+
{
|
|
16361
|
+
type: "button",
|
|
16362
|
+
onClick: () => setRunId((n) => n + 1),
|
|
16363
|
+
className: "ms-auto inline-flex items-center gap-1.5 rounded-md border border-white/12 bg-white/[0.04] px-2.5 py-1 font-mono text-[11px] text-muted-foreground hover:text-foreground hover:bg-white/[0.08] transition-colors",
|
|
16364
|
+
"aria-label": "Replay the terminal demo",
|
|
16365
|
+
children: [
|
|
16366
|
+
/* @__PURE__ */ jsx101(RotateCcw3, { size: 12 }),
|
|
16367
|
+
" Replay"
|
|
16368
|
+
]
|
|
16369
|
+
}
|
|
16370
|
+
)
|
|
16344
16371
|
] }),
|
|
16345
|
-
/* @__PURE__ */ jsxs89("div", { ref: scrollRef, className: "p-5 font-mono text-[12.5px] sm:text-[13px] leading-[1.9]
|
|
16372
|
+
/* @__PURE__ */ jsxs89("div", { ref: scrollRef, className: "p-5 font-mono text-[12.5px] sm:text-[13px] leading-[1.9] overflow-auto", style: { height }, children: [
|
|
16346
16373
|
frame.lines,
|
|
16347
16374
|
frame.showEnd && endSlot ? /* @__PURE__ */ jsx101("div", { className: "mt-4 pt-4 border-t border-white/10", children: endSlot }) : null
|
|
16348
16375
|
] })
|
|
@@ -16351,26 +16378,103 @@ function TypingTerminal({ steps, endSlot, title = "~/myapp \u2014 togo", classNa
|
|
|
16351
16378
|
TypingTerminal.displayName = "TypingTerminal";
|
|
16352
16379
|
|
|
16353
16380
|
// src/components/marketing/MascotMark.tsx
|
|
16381
|
+
import * as React33 from "react";
|
|
16354
16382
|
import { jsx as jsx102, jsxs as jsxs90 } from "react/jsx-runtime";
|
|
16383
|
+
var EYES = [
|
|
16384
|
+
{ x: 0.405, y: 0.45 },
|
|
16385
|
+
{ x: 0.595, y: 0.45 }
|
|
16386
|
+
];
|
|
16387
|
+
var EYE_W = 0.085;
|
|
16388
|
+
var PUPIL_RATIO = 0.52;
|
|
16389
|
+
var MAX_OFF = (1 - PUPIL_RATIO) / 2 * 100;
|
|
16355
16390
|
var KEYFRAMES = `
|
|
16356
16391
|
@keyframes tgMascotFloat { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-12px)} }
|
|
16357
|
-
@keyframes tgMascotChar {
|
|
16358
|
-
0%,100% { transform: rotate(0deg) scaleX(1) scaleY(1); }
|
|
16359
|
-
44% { transform: rotate(0deg) scaleX(1) scaleY(1); }
|
|
16360
|
-
48% { transform: rotate(-3deg) scaleX(1.04) scaleY(0.92); } /* squash nod */
|
|
16361
|
-
52% { transform: rotate(-3deg) scaleX(0.98) scaleY(1.05); } /* stretch */
|
|
16362
|
-
60% { transform: rotate(3deg) scaleX(1) scaleY(1); }
|
|
16363
|
-
72% { transform: rotate(0deg) scaleX(1) scaleY(1); }
|
|
16364
|
-
}
|
|
16365
16392
|
.tg-mascot { will-change: transform; animation: tgMascotFloat 6s ease-in-out infinite; }
|
|
16366
|
-
|
|
16367
|
-
@media (prefers-reduced-motion: reduce) {
|
|
16368
|
-
.tg-mascot, .tg-mascot > img { animation: none !important; }
|
|
16369
|
-
}`;
|
|
16393
|
+
@media (prefers-reduced-motion: reduce) { .tg-mascot { animation: none !important; } }`;
|
|
16370
16394
|
function MascotMark({ src = "/togo-mark.svg", alt = "ToGO", className }) {
|
|
16371
|
-
|
|
16395
|
+
const ref = React33.useRef(null);
|
|
16396
|
+
const [active, setActive] = React33.useState(false);
|
|
16397
|
+
const [look, setLook] = React33.useState({ dx: 0, dy: 0 });
|
|
16398
|
+
React33.useEffect(() => {
|
|
16399
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
16400
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
16401
|
+
if (!window.matchMedia("(hover: hover) and (pointer: fine)").matches) return;
|
|
16402
|
+
setActive(true);
|
|
16403
|
+
let raf = 0;
|
|
16404
|
+
const onMove = (e) => {
|
|
16405
|
+
const el = ref.current;
|
|
16406
|
+
if (!el) return;
|
|
16407
|
+
const r = el.getBoundingClientRect();
|
|
16408
|
+
const cx = r.left + r.width / 2;
|
|
16409
|
+
const cy = r.top + r.height * 0.45;
|
|
16410
|
+
const dx = Math.max(-1, Math.min(1, (e.clientX - cx) / (r.width * 0.85)));
|
|
16411
|
+
const dy = Math.max(-1, Math.min(1, (e.clientY - cy) / (r.height * 0.85)));
|
|
16412
|
+
cancelAnimationFrame(raf);
|
|
16413
|
+
raf = requestAnimationFrame(() => setLook({ dx, dy }));
|
|
16414
|
+
};
|
|
16415
|
+
const recenter = () => setLook({ dx: 0, dy: 0 });
|
|
16416
|
+
window.addEventListener("pointermove", onMove, { passive: true });
|
|
16417
|
+
window.addEventListener("pointerleave", recenter);
|
|
16418
|
+
document.addEventListener("mouseleave", recenter);
|
|
16419
|
+
return () => {
|
|
16420
|
+
window.removeEventListener("pointermove", onMove);
|
|
16421
|
+
window.removeEventListener("pointerleave", recenter);
|
|
16422
|
+
document.removeEventListener("mouseleave", recenter);
|
|
16423
|
+
cancelAnimationFrame(raf);
|
|
16424
|
+
};
|
|
16425
|
+
}, []);
|
|
16426
|
+
const tilt = active ? look.dx * 4 : 0;
|
|
16427
|
+
return /* @__PURE__ */ jsxs90("div", { ref, className: cn("tg-mascot", className), style: { position: "relative", display: "inline-block" }, children: [
|
|
16372
16428
|
/* @__PURE__ */ jsx102("style", { children: KEYFRAMES }),
|
|
16373
|
-
/* @__PURE__ */
|
|
16429
|
+
/* @__PURE__ */ jsxs90(
|
|
16430
|
+
"div",
|
|
16431
|
+
{
|
|
16432
|
+
style: {
|
|
16433
|
+
position: "relative",
|
|
16434
|
+
transform: active ? `rotate(${tilt}deg)` : void 0,
|
|
16435
|
+
transformOrigin: "50% 75%",
|
|
16436
|
+
transition: "transform .25s ease-out"
|
|
16437
|
+
},
|
|
16438
|
+
children: [
|
|
16439
|
+
/* @__PURE__ */ jsx102("img", { src, alt, draggable: false, style: { display: "block", width: "100%", height: "100%" } }),
|
|
16440
|
+
active && EYES.map((eye, i) => /* @__PURE__ */ jsx102(
|
|
16441
|
+
"span",
|
|
16442
|
+
{
|
|
16443
|
+
"aria-hidden": "true",
|
|
16444
|
+
style: {
|
|
16445
|
+
position: "absolute",
|
|
16446
|
+
left: `${eye.x * 100}%`,
|
|
16447
|
+
top: `${eye.y * 100}%`,
|
|
16448
|
+
width: `${EYE_W * 100}%`,
|
|
16449
|
+
aspectRatio: "1",
|
|
16450
|
+
transform: "translate(-50%,-50%)",
|
|
16451
|
+
borderRadius: "9999px",
|
|
16452
|
+
background: "rgba(255,255,255,.94)",
|
|
16453
|
+
boxShadow: "inset 0 2px 4px rgba(8,16,40,.28)"
|
|
16454
|
+
},
|
|
16455
|
+
children: /* @__PURE__ */ jsx102(
|
|
16456
|
+
"span",
|
|
16457
|
+
{
|
|
16458
|
+
style: {
|
|
16459
|
+
position: "absolute",
|
|
16460
|
+
left: `${50 + look.dx * MAX_OFF}%`,
|
|
16461
|
+
top: `${50 + look.dy * MAX_OFF}%`,
|
|
16462
|
+
width: `${PUPIL_RATIO * 100}%`,
|
|
16463
|
+
aspectRatio: "1",
|
|
16464
|
+
transform: "translate(-50%,-50%)",
|
|
16465
|
+
borderRadius: "9999px",
|
|
16466
|
+
background: "#0a1733",
|
|
16467
|
+
boxShadow: "inset 1.5px -1.5px 2px rgba(255,255,255,.35)",
|
|
16468
|
+
transition: "left .12s ease-out, top .12s ease-out"
|
|
16469
|
+
}
|
|
16470
|
+
}
|
|
16471
|
+
)
|
|
16472
|
+
},
|
|
16473
|
+
i
|
|
16474
|
+
))
|
|
16475
|
+
]
|
|
16476
|
+
}
|
|
16477
|
+
)
|
|
16374
16478
|
] });
|
|
16375
16479
|
}
|
|
16376
16480
|
MascotMark.displayName = "MascotMark";
|