Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
@property --border-angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}

@keyframes border-rotate {
to {
--border-angle: 360deg;
}
}

.outer-container {
width: 100%;
overflow-y: auto;
overscroll-behavior: none;
pointer-events: auto;
background:
linear-gradient(
rgb(var(--color-query-surface-subtle)),
rgb(var(--color-query-surface-subtle))
)
padding-box,
conic-gradient(
from var(--border-angle),
rgb(var(--color-query-accent)),
rgb(var(--color-query-accent-subtle)),
rgb(var(--color-query-accent)),
rgb(var(--color-query-accent-subtle)),
rgb(var(--color-query-accent))
)
border-box;
border: 1.5px solid transparent;
border-radius: var(--border-radius-large);
box-shadow: var(--shadow-elevated);

// Animate the registered custom property to rotate the border gradient
@include prefers-motion {
animation: border-rotate 6s linear infinite;
}
}

.inner-container {
display: flex;
flex-direction: column;
row-gap: 32px;
padding: 40px;
}

.question {
@include type-body-large(500);

align-self: flex-end;
max-width: 80%;
padding: 20px 28px;
color: rgb(var(--color-query-content-subtle));
background: rgb(var(--color-query-surface-muted));
border-radius: var(--border-radius-medium);
}

.answer {
@include type-body-large;

color: rgb(var(--color-query-content-subtle));
white-space: break-spaces;
}

.prompts-container {
display: flex;
flex-direction: column;
row-gap: 8px;
align-items: flex-start;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use client';

import { EASE_LINEAR } from '@package/tokens/ts';
import { m } from 'motion/react';
import { Button } from '~/components/elements/button';
import s from './follow_up.module.scss';

export interface QuestionAndAnswers {
/** The question the user asked, echoed back as a chat bubble. */
question: string;

/** The assistant's answer. Newlines are preserved. */
answer: string;

/** Suggested follow-up prompts, rendered as selectable pills. */
prompts: string[];
}

interface FollowUpProps {
followUp: QuestionAndAnswers;
onSelect: (followUp: string) => void;
}

export const FollowUp = ({ followUp, onSelect }: FollowUpProps) => {
return (
<m.section
className={s['outer-container']}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.1, ease: EASE_LINEAR }}
>
<div className={s['inner-container']}>
<p className={s.question}>{followUp.question}</p>

<div className={s.answer}>{followUp.answer}</div>

{followUp.prompts.length > 0 && (
<ul className={s['prompts-container']}>
{followUp.prompts.map((prompt) => (
<li key={prompt}>
<Button
size="medium"
variant="flat"
tone="accent-subtle"
onClick={() => onSelect(prompt)}
>
{prompt}
</Button>
</li>
))}
</ul>
)}
</div>
</m.section>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
overflow-y: auto;
overscroll-behavior: none;
pointer-events: auto;
background: rgb(var(--color-query-surface));
background: rgb(var(--color-query-surface-raised));
border-radius: var(--border-radius-large);
box-shadow: var(--shadow-elevated);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { IconClose } from '~/components/primitives/icons/close';
import { IconInfo } from '~/components/primitives/icons/info';
import s from './intro.module.scss';

const EXAMPLE_PROMPTS = [
export const EXAMPLE_PROMPTS = [
'How access to electricity has changed across countries in Africa?',
'Which countries have the highest access to mobile phones?',
'Compare GDP and population growth globally over the last 50 years.',
'What fraction of the world is forest?',
] as const;

interface IntroProps {
onSelect: (example: string) => void;
onSelect: (example: string, index: number) => void;
onClose: () => void;
}

Expand Down Expand Up @@ -53,13 +53,13 @@ export const Intro = ({ onSelect, onClose }: IntroProps) => {
</p>

<ul className={s['examples-container']}>
{EXAMPLE_PROMPTS.map((example) => (
{EXAMPLE_PROMPTS.map((example, index) => (
<li key={example}>
<Button
size="medium"
variant="flat"
tone="accent-subtle"
onClick={() => onSelect(example)}
onClick={() => onSelect(example, index)}
>
{example}
</Button>
Expand Down
44 changes: 32 additions & 12 deletions dataweaver/apps/web/src/components/scopes/page_home/page_home.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
'use client';

import { AnimatePresence } from 'motion/react';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import { useQueryActions } from '~/components/scopes/atlas/query_provider';
import { Intro } from './intro';
import { MOCK_FOLLOW_UP } from '~/configs/mock_follow_up';
import { FollowUp, type QuestionAndAnswers } from './follow_up';
import { EXAMPLE_PROMPTS, Intro } from './intro';
import s from './page_home.module.scss';
import { Prompt } from './prompt';
import { Status } from './status';
Expand All @@ -12,37 +14,55 @@ export const PageHome = () => {
const { status, runPrompt } = useQueryActions();

const [isIntroVisible, setIsIntroVisible] = useState(true);
const [followUp, setFollowUp] = useState<QuestionAndAnswers | null>(null);
const [promptValue, setPromptValue] = useState('');

// Auto close intro if we have a status and it's visible
useEffect(() => {
if (status && isIntroVisible) setIsIntroVisible(false);
}, [status, isIntroVisible]);

const submit = (promptValue: string) => {
const submitPrompt = (promptValue: string) => {
runPrompt(promptValue);
setPromptValue('');
setIsIntroVisible(false);
setFollowUp(null);
};

const selectExample = (example: string, index: number) => {
// TODO: For now this purely just previews when last intro prompt is
// selected. This needs to be hooked up differently / reworked later but for
// now allows us to demo UI
if (index === EXAMPLE_PROMPTS.length - 1) {
setIsIntroVisible(false);
setFollowUp(MOCK_FOLLOW_UP);
return;
}

submitPrompt(example);
};

return (
<div className={s.container}>
<AnimatePresence initial={false} mode="wait">
{isIntroVisible && !status && (
{isIntroVisible && !status && !followUp && (
<Intro
key="intro"
onSelect={submit}
onSelect={selectExample}
onClose={() => setIsIntroVisible(false)}
/>
)}

{status && !isIntroVisible && <Status key="status" status={status} />}
{followUp && !status && (
<FollowUp
key="follow-up"
followUp={followUp}
onSelect={submitPrompt}
/>
)}

{status && <Status key="status" status={status} />}
</AnimatePresence>

<Prompt
value={promptValue}
onValueChange={setPromptValue}
onSubmit={submit}
onSubmit={submitPrompt}
/>
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions dataweaver/apps/web/src/configs/mock_follow_up.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { QuestionAndAnswers } from '~/components/scopes/page_home/follow_up';

export const MOCK_FOLLOW_UP: QuestionAndAnswers = {
question: 'Do you know of a place in Africa called Seychelles?',
answer:
'Seychelles is a country in Africa. The population in Seychelles was ' +
'121,354 in 2024. The nominal GDP per capita in Seychelles was ' +
'$17,858.82 in 2024. The Gini index in Seychelles was 32.1 in 2018. ' +
'The life expectancy in Seychelles was 74.96 in 2023. The energy ' +
'consumption per capita in Seychelles was 2,410.83kgoe in 2007. The ' +
'carbon dioxide emissions per capita in Seychelles was 7.24t in 2024.' +
// TODO: Support HTML rendering here so that this line / future question
// lines can support bold text
'\n\nWhat specifically would you like to know?',
prompts: [
'Economic impact',
'Health outcomes for its people',
'Energy access in the country',
'Environmental impact',
],
} as const;
31 changes: 17 additions & 14 deletions dataweaver/packages/tokens/src/colors.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"accent-subtle": [194, 231, 255],
"accent-subtle-strong": [173, 214, 240],

"surface": [247, 252, 255],
"surface-subtle": [248, 249, 252],
"surface-hover": [227, 231, 237],
"surface-raised": [255, 255, 255],
"surface-dimmed": [247, 252, 255],
"surface-subtle": [248, 249, 252],
"surface-muted": [227, 231, 237],

"content": [32, 33, 36],
"content-muted": [68, 71, 70],
Expand All @@ -17,17 +17,20 @@
"shadow": [0, 0, 0],
"transparent": [0, 0, 0, 0],

"atlas-surface": "$surface",
"atlas-decorator": "$surface-hover",
"atlas-surface": "$surface-dimmed",
"atlas-decorator": "$surface-muted",
"atlas-content": "$shadow",
"atlas-accent": "$accent",
"atlas-accent-content": "$accent-content",

"query-surface": "$surface-raised",
"query-surface-raised": "$surface-raised",
"query-surface-subtle": "$surface-subtle",
"query-surface-muted": "$surface-muted",
"query-content": "$content",
"query-content-subtle": "$content-subtle",
"query-content-dimmed": "$content-dimmed",
"query-accent": "$accent",
"query-accent-subtle": "$accent-subtle",

"button-prominent-base": "$transparent",
"button-prominent-content": "$content",
Expand All @@ -38,14 +41,14 @@

"button-subtle-base": "$transparent",
"button-subtle-content": "$content",
"button-subtle-base-hover": "$surface-hover",
"button-subtle-base-hover": "$surface-muted",
"button-subtle-content-hover": "$button-subtle-content",
"button-subtle-border": [219, 219, 219],
"button-subtle-border-hover": "$button-subtle-border",

"button-subtle-highlight-base": "$transparent",
"button-subtle-highlight-content": "$accent",
"button-subtle-highlight-base-hover": "$surface-hover",
"button-subtle-highlight-base-hover": "$surface-muted",
"button-subtle-highlight-content-hover": "$button-subtle-highlight-content",
"button-subtle-highlight-border": [116, 119, 117],
"button-subtle-highlight-border-hover": "$button-subtle-highlight-border",
Expand All @@ -64,9 +67,9 @@
"button-accent-subtle-border": "$transparent",
"button-accent-subtle-border-hover": "$transparent",

"control-surface": "$surface",
"control-surface": "$surface-dimmed",
"control-surface-raised": "$surface-raised",
"control-surface-hover": "$surface-hover",
"control-surface-hover": "$surface-muted",
"control-accent": "$accent",
"control-accent-subtle": "$accent-subtle",
"control-content": "$content",
Expand All @@ -77,18 +80,18 @@
"card-content": "$content",
"card-content-muted": "$content-muted",
"card-divider": [196, 199, 197],
"card-chart-grid": "$surface-hover",
"card-chart-grid": "$surface-muted",
"card-action-base": "$transparent",
"card-action-content": "$accent-content",
"card-action-base-hover": "$surface-raised",
"card-action-content-hover": "$accent",

"skeleton-surface": [242, 242, 242],

"menu-surface": "$surface",
"menu-surface": "$surface-dimmed",

"radio-surface": "$surface-hover",
"radio-surface-hover": "$surface",
"radio-surface": "$surface-muted",
"radio-surface-hover": "$surface-dimmed",
"radio-surface-checked": "$surface-raised",
"radio-border": "$content-dimmed",
"radio-mark": "$content",
Expand Down