Skip to content

Commit

Permalink
feat(bridge-ui): Tabs Component (#13380)
Browse files Browse the repository at this point in the history
  • Loading branch information
jscriptcoder authored Mar 22, 2023
1 parent d6c12ab commit a046fa3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 29 deletions.
1 change: 1 addition & 0 deletions packages/bridge-ui/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@
pausable: false,
};
// TODO: Not found route
const routes = {
'/:tab?': wrap({
component: Home,
Expand Down
24 changes: 24 additions & 0 deletions packages/bridge-ui/src/components/Tabs/Tab.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { link } from 'svelte-spa-router';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { key } from './Tabs.svelte';
export let href: string = '';
export let name: string = '';
const activeTab = getContext<Writable<string>>(key);
$: selected = name === $activeTab;
$: tabActiveCls = selected ? 'tab-active' : '';
</script>

<a
role="tab"
aria-selected={selected}
class="tab tab-bordered {tabActiveCls}"
on:click={() => ($activeTab = name)}
{href}
use:link>
<slot />
</a>
3 changes: 3 additions & 0 deletions packages/bridge-ui/src/components/Tabs/TabList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div role="tablist" class="tabs {$$restProps.class || ''}">
<slot />
</div>
16 changes: 16 additions & 0 deletions packages/bridge-ui/src/components/Tabs/TabPanel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts">
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { key } from './Tabs.svelte';
export let tab: string = '';
const activeTab = getContext<Writable<string>>(key);
$: selected = tab === $activeTab;
$: classes = `${$$restProps.class || ''} ${!selected ? 'hidden' : ''}`;
</script>

<div role="tabpanel" aria-expanded={selected} class={classes}>
<slot />
</div>
17 changes: 17 additions & 0 deletions packages/bridge-ui/src/components/Tabs/Tabs.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts" context="module">
export const key = Symbol();
</script>

<script lang="ts">
import { writable } from 'svelte/store';
import { setContext } from 'svelte';
export let activeTab = '';
// State only available to the component and its descendants
setContext(key, writable(activeTab));
</script>

<div class={$$restProps.class} style={$$restProps.style}>
<slot />
</div>
4 changes: 4 additions & 0 deletions packages/bridge-ui/src/components/Tabs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as Tabs } from './Tabs.svelte';
export { default as TabList } from './TabList.svelte';
export { default as Tab } from './Tab.svelte';
export { default as TabPanel } from './TabPanel.svelte';
65 changes: 36 additions & 29 deletions packages/bridge-ui/src/pages/home/Home.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
import { link, location } from 'svelte-spa-router';
import { location } from 'svelte-spa-router';
import { transactions } from '../../store/transactions';
import BridgeForm from '../../components/form/BridgeForm.svelte';
import TaikoBanner from '../../components/TaikoBanner.svelte';
import Transactions from '../../components/Transactions.svelte';
import { Tabs, TabList, Tab, TabPanel } from '../../components/Tabs';
let bridgeWidth: number;
let bridgeHeight: number;
$: activeTab = $location.replace('/', '').startsWith('transactions')
? 'transactions'
: 'bridge';
$: isBridge = activeTab === 'bridge';
// List of tab's name <=> route association
// TODO: add this into a general configuration.
const tabsRoute = [
{ name: 'bridge', href: '/' },
{ name: 'transactions', href: '/transactions' },
// Add more tabs if needed
];
// TODO: we're assuming we have only two tabs here.
// Change strategy if needed.
$: activeTab = $location === '/' ? tabsRoute[0].name : tabsRoute[1].name;
// TODO: do we really need all these tricks to style containers
// Rethink this part: fluid, fixing on bigger screens
$: isBridge = activeTab === tabsRoute[0].name;
$: styleContainer = isBridge ? '' : `min-width: ${bridgeWidth}px;`;
$: fitClassContainer = isBridge ? 'max-w-fit' : 'w-fit';
$: styleInner =
Expand All @@ -26,34 +38,29 @@
style={styleContainer}
bind:clientWidth={bridgeWidth}
bind:clientHeight={bridgeHeight}>
<div
<Tabs
class="rounded-3xl border-2 border-bridge-form border-solid p-2 md:p-6"
style={styleInner}>
<!-- TODO: extract this tab component into a general one? -->
<div class="tabs block mb-4">
<a
class="tab tab-bordered {isBridge ? 'tab-active' : ''}"
href="/"
use:link>Bridge</a>
<a
class="tab tab-bordered {!isBridge ? 'tab-active' : ''}"
href="/transactions"
use:link>Transactions ({$transactions.length})</a>
</div>

{#if activeTab === 'bridge'}
style={styleInner}
bind:activeTab>
{@const tab1 = tabsRoute[0]}
{@const tab2 = tabsRoute[1]}

<TabList class="block mb-4">
<Tab name={tab1.name} href={tab1.href}>Bridge</Tab>
<Tab name={tab2.name} href={tab2.href}>
Transactions ({$transactions.length})
</Tab>
</TabList>

<TabPanel tab={tab1.name}>
<TaikoBanner />
<div class="px-4">
<BridgeForm />
</div>
{:else}
</TabPanel>

<TabPanel tab={tab2.name}>
<Transactions />
{/if}
</div>
</TabPanel>
</Tabs>
</div>

<style>
.tabs {
display: block;
}
</style>

0 comments on commit a046fa3

Please sign in to comment.