Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand Templates #10994

Merged
merged 15 commits into from
Sep 9, 2024
Binary file added app/dashboard/src/assets/ReadAndFilter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/aggregate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/blankProject.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/book.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/cleansing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/covid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/dashboard/src/assets/enso_logo_large.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/joining.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/kmeans.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/monthSales.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/nasdaq.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/dashboard/src/assets/weather.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ const DIALOG_STYLES = twv.tv({
},
slots: {
header:
'sticky top-0 grid grid-cols-[1fr_auto_1fr] items-center border-b border-primary/10 transition-[border-color] duration-150',
'sticky z-1 top-0 grid grid-cols-[1fr_auto_1fr] items-center border-b border-primary/10 transition-[border-color] duration-150',
closeButton: 'col-start-1 col-end-1 mr-auto',
heading: 'col-start-2 col-end-2 my-0 text-center',
content: 'relative flex-auto',
content: 'relative flex-auto overflow-y-auto max-h-[inherit]',
},
compoundVariants: [
{ type: 'modal', size: 'small', class: 'max-w-sm' },
Expand Down Expand Up @@ -144,7 +144,7 @@ export function Dialog(props: DialogProps) {
testId = 'dialog',
size,
rounded,
padding,
padding = type === 'modal' ? 'medium' : 'xlarge',
fitContent,
...ariaDialogProps
} = props
Expand Down
4 changes: 2 additions & 2 deletions app/dashboard/src/components/AriaComponents/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const TEXT_STYLE = twv.tv({
danger: 'text-danger',
success: 'text-accent-dark',
disabled: 'text-primary/30',
invert: 'text-white',
invert: 'text-invert',
inherit: 'text-inherit',
current: 'text-current',
},
Expand Down Expand Up @@ -89,7 +89,7 @@ export const TEXT_STYLE = twv.tv({
},
monospace: { true: 'font-mono' },
italic: { true: 'italic' },
nowrap: { true: 'whitespace-nowrap' },
nowrap: { true: 'whitespace-nowrap', normal: 'whitespace-normal', false: '' },
textSelection: {
auto: '',
none: 'select-none',
Expand Down
203 changes: 109 additions & 94 deletions app/dashboard/src/layouts/Samples.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
/** @file Renders the list of templates from which a project can be created. */
import * as React from 'react'

import Logo from '#/assets/enso_logo.svg'
import ReadAndFilterImage from '#/assets/ReadAndFilter.png'
import AggregatingImage from '#/assets/aggregate.png'
import BlankImage from '#/assets/blankProject.png'
import CleansingImage from '#/assets/cleansing.png'
import CovidImage from '#/assets/covid.png'
import GeoImage from '#/assets/geo.svg'
import HeartIcon from '#/assets/heart.svg'
import OpenCountIcon from '#/assets/open_count.svg'
import JoinImage from '#/assets/joining.png'
import KMeansImage from '#/assets/kmeans.png'
import MonthSalesImage from '#/assets/monthSales.png'
import NasdaqImage from '#/assets/nasdaq.png'
import SpreadsheetsImage from '#/assets/spreadsheets.svg'
import VisualizeImage from '#/assets/visualize.png'
import WeatherImage from '#/assets/weather.png'

import * as textProvider from '#/providers/TextProvider'

import * as aria from '#/components/aria'
import FocusArea from '#/components/styled/FocusArea'
import FocusRing from '#/components/styled/FocusRing'
import SvgMask from '#/components/SvgMask'

import * as tailwindMerge from '#/utilities/tailwindMerge'

// =================
// === Constants ===
// =================

/** A placeholder author for a sample, for use until the backend implements an endpoint. */
const DUMMY_AUTHOR = 'Enso Team'
/** A placeholder number of times a sample has been opened, for use until the backend implements
* an endpoint. */
const DUMMY_OPEN_COUNT = 10
/** A placeholder number of likes for a sample, for use until the backend implements an endpoint. */
const DUMMY_LIKE_COUNT = 10
import { Button, Text } from '#/components/AriaComponents'

// =========================
// === List of templates ===
Expand All @@ -41,42 +29,101 @@ export interface Sample {
readonly description: string
readonly id: string
readonly background?: string
readonly group?: string
}

/** The full list of templates. */
export const SAMPLES: Sample[] = [
{
title: 'Colorado COVID',
id: 'Colorado_COVID',
description: 'Learn to glue multiple spreadsheets to analyses all your data at once.',
title: 'Blank Project',
id: 'Default',
description: 'Start with a blank workflow.',
background: `url("${BlankImage}") center / cover`,
group: 'Getting Started',
},
{
title: 'KMeans',
id: 'KMeans',
description: 'Learn where to open a coffee shop to maximize your income.',
title: 'Reading and Filterng Data',
id: 'Getting_Started_Reading',
description: 'Learn how to bring data into Enso.',
background: `url("${ReadAndFilterImage}") center / cover`,
group: 'Getting Started',
},
{
title: 'Aggregating and Pivoting',
id: 'Getting_Started_Aggregating',
description: 'Learn how to group and aggregate data, and pivot.',
background: `url("${AggregatingImage}") center / cover`,
group: 'Getting Started',
},
{
title: 'Cleaning and Parsing Data',
id: 'Getting_Started_Cleansing',
description: 'Learn how to cleanse and parse text values.',
background: `url("${CleansingImage}") center / cover`,
group: 'Getting Started',
},
{
title: 'Selecting Columns and Joining Tables',
id: 'Getting_Started_Selecting',
description: 'Learn how to choose columns and join tables.',
background: `url("${JoinImage}") center / cover`,
group: 'Getting Started',
},
{
title: 'Analyze GitHub stars',
id: 'Stargazers',
description: "Find out which of Enso's repositories are most popular over time.",
background: `url("${VisualizeImage}") center / cover`,
group: 'Advanced',
},
{
title: 'NASDAQ Returns',
id: 'NASDAQReturns',
description: 'Learn how to clean your data to prepare it for advanced analysis.',
background: `url("${NasdaqImage}") center / cover`,
group: 'Advanced',
},
{
title: 'KMeans',
id: 'KMeans',
description: 'Learn where to open a coffee shop to maximize your income.',
background: `url("${KMeansImage}") center / cover`,
group: 'Advanced',
},
{
title: 'Combine spreadsheets',
id: 'Orders',
description: 'Glue multiple spreadsheets together to analyse all your data at once.',
background: `url('${SpreadsheetsImage}') center / 50% no-repeat, rgba(255, 255, 255, 0.30)`,
background: `url("${SpreadsheetsImage}") center / 50% no-repeat, rgba(255, 255, 255, 0.30)`,
group: 'Examples',
},
{
title: 'Month on Month Sales',
id: 'Monthly_Sales',
description: 'Learn how to compare with previous month sales.',
background: `url("${MonthSalesImage}") center / cover`,
group: 'Examples',
},
{
title: 'Colorado COVID',
id: 'Colorado_COVID',
description: 'Learn to glue multiple spreadsheets to analyses all your data at once.',
background: `url('${CovidImage}') center / 100% no-repeat, rgba(255, 255, 255, 0.30)`,
group: 'Examples',
},
{
title: 'Web API analysis',
id: 'Bank_Holiday_Rain',
description: 'Learn whether it rains on UK Bank Holidays via REST APIs.',
background: `url('${WeatherImage}') center / 100% no-repeat, rgba(255, 255, 255, 0.30)`,
group: 'Examples',
},
{
title: 'Geospatial analysis',
id: 'Restaurants',
description: 'Learn where to open a coffee shop to maximize your income.',
background: `url('${GeoImage}') 50% 20% / 100% no-repeat`,
},
{
title: 'Analyze GitHub stars',
id: 'Stargazers',
description: "Find out which of Enso's repositories are most popular over time.",
background: `url("${VisualizeImage}") center / cover`,
group: 'Examples',
},
]

Expand All @@ -93,61 +140,31 @@ interface InternalProjectTileProps {
/** A button that, when clicked, creates and opens a new project based on a template. */
function ProjectTile(props: InternalProjectTileProps) {
const { sample, createProject } = props
const { getText } = textProvider.useText()
const { id, title, description, background } = sample
const author = DUMMY_AUTHOR
const opens = DUMMY_OPEN_COUNT
const likes = DUMMY_LIKE_COUNT

return (
<div className="flex flex-col gap-sample">
<FocusArea direction="horizontal">
{(innerProps) => (
<FocusRing placement="after">
<aria.Button
key={title}
className="focus-child relative flex h-sample grow cursor-pointer flex-col text-left after:pointer-events-none after:absolute after:inset after:rounded-default"
onPress={() => {
createProject(id, title)
}}
{...innerProps}
>
<div
style={{ background }}
className={tailwindMerge.twMerge(
'h-sample-image w-full rounded-t-default',
background == null && 'bg-frame',
)}
/>
<div className="w-full grow rounded-b-default bg-frame px-sample-description-x pb-sample-description-b pt-sample-description-t backdrop-blur">
<aria.Heading className="text-header text-sm font-bold">{title}</aria.Heading>
<div className="text-ellipsis text-xs leading-snug">{description}</div>
</div>
</aria.Button>
</FocusRing>
)}
</FocusArea>
{/* Although this component is instantiated multiple times, it has a unique role and hence
* its own opacity. */}
{/* eslint-disable-next-line no-restricted-syntax */}
<div className="flex h-sample-info justify-between px-sample-description-x text-primary opacity-70">
<div className="flex gap-samples-icon-with-text">
<SvgMask src={Logo} className="size-4 self-end" />
<aria.Text className="self-start font-bold leading-snug">{author}</aria.Text>
</div>
{/* Normally `flex` */}
<div className="hidden gap-icons">
<div title={getText('views')} className="flex gap-samples-icon-with-text">
<SvgMask alt={getText('views')} src={OpenCountIcon} className="size-4 self-end" />
<aria.Text className="self-start font-bold leading-snug">{opens}</aria.Text>
</div>
<div title={getText('likes')} className="flex gap-samples-icon-with-text">
<SvgMask alt={getText('likes')} src={HeartIcon} className="size-4 self-end" />
<aria.Text className="self-start font-bold leading-snug">{likes}</aria.Text>
</div>
<Button
variant="custom"
size="custom"
rounded="xxxlarge"
key={title}
className="flex-none snap-center snap-always overflow-hidden"
style={{ background }}
onPress={() => {
createProject(id, title)
}}
>
<div className="flex aspect-[7/4] h-40 w-full flex-col justify-end bg-gradient-to-t from-primary/80 to-transparent">
<div className="flex w-full flex-col items-start px-4 pb-3 text-start">
<Text variant="subtitle" color="invert" nowrap="normal">
{title}
</Text>
<Text variant="body-sm" color="invert" nowrap="normal">
{description}
</Text>
</div>
</div>
</div>
</Button>
)
}

Expand All @@ -157,22 +174,20 @@ function ProjectTile(props: InternalProjectTileProps) {

/** Props for a {@link Samples}. */
export interface SamplesProps {
readonly groupName: string
readonly createProject: (templateId?: string | null, templateName?: string | null) => void
}

/** A list of sample projects. */
export default function Samples(props: SamplesProps) {
const { createProject } = props
const { getText } = textProvider.useText()
const { groupName, createProject } = props

return (
<div data-testid="samples" className="flex flex-col gap-subheading px-[5px]">
<aria.Heading level={2} className="text-subheading font-normal">
{getText('sampleAndCommunityProjects')}
</aria.Heading>
<div data-testid="samples" className="flex w-full flex-col">
<Text.Heading level={2}>{groupName}</Text.Heading>

<div className="grid grid-cols-fill-samples gap-samples">
{SAMPLES.map((sample) => (
<div className="-mx-12 inline-flex snap-x snap-mandatory gap-4 overflow-x-auto px-12 py-2 scroll-offset-edge-9xl">
{SAMPLES.filter((s) => s.group === groupName).map((sample) => (
<ProjectTile key={sample.id} sample={sample} createProject={createProject} />
))}
</div>
Expand Down
26 changes: 17 additions & 9 deletions app/dashboard/src/layouts/StartModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,26 @@ export default function StartModal(props: StartModalProps) {
<ariaComponents.Dialog type="fullscreen" title={getText('selectTemplate')}>
{(opts) => (
<div className="mb-4 flex flex-1 flex-col gap-home text-xs text-primary">
<ariaComponents.Text
elementType="p"
variant="custom"
balance
className="mx-10 my-12 max-w-[45rem] self-center text-center text-3xl font-light leading-snug"
>
{getText('welcomeSubtitle')}
</ariaComponents.Text>

<WhatsNew />

<Samples
groupName="Getting Started"
createProject={(templateId, templateName) => {
createProject(templateId, templateName)
opts.close()
}}
/>

<Samples
groupName="Examples"
createProject={(templateId, templateName) => {
createProject(templateId, templateName)
opts.close()
}}
/>

<Samples
groupName="Advanced"
createProject={(templateId, templateName) => {
createProject(templateId, templateName)
opts.close()
Expand Down
Loading
Loading