taskgenius_taskgenius-plugin/src/components/features/onboarding/IntroTyping.ts
Quorafind 3fcf2f9705 feat(onboarding): add fluent/legacy mode selection flow
Expand onboarding wizard with new interactive steps to guide users
through UI architecture selection:

- Add animated typing intro component with AI-style streaming effect
- Add UI mode selection step (Fluent vs Legacy interface styles)
- Add Fluent placement configuration (Sideleaves vs Inline layout)
- Refactor onboarding flow from 5 to 7 steps with conditional branching
- Apply selected architecture preferences to plugin settings
- Add visual mode classes and enhanced styling support

The new flow allows users to customize their Task Genius experience
during initial setup while maintaining backward compatibility with
existing configurations.
2025-09-30 16:09:25 +08:00

112 lines
2.9 KiB
TypeScript

import { t } from "@/translations/helper";
export class IntroTyping {
private timers: number[] = [];
cleanup() {
this.timers.forEach((id) => window.clearTimeout(id));
this.timers = [];
}
render(container: HTMLElement) {
container.empty();
const wrap = container.createDiv({cls: "intro-typing"});
const line1 = wrap.createEl("h1", {cls: "intro-line intro-line-1"});
const line2 = wrap.createEl("h2", {cls: "intro-line intro-line-2"});
const line3 = wrap.createEl("p", {cls: "intro-line intro-line-3"});
const line4 = wrap.createEl("p", {cls: "intro-line intro-line-4"});
const seq = [
{
el: line1,
text: t("Hi,"),
speed: 35
},
{
el: line2,
text: t("Thank you for using Task Genius"),
speed: 25
},
{
el: line3,
text: t("In the following steps, you will gradually set up Task Genius to get a more suitable environment for you"),
speed: 20
},
{
el: line4,
text: t("In the current version, Task Genius provides a brand new visual and interactive experience: Fluent; while also providing the option to return to the previous interface. Which one do you prefer?"),
speed: 20
},
];
this.aiStreamSequence(seq);
}
/**
* AI-style streaming text effect with smooth character fade-in
*/
private aiStreamSequence(seq: { el: HTMLElement; text: string; speed: number }[]) {
const streamLine = (idx: number) => {
if (idx >= seq.length) return;
const {el, text, speed} = seq[idx];
// Clear and prepare element
el.empty();
el.addClass("is-streaming");
// Create individual character spans for smooth animation
const chars: HTMLElement[] = [];
for (let i = 0; i < text.length; i++) {
const char = text[i];
const span = el.createSpan({
cls: "intro-char",
text: char,
});
// Special handling for spaces to preserve layout
if (char === " ") {
span.addClass("intro-char-space");
}
chars.push(span);
}
// Create cursor element that will follow the characters
const cursor = el.createSpan({
cls: "intro-cursor",
text: "▊",
});
// Animate characters with AI-style streaming effect
let charIndex = 0;
const animateChar = () => {
if (charIndex < chars.length) {
const char = chars[charIndex];
// Add small random variation for more natural feel
const jitter = Math.random() * speed * 0.3;
char.addClass("intro-char-visible");
// Move cursor after the just-revealed character
char.after(cursor);
charIndex++;
const id = window.setTimeout(animateChar, speed + jitter);
this.timers.push(id);
} else {
// Line complete, remove cursor and move to next
cursor.remove();
el.removeClass("is-streaming");
el.addClass("stream-complete");
// Small delay before next line
const id = window.setTimeout(() => streamLine(idx + 1), 300);
this.timers.push(id);
}
};
// Start animation
animateChar();
};
streamLine(0);
}
}