Skip to content

Commit

Permalink
Merge pull request #75 from zamm-dev/fix-animations
Browse files Browse the repository at this point in the history
 Fix InfoBox reveal for populated chat conversations
  • Loading branch information
amosjyng authored Apr 13, 2024
2 parents 3877239 + 66eb431 commit a49582d
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 91 deletions.
15 changes: 10 additions & 5 deletions src-svelte/src/lib/InfoBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,10 @@
revealCutoffFraction,
equivalentYProgress,
);
const delayFraction = adjustedYProgress * theoreticalTotalKickoffFraction;
const delayFraction = Math.max(
0,
adjustedYProgress * theoreticalTotalKickoffFraction,
);
return new PrimitiveTimingFraction({
delayFraction,
durationFraction: perElementRevealFraction,
Expand Down Expand Up @@ -455,15 +458,16 @@
let revealAnimations = getNodeAnimations(node);
const config = { childList: true, subtree: true };
const mutationCallback: MutationCallback = () => {
const recalculateReveals = () => {
revealAnimations = getNodeAnimations(node);
// hide all new nodes immediately
revealAnimations.forEach((anim) => {
anim.tickForGlobalTime(0);
});
};
const observer = new MutationObserver(mutationCallback);
observer.observe(node, config);
const mutationObserver = new MutationObserver(recalculateReveals);
mutationObserver.observe(node, config);
node.addEventListener("info-box-update", recalculateReveals);
return {
delay: timing.infoBox.delayMs(),
Expand All @@ -484,7 +488,8 @@
}
if (tGlobalFraction === 1) {
observer.disconnect();
mutationObserver.disconnect();
node.removeEventListener("info-box-update", recalculateReveals);
}
},
};
Expand Down
4 changes: 2 additions & 2 deletions src-svelte/src/lib/SubInfoBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
const subinfoboxId = getComponentId("subinfobox");
</script>

<section class="sub-info-box" aria-labelledby={subinfoboxId}>
<section class="sub-info-box composite-reveal" aria-labelledby={subinfoboxId}>
<div class="subheading">
<h3 id={subinfoboxId}>{subheading}</h3>
</div>
<div class="content">
<div class="content composite-reveal">
<slot />
</div>
</section>
Expand Down
2 changes: 1 addition & 1 deletion src-svelte/src/lib/__mocks__/MockAppLayout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import Snackbar from "$lib/snackbar/Snackbar.svelte";
</script>

<div class="storybook-wrapper">
<div id="mock-app-layout" class="storybook-wrapper">
<AnimationControl>
<slot />
<Snackbar />
Expand Down
2 changes: 1 addition & 1 deletion src-svelte/src/lib/__mocks__/MockFullPageLayout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import Snackbar from "$lib/snackbar/Snackbar.svelte";
</script>

<div class="storybook-wrapper full-height">
<div id="mock-full-page-layout" class="storybook-wrapper full-height">
<AnimationControl>
<slot />
<Snackbar />
Expand Down
18 changes: 13 additions & 5 deletions src-svelte/src/lib/__mocks__/MockPageTransitions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@
animationSpeed.set(0.1);
</script>

<MockFullPageLayout>
<PageTransition currentRoute="/storybook-demo">
<slot />
</PageTransition>
</MockFullPageLayout>
<div id="mock-transitions">
<MockFullPageLayout>
<PageTransition currentRoute="/storybook-demo">
<slot />
</PageTransition>
</MockFullPageLayout>
</div>

<style>
#mock-transitions {
margin: -1rem;
}
</style>
7 changes: 4 additions & 3 deletions src-svelte/src/routes/AnimationControl.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@
</script>

<div
class="container full-height"
id="animation-control"
class="full-height"
class:animations-disabled={!$animationsOn}
{style}
>
<slot />
</div>

<style>
.container {
#animation-control {
height: 100%;
position: relative;
}
.container.animations-disabled :global(*) {
#animation-control.animations-disabled :global(*) {
animation-play-state: paused !important;
transition: none !important;
}
Expand Down
12 changes: 9 additions & 3 deletions src-svelte/src/routes/AnimationControl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ describe("AnimationControl", () => {
test("will enable animations by default", async () => {
render(AnimationControl, {});

const animationControl = document.querySelector(".container") as Element;
const animationControl = document.getElementById(
"animation-control",
) as Element;
expect(animationControl.classList).not.toContainEqual(
"animations-disabled",
);
Expand All @@ -26,7 +28,9 @@ describe("AnimationControl", () => {
animationsOn.set(false);
render(AnimationControl, {});

const animationControl = document.querySelector(".container") as Element;
const animationControl = document.getElementById(
"animation-control",
) as Element;
expect(animationControl.classList).toContainEqual("animations-disabled");
expect(animationControl.getAttribute("style")).toEqual(
"--base-animation-speed: 1; --standard-duration: 0.00ms;",
Expand All @@ -37,7 +41,9 @@ describe("AnimationControl", () => {
animationSpeed.set(0.9);
render(AnimationControl, {});

const animationControl = document.querySelector(".container") as Element;
const animationControl = document.getElementById(
"animation-control",
) as Element;
expect(animationControl.classList).not.toContainEqual(
"animations-disabled",
);
Expand Down
6 changes: 3 additions & 3 deletions src-svelte/src/routes/api-calls/[slug]/ApiCallDisplay.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

<InfoBox title="API Call">
{#if apiCall}
<table>
<table class="composite-reveal">
<tr>
<td>ID</td>
<td>{apiCall?.id ?? "Unknown"}</td>
Expand Down Expand Up @@ -74,9 +74,9 @@
</table>

<SubInfoBox subheading="Prompt">
<div class="prompt">
<div class="prompt composite-reveal">
{#each apiCall?.request.prompt.messages ?? [] as message}
<div class={"message " + message.role.toLowerCase()}>
<div class={"message atomic-reveal " + message.role.toLowerCase()}>
<span class="role">{message.role}</span>
<pre>{message.text}</pre>
</div>
Expand Down
56 changes: 56 additions & 0 deletions src-svelte/src/routes/chat/Chat.mock-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { ChatMessage } from "$lib/bindings";

export const shortConversation: ChatMessage[] = [
{
role: "System",
text: "You are ZAMM, a chat program. Respond in first person.",
},
{
role: "Human",
text: "Hello, does this work?",
},
];

export const conversation: ChatMessage[] = [
{
role: "System",
text: "You are ZAMM, a chat program. Respond in first person.",
},
{
role: "Human",
text: "Hello, does this work?",
},
{
role: "AI",
text:
"Hello! I'm ZAMM, a chat program. I'm here to assist you. " +
"What can I help you with today?",
},
{
role: "Human",
text: "Tell me something really funny, like really funny. Make me laugh hard.",
},
{
role: "AI",
text:
"Sure, here's a light-hearted joke for you:\n\n" +
"Why don't scientists trust atoms?\n\n" +
"Because they make up everything!",
},
{
role: "Human",
text:
"This is some Python code:\n\n" +
"```python\n" +
"def hello_world():\n" +
" print('Hello, world!')\n" +
"```\n\n" +
"Convert it to Rust",
},
{
role: "AI",
text:
"Here's how the Python code you provided would look in Rust:\n\n" +
'```rust\nfn main() {\n println!("Hello, world!");\n}\n```',
},
];
36 changes: 36 additions & 0 deletions src-svelte/src/routes/chat/Chat.reveal.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import ChatComponent from "./Chat.svelte";
import SvelteStoresDecorator from "$lib/__mocks__/stores";
import MockPageTransitions from "$lib/__mocks__/MockPageTransitions.svelte";
import TauriInvokeDecorator from "$lib/__mocks__/invoke";
import type { StoryFn, StoryObj } from "@storybook/svelte";
import { conversation } from "./Chat.mock-data";

export default {
component: ChatComponent,
title: "Screens/Chat/Conversation",
argTypes: {},
decorators: [
SvelteStoresDecorator,
TauriInvokeDecorator,
(story: StoryFn) => {
return {
Component: MockPageTransitions,
slot: story,
};
},
],
};

const Template = ({ ...args }) => ({
Component: ChatComponent,
props: args,
});

export const FullPage: StoryObj = Template.bind({}) as any;

export const FullPageConversation: StoryObj = Template.bind({}) as any;
FullPageConversation.parameters = {
stores: {
conversation,
},
};
68 changes: 1 addition & 67 deletions src-svelte/src/routes/chat/Chat.stories.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import ChatComponent from "./Chat.svelte";
import MockFullPageLayout from "$lib/__mocks__/MockFullPageLayout.svelte";
import SvelteStoresDecorator from "$lib/__mocks__/stores";
import MockPageTransitions from "$lib/__mocks__/MockPageTransitions.svelte";
import TauriInvokeDecorator from "$lib/__mocks__/invoke";
import type { StoryFn, StoryObj } from "@storybook/svelte";
import type { ChatMessage } from "$lib/bindings";
import { conversation, shortConversation } from "./Chat.mock-data";

export default {
component: ChatComponent,
Expand Down Expand Up @@ -34,61 +33,6 @@ Empty.parameters = {
},
};

const shortConversation: ChatMessage[] = [
{
role: "System",
text: "You are ZAMM, a chat program. Respond in first person.",
},
{
role: "Human",
text: "Hello, does this work?",
},
];

const conversation: ChatMessage[] = [
{
role: "System",
text: "You are ZAMM, a chat program. Respond in first person.",
},
{
role: "Human",
text: "Hello, does this work?",
},
{
role: "AI",
text:
"Hello! I'm ZAMM, a chat program. I'm here to assist you. " +
"What can I help you with today?",
},
{
role: "Human",
text: "Tell me something really funny, like really funny. Make me laugh hard.",
},
{
role: "AI",
text:
"Sure, here's a light-hearted joke for you:\n\n" +
"Why don't scientists trust atoms?\n\n" +
"Because they make up everything!",
},
{
role: "Human",
text:
"This is some Python code:\n\n" +
"```python\n" +
"def hello_world():\n" +
" print('Hello, world!')\n" +
"```\n\n" +
"Convert it to Rust",
},
{
role: "AI",
text:
"Here's how the Python code you provided would look in Rust:\n\n" +
'```rust\nfn main() {\n println!("Hello, world!");\n}\n```',
},
];

export const NotEmpty: StoryObj = Template.bind({}) as any;
NotEmpty.parameters = {
stores: {
Expand Down Expand Up @@ -195,13 +139,3 @@ TypingIndicatorStatic.parameters = {
defaultViewport: "smallTablet",
},
};

export const FullPage: StoryObj = Template.bind({}) as any;
FullPage.decorators = [
(story: StoryFn) => {
return {
Component: MockPageTransitions,
slot: story,
};
},
];
13 changes: 12 additions & 1 deletion src-svelte/src/routes/chat/Chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
export let showMostRecentMessage = true;
let messageComponents: Message[] = [];
let growable: Scrollable | undefined;
let chatContainer: HTMLDivElement | undefined = undefined;
let conversationWidthPx = 100;
function resizeConversationView() {
Expand All @@ -44,6 +45,13 @@
if (showMostRecentMessage) {
growable?.scrollToBottom();
}
if (!chatContainer) {
console.warn("Chat container not initialized");
return;
}
chatContainer.dispatchEvent(
new CustomEvent("info-box-update", { bubbles: true }),
);
}
function appendMessage(message: ChatMessage) {
Expand Down Expand Up @@ -81,7 +89,10 @@
</script>

<InfoBox title="Chat" fullHeight>
<div class="chat-container composite-reveal full-height">
<div
class="chat-container composite-reveal full-height"
bind:this={chatContainer}
>
<Scrollable
initialPosition={showMostRecentMessage ? "bottom" : "top"}
on:resize={onScrollableResized}
Expand Down

0 comments on commit a49582d

Please sign in to comment.