mirror of
https://github.com/ivabus/gui
synced 2025-06-08 00:00:27 +03:00
added reusable ui components: posts list and panel header w/ cta
This commit is contained in:
parent
9173ef66b2
commit
c05d3b0775
12 changed files with 123 additions and 222 deletions
|
@ -0,0 +1,17 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import '$appcss';
|
||||||
|
import { getAllPosts } from '$libs/api/mock';
|
||||||
|
import type { AirtablePost } from '@tea/ui/types';
|
||||||
|
import Posts from '@tea/ui/Posts/Posts.svelte';
|
||||||
|
import PanelHeader from '@tea/ui/PanelHeader/PanelHeader.svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let courses: AirtablePost[] = [];
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
courses = await getAllPosts('course');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PanelHeader title="Essential Workshops" ctaLabel="View all" ctaLink="/" />
|
||||||
|
<Posts posts={courses} />
|
17
packages/gui/src/components/News/News.svelte
Normal file
17
packages/gui/src/components/News/News.svelte
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import '$appcss';
|
||||||
|
import { getAllPosts } from '$libs/api/mock';
|
||||||
|
import type { AirtablePost } from '@tea/ui/types';
|
||||||
|
import Posts from '@tea/ui/Posts/Posts.svelte';
|
||||||
|
import PanelHeader from '@tea/ui/PanelHeader/PanelHeader.svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let news: AirtablePost[] = [];
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
news = await getAllPosts('news');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PanelHeader title="Open-source News" ctaLabel="Read more articles >" ctaLink="/" />
|
||||||
|
<Posts posts={news} />
|
|
@ -1,40 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import '$appcss';
|
|
||||||
import { getAllPosts } from '$libs/api/mock';
|
|
||||||
import type { AirtablePost } from '@tea/ui/types';
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
export let title: string;
|
|
||||||
export let type: string;
|
|
||||||
export let readMoreLink: string;
|
|
||||||
export let readMoreCta = 'Read more';
|
|
||||||
|
|
||||||
let posts: AirtablePost[] = [];
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
// todo: filter by type
|
|
||||||
posts = await getAllPosts();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<header class="flex items-center justify-between border border-gray bg-black p-4 text-primary">
|
|
||||||
<span class="uppercase">{title}</span>
|
|
||||||
<a href={readMoreLink} class="font-sono text-sm underline">{readMoreCta}</a>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<ul class="flex flex-col bg-black">
|
|
||||||
{#each posts as article}
|
|
||||||
<li class="border border-t-0 border-gray p-4">
|
|
||||||
<article class="flex border border-gray">
|
|
||||||
<figure class="w-1/3">
|
|
||||||
<img src={article.thumb_image_url} alt={article.title} />
|
|
||||||
</figure>
|
|
||||||
<section class="p-4 font-sono">
|
|
||||||
<h1 class="text-xl text-primary">{article.title}</h1>
|
|
||||||
<p class="my-4 text-sm">{article.short_description}</p>
|
|
||||||
<a href={article.link} class="text-sm text-primary underline">Read more ...</a>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
|
@ -6,7 +6,7 @@
|
||||||
import FeaturedPackages from '$components/FeaturedPackages/FeaturedPackages.svelte';
|
import FeaturedPackages from '$components/FeaturedPackages/FeaturedPackages.svelte';
|
||||||
import GettingStarted from '$components/GettingStarted/GettingStarted.svelte';
|
import GettingStarted from '$components/GettingStarted/GettingStarted.svelte';
|
||||||
import TopPackages from '$components/TopPackages/TopPackages.svelte';
|
import TopPackages from '$components/TopPackages/TopPackages.svelte';
|
||||||
import PostThumbs from '$components/PostThumbs/PostThumbs.svelte';
|
import News from '$components/News/News.svelte';
|
||||||
backLink.set('');
|
backLink.set('');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -22,12 +22,7 @@
|
||||||
<TopPackages />
|
<TopPackages />
|
||||||
</section>
|
</section>
|
||||||
<section class="mt-8">
|
<section class="mt-8">
|
||||||
<PostThumbs
|
<News />
|
||||||
title="open-source news"
|
|
||||||
readMoreCta="Read more articles >"
|
|
||||||
readMoreLink="/"
|
|
||||||
type="news"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import '$appcss';
|
import '$appcss';
|
||||||
import PageHeader from '$components/PageHeader/PageHeader.svelte';
|
import PageHeader from '$components/PageHeader/PageHeader.svelte';
|
||||||
import FeaturedCourses from '$components/FeaturedCourses/FeaturedCourses.svelte';
|
import FeaturedCourses from '$components/FeaturedCourses/FeaturedCourses.svelte';
|
||||||
import PostThumbs from '$components/PostThumbs/PostThumbs.svelte';
|
import EssentialWorkshops from '$components/EssentialWorkshops/EssentialWorkshops.svelte';
|
||||||
import { backLink } from '$libs/stores';
|
import { backLink } from '$libs/stores';
|
||||||
backLink.set('/');
|
backLink.set('/');
|
||||||
</script>
|
</script>
|
||||||
|
@ -15,11 +15,6 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="mt-8">
|
<section class="mt-8">
|
||||||
<PostThumbs
|
<EssentialWorkshops />
|
||||||
type="course"
|
|
||||||
title="ESSENTIAL WORKSHOPS"
|
|
||||||
readMoreCta="View all >"
|
|
||||||
readMoreLink="/"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { within, userEvent } from '@storybook/testing-library';
|
|
||||||
import Page from './Page.svelte';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Example/Page',
|
|
||||||
component: Page,
|
|
||||||
parameters: {
|
|
||||||
// More on how to position stories at: https://storybook.js.org/docs/7.0/svelte/configure/story-layout
|
|
||||||
layout: 'fullscreen'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export const LoggedOut = {};
|
|
||||||
|
|
||||||
// More on interaction testing: https://storybook.js.org/docs/7.0/svelte/writing-tests/interaction-testing
|
|
||||||
export const LoggedIn = {
|
|
||||||
render: (args) => ({
|
|
||||||
Component: Page,
|
|
||||||
props: args
|
|
||||||
}),
|
|
||||||
play: async ({ canvasElement }) => {
|
|
||||||
const canvas = within(canvasElement);
|
|
||||||
const loginButton = await canvas.getByRole('button', {
|
|
||||||
name: /Log in/i
|
|
||||||
});
|
|
||||||
await userEvent.click(loginButton);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,70 +0,0 @@
|
||||||
<script type="ts">
|
|
||||||
import './page.css';
|
|
||||||
import Header from '../Header/Header.svelte';
|
|
||||||
|
|
||||||
let user = null;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<Header
|
|
||||||
{user}
|
|
||||||
on:login={() => (user = { name: 'Jane Doe' })}
|
|
||||||
on:logout={() => (user = null)}
|
|
||||||
on:createAccount={() => (user = { name: 'Jane Doe' })}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2>Pages in Storybook</h2>
|
|
||||||
<p>
|
|
||||||
We recommend building UIs with a
|
|
||||||
<a
|
|
||||||
href="https://blog.hichroma.com/component-driven-development-ce1109d56c8e"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<strong>component-driven</strong>
|
|
||||||
</a>
|
|
||||||
process starting with atomic components and ending with pages.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Render pages with mock data. This makes it easy to build and review page states without
|
|
||||||
needing to navigate to them in your app. Here are some handy patterns for managing page data
|
|
||||||
in Storybook:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Use a higher-level connected component. Storybook helps you compose such data from the
|
|
||||||
"args" of child component stories
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Assemble data in the page component from your services. You can mock these services out
|
|
||||||
using Storybook.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Get a guided tutorial on component-driven development at
|
|
||||||
<a href="https://storybook.js.org/tutorials/" target="_blank" rel="noopener noreferrer">
|
|
||||||
Storybook tutorials
|
|
||||||
</a>
|
|
||||||
. Read more in the
|
|
||||||
<a href="https://storybook.js.org/docs" target="_blank" rel="noopener noreferrer">docs</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
<div class="tip-wrapper">
|
|
||||||
<span class="tip">Tip</span>
|
|
||||||
Adjust the width of the canvas with the
|
|
||||||
<svg width="10" height="10" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g fill="none" fill-rule="evenodd">
|
|
||||||
<path
|
|
||||||
d="M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0
|
|
||||||
01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0
|
|
||||||
010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z"
|
|
||||||
id="a"
|
|
||||||
fill="#999"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
Viewports addon in the toolbar
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</article>
|
|
|
@ -1,71 +0,0 @@
|
||||||
@import '../app.css';
|
|
||||||
|
|
||||||
section {
|
|
||||||
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 24px;
|
|
||||||
padding: 48px 20px;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 600px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
section h2 {
|
|
||||||
font-weight: 900;
|
|
||||||
font-size: 32px;
|
|
||||||
line-height: 1;
|
|
||||||
margin: 0 0 4px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
section p {
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
section a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #1ea7fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
section ul {
|
|
||||||
padding-left: 30px;
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
section li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .tip {
|
|
||||||
display: inline-block;
|
|
||||||
border-radius: 1em;
|
|
||||||
font-size: 11px;
|
|
||||||
line-height: 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
background: #e7fdd8;
|
|
||||||
color: #66bf3c;
|
|
||||||
padding: 4px 12px;
|
|
||||||
margin-right: 10px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .tip-wrapper {
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 20px;
|
|
||||||
margin-top: 40px;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .tip-wrapper svg {
|
|
||||||
display: inline-block;
|
|
||||||
height: 12px;
|
|
||||||
width: 12px;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section .tip-wrapper svg path {
|
|
||||||
fill: #1ea7fd;
|
|
||||||
}
|
|
19
packages/ui/src/PanelHeader/PanelHeader.stories.ts
Normal file
19
packages/ui/src/PanelHeader/PanelHeader.stories.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import PanelHeader from './PanelHeader.svelte';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Example/PanelHeader',
|
||||||
|
component: PanelHeader,
|
||||||
|
render: (props) => ({
|
||||||
|
Component: PanelHeader,
|
||||||
|
props
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// More on interaction testing: https://storybook.js.org/docs/7.0/svelte/writing-tests/interaction-testing
|
||||||
|
export const Example = {
|
||||||
|
args: {
|
||||||
|
title: 'Open-Source News',
|
||||||
|
ctaLabel: 'Read More News >',
|
||||||
|
ctaLink: '/'
|
||||||
|
}
|
||||||
|
};
|
10
packages/ui/src/PanelHeader/PanelHeader.svelte
Normal file
10
packages/ui/src/PanelHeader/PanelHeader.svelte
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export let title: string;
|
||||||
|
export let ctaLabel: string;
|
||||||
|
export let ctaLink: string;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="flex items-center justify-between border border-gray bg-black p-4 text-primary">
|
||||||
|
<span class="uppercase">{title}</span>
|
||||||
|
<a href={ctaLink} class="font-sono text-sm underline">{ctaLabel}</a>
|
||||||
|
</header>
|
33
packages/ui/src/Posts/Posts.stories.ts
Normal file
33
packages/ui/src/Posts/Posts.stories.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import Posts from './Posts.svelte';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Example/Posts',
|
||||||
|
component: Posts,
|
||||||
|
render: ({ posts }) => ({
|
||||||
|
Component: Posts,
|
||||||
|
props: {
|
||||||
|
posts
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// More on interaction testing: https://storybook.js.org/docs/7.0/svelte/writing-tests/interaction-testing
|
||||||
|
export const Example = {
|
||||||
|
args: {
|
||||||
|
posts: [
|
||||||
|
{
|
||||||
|
airtable_record_id: 'a',
|
||||||
|
link: 'https://google.com',
|
||||||
|
title: 'Tea Inc releases game changing api!',
|
||||||
|
sub_title: 'lorem ipsum dolor sit amet',
|
||||||
|
short_description: 'lorem ipsum dolor sit amet',
|
||||||
|
thumb_image_url: '/images/bored-ape.png',
|
||||||
|
thumb_image_name: 'borred-api.png',
|
||||||
|
created_at: new Date(),
|
||||||
|
updated_at: new Date(),
|
||||||
|
published_at: new Date(),
|
||||||
|
tags: ['news']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
23
packages/ui/src/Posts/Posts.svelte
Normal file
23
packages/ui/src/Posts/Posts.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import '../app.css';
|
||||||
|
import type { AirtablePost } from '../types';
|
||||||
|
|
||||||
|
export let posts: AirtablePost[] = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class="flex flex-col bg-black">
|
||||||
|
{#each posts as article}
|
||||||
|
<li class="border border-t-0 border-gray p-4">
|
||||||
|
<article class="flex border border-gray">
|
||||||
|
<figure class="w-1/3">
|
||||||
|
<img src={article.thumb_image_url} alt={article.title} />
|
||||||
|
</figure>
|
||||||
|
<section class="p-4 font-sono">
|
||||||
|
<h1 class="text-xl text-primary">{article.title}</h1>
|
||||||
|
<p class="my-4 text-sm">{article.short_description}</p>
|
||||||
|
<a href={article.link} class="text-sm text-primary underline">Read more ...</a>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
Loading…
Reference in a new issue