Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ a {
text-decoration-color: hsl(var(--link-hue), 75%, 50%);
}

.bg-link-hue {
background-color: hsl(var(--link-hue), 75%, 50%);
}

/*
a:hover {
text-decoration-color: gold;
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/meme-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export function MemeSelector(props: MemeSelectorProps): JSX.Element {
return (
<div
ref={setModal}
class="fixed bottom-20 left-4 right-4 sm:left-1/2 sm:right-auto sm:transform sm:-translate-x-1/2 sm:w-[800px] sm:max-w-[90vw] max-h-[80vh] flex flex-col bg-black/80 border border-white/20 rounded-lg shadow-2xl pointer-events-auto backdrop-blur-lg z-[100]"
class="fixed bottom-20 left-1/2 -translate-x-1/2 w-[90vw] sm:w-[800px] sm:max-w-[90vw] max-h-[80vh] flex flex-col bg-black/80 border border-white/20 rounded-lg shadow-2xl pointer-events-auto backdrop-blur-lg z-[100]"
>
{/* Header with tabs */}
<div class="flex items-center justify-between border-b border-white/20 p-2 sm:p-3 shrink-0">
Expand Down
140 changes: 140 additions & 0 deletions app/src/components/tutorial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import solid from "@kixelated/signals/solid";
import { onCleanup, onMount, Show } from "solid-js";
import type { JSX } from "solid-js/jsx-runtime";
import Settings from "../settings";

export function Tutorial(): JSX.Element {
const step = solid(Settings.tutorial.step);

const steps = [
{
title: "Share Stuff",
description:
"Enable your microphone or webcam down here. Or share your screen, just make sure you close that tab first. You know the one.",
arrow: "bottom-left",
styles: { bottom: "5rem", left: "1rem" },
},
{
title: "Talk Stuff",
description: "Spam unfunny messages down here. There's also a dank meme selector.",
arrow: "bottom",
styles: { bottom: "5rem", left: "50%", transform: "translateX(-50%)" },
},
{
title: "Advanced Stuff",
description: "I guess.",
arrow: "bottom-right",
styles: { bottom: "5rem", right: "1rem" },
},
{
title: "Other Stuff",
description: "Favorite the room if you want to hang later. Or leave unannounced, cold.",
arrow: "top-right",
styles: { top: "5rem", right: "1rem" },
},
];

const nextStep = () => {
Settings.tutorial.step.set(step() + 1);
};

const skipTutorial = () => {
Settings.tutorial.step.set(steps.length);
};

onMount(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape" && step() < steps.length) {
skipTutorial();
}
};
document.addEventListener("keydown", handleEscape);
onCleanup(() => document.removeEventListener("keydown", handleEscape));
});

return (
<Show when={step() < steps.length}>
{/* Backdrop */}
<button
type="button"
class="fixed inset-0 backdrop-blur-sm bg-black/50 z-[1000] pointer-events-auto border-none p-0 m-0"
onClick={skipTutorial}
aria-label="Close tutorial"
/>

{/* Tutorial tooltip */}
<div
class="fixed z-[1001] bg-black/70 rounded-xl border border-white/20 shadow-2xl p-5 max-w-sm pointer-events-auto"
style={steps[step()].styles}
>
<div class="flex items-start justify-between mb-2">
<h3 class="text-xl font-semibold text-white underline decoration-link-hue underline-offset-2">
{steps[step()].title}
</h3>
<button
type="button"
onClick={skipTutorial}
class="text-white/60 hover:text-white transition-colors -mt-1"
aria-label="Skip tutorial"
>
<span class="icon-[mdi--close] text-xl" />
</button>
</div>

<p class="text-white/80 mb-4 text-sm leading-relaxed">{steps[step()].description}</p>

<div class="flex items-center justify-between">
<div class="flex gap-1.5">
{steps.map((_, index) => (
<div
class="w-2 h-2 rounded-full transition-all duration-200"
style={{
"background-color":
index === step() ? "hsl(var(--link-hue) 60% 60%)" : "rgba(255, 255, 255, 0.3)",
}}
/>
))}
</div>

<div class="flex gap-2">
<button
type="button"
onClick={skipTutorial}
class="px-3 py-1.5 text-sm text-white/60 hover:text-white transition-colors rounded-md hover:bg-white/5 cursor-pointer"
>
Skip
</button>
<button
type="button"
onClick={nextStep}
class="px-4 py-1.5 text-sm bg-white/10 hover:bg-white/20 rounded-md transition-colors text-white font-medium cursor-pointer"
classList={{
"bg-link-hue": step() === steps.length - 1,
}}
>
{step() < steps.length - 1 ? "Next" : "Got it!"}
</button>
</div>
</div>

{/* Arrow */}
<div
class="absolute w-2 h-2 bg-black/70 border-white/20 transform rotate-45"
classList={{
"border-t border-l": steps[step()].arrow.startsWith("top"),
"border-b border-r": steps[step()].arrow.startsWith("bottom"),
}}
style={{
left: steps[step()].arrow.endsWith("left")
? "2rem"
: steps[step()].arrow.endsWith("right")
? "calc(100% - 2rem)"
: "50%",
bottom: steps[step()].arrow.startsWith("bottom") ? "-4px" : undefined,
top: steps[step()].arrow.startsWith("top") ? "-4px" : undefined,
}}
/>
</div>
</Show>
);
}
Loading
Loading