feat: UI create explore view skeleton (#197)
* wip: added header for explore view * chore: add skeleton for explore view * chore: add dropdown variation * style: align dropdown list
This commit is contained in:
parent
f74c8bb569
commit
c10c59ae24
|
|
@ -1,7 +1,6 @@
|
||||||
import { HashRouter, Route, Routes, Navigate } from 'react-router-dom';
|
import { HashRouter, Route, Routes, Navigate } from 'react-router-dom';
|
||||||
import { themeGlobals } from '@/theme/globals';
|
import { themeGlobals } from '@/theme/globals';
|
||||||
import { ComponentsTest, CreateAP, Home, Mint } from './views';
|
import { ComponentsTest, Home, Mint, Explore, CreateAP } from './views';
|
||||||
import { MintTest } from './views/mint-test';
|
|
||||||
import { AppPage, ToastProvider } from './components';
|
import { AppPage, ToastProvider } from './components';
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
|
|
@ -13,12 +12,12 @@ export const App = () => {
|
||||||
<AppPage>
|
<AppPage>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
|
<Route path="/explore" element={<Explore />} />
|
||||||
<Route path="/mint" element={<Mint />} />
|
<Route path="/mint" element={<Mint />} />
|
||||||
<Route path="/create-ap" element={<CreateAP />} />
|
<Route path="/create-ap" element={<CreateAP />} />
|
||||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||||
{/** TODO remove for release */}
|
{/** TODO remove for release */}
|
||||||
<Route path="/components-test" element={<ComponentsTest />} />
|
<Route path="/components-test" element={<ComponentsTest />} />
|
||||||
<Route path="/mint-test" element={<MintTest />} />
|
|
||||||
<Route path="*" element={<Navigate to="/" />} />
|
<Route path="*" element={<Navigate to="/" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
|
|
|
||||||
|
|
@ -46,63 +46,132 @@ const DropdownOption = ({ option }: DropdownOptionProps) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
type DropdownButtonProps = {
|
type DropdownButtonProps = {
|
||||||
|
/**
|
||||||
|
* The selected value of the dropdown.
|
||||||
|
*/
|
||||||
selectedValue: DropdownItem | undefined;
|
selectedValue: DropdownItem | undefined;
|
||||||
|
/**
|
||||||
|
* If it's true, the list of options will be displayed
|
||||||
|
*/
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
/**
|
||||||
|
* Background color of the dropdown. Should be on tailwind palette.
|
||||||
|
*/
|
||||||
|
backgroundColor?: string;
|
||||||
|
/**
|
||||||
|
* Text color of the dropdown. Should be on tailwind palette.
|
||||||
|
*/
|
||||||
|
textColor?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DropdownButton = ({ selectedValue, open }: DropdownButtonProps) => (
|
const DropdownButton = ({
|
||||||
<Listbox.Button
|
selectedValue,
|
||||||
className={`relative w-full cursor-default border-solid border border-slate7 py-3 pl-3.5 pr-10 h-11 text-left focus:outline-none sm:text-sm ${
|
open, //TODO maybe would be deprecated
|
||||||
open
|
backgroundColor,
|
||||||
? 'border-b-0 rounded-t-xl bg-black border-slate6'
|
textColor,
|
||||||
: 'rounded-xl bg-transparent'
|
}: DropdownButtonProps) => {
|
||||||
}`}
|
const textColorCss = textColor ? `text-${textColor}` : 'text-slate12';
|
||||||
>
|
const borderColor = backgroundColor
|
||||||
<span
|
? `border-${backgroundColor}`
|
||||||
className={`block truncate ${
|
: 'border-slate7';
|
||||||
selectedValue && selectedValue.label ? 'text-slate12' : 'text-slate11'
|
const backgroundColorClass = backgroundColor
|
||||||
} break-words`}
|
? `bg-${backgroundColor}`
|
||||||
|
: 'bg-transparent';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Listbox.Button
|
||||||
|
className={`relative w-full cursor-default ${borderColor} border-solid border rounded-xl py-3 pl-3.5 pr-10 h-11 text-left focus:outline-none sm:text-sm
|
||||||
|
${backgroundColorClass}
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
{selectedValue && selectedValue.label ? selectedValue.label : 'Select'}
|
<span
|
||||||
</span>
|
className={`block truncate ${
|
||||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4">
|
selectedValue && selectedValue.label
|
||||||
<Icon name="chevron-down" />
|
? `${textColorCss}`
|
||||||
</span>
|
: 'text-slate11'
|
||||||
</Listbox.Button>
|
} break-words`}
|
||||||
);
|
>
|
||||||
|
{selectedValue && selectedValue.label ? selectedValue.label : 'Select'}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4 ${textColorCss}`}
|
||||||
|
>
|
||||||
|
<Icon name="chevron-down" />
|
||||||
|
</span>
|
||||||
|
</Listbox.Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export type DropdownItem = {
|
export type DropdownItem = {
|
||||||
|
/**
|
||||||
|
* The key of the item.
|
||||||
|
*/
|
||||||
value: string;
|
value: string;
|
||||||
|
/**
|
||||||
|
* The label to display of the item.
|
||||||
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DropdownProps = {
|
export type DropdownProps = {
|
||||||
|
/**
|
||||||
|
* List of items to be displayed in the dropdown.
|
||||||
|
*/
|
||||||
items: DropdownItem[];
|
items: DropdownItem[];
|
||||||
|
/**
|
||||||
|
* The selected value of the dropdown.
|
||||||
|
*/
|
||||||
selectedValue: DropdownItem | undefined;
|
selectedValue: DropdownItem | undefined;
|
||||||
|
/**
|
||||||
|
* Callback when the selected value changes.
|
||||||
|
*/
|
||||||
onChange(option: DropdownItem): void;
|
onChange(option: DropdownItem): void;
|
||||||
|
/**
|
||||||
|
* Background color of the dropdown. Should be on tailwind palette. https://tailwindcss.com/docs/background-color
|
||||||
|
*/
|
||||||
|
backgroundColor?: string;
|
||||||
|
/**
|
||||||
|
* Text color of the dropdown. Should be on tailwind palette. https://tailwindcss.com/docs/text-color
|
||||||
|
*/
|
||||||
|
textColor?: string;
|
||||||
|
/**
|
||||||
|
* Width of the options list. Should be on tailwind width. https://tailwindcss.com/docs/width
|
||||||
|
*/
|
||||||
|
optionsWidth?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Dropdown: React.FC<DropdownProps> = ({
|
export const Dropdown: React.FC<DropdownProps> = ({
|
||||||
items,
|
items,
|
||||||
selectedValue,
|
selectedValue,
|
||||||
onChange,
|
onChange,
|
||||||
|
backgroundColor,
|
||||||
|
textColor,
|
||||||
|
optionsWidth,
|
||||||
}) => {
|
}) => {
|
||||||
const handleDropdownChange = (option: DropdownItem) => {
|
const handleDropdownChange = (option: DropdownItem) => {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
};
|
};
|
||||||
|
const width = optionsWidth ? `w-${optionsWidth}` : 'w-full';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Listbox value={selectedValue} by="value" onChange={handleDropdownChange}>
|
<Listbox value={selectedValue} by="value" onChange={handleDropdownChange}>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div className="relative max-w-full">
|
<div className="relative max-w-full">
|
||||||
<DropdownButton selectedValue={selectedValue} open={open} />
|
<DropdownButton
|
||||||
|
selectedValue={selectedValue}
|
||||||
|
open={open}
|
||||||
|
backgroundColor={backgroundColor}
|
||||||
|
textColor={textColor}
|
||||||
|
/>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
leave="transition ease-in duration-100"
|
leave="transition ease-in duration-100"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Listbox.Options className="absolute max-h-32 w-full z-10 overflow-auto rounded-b-xl bg-black px-3 pt-2 border-solid border-slate6 border text-base focus:outline-none sm:text-sm">
|
<Listbox.Options
|
||||||
|
className={`absolute mt-1 max-h-32 ${width} right-0 z-10 overflow-auto rounded-xl bg-black px-3 pt-2 border-solid border-slate6 border text-base focus:outline-none sm:text-sm`}
|
||||||
|
>
|
||||||
{items.map((option: DropdownItem) => (
|
{items.map((option: DropdownItem) => (
|
||||||
<DropdownOption key={option.value} option={option} />
|
<DropdownOption key={option.value} option={option} />
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||||
<InputStyled
|
<InputStyled
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
css={{ ...(leftIcon && { pl: '$10' }) }}
|
css={{ ...(leftIcon && { pl: '$10' }), ...(props?.css || {}) }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const NavBar: React.FC = () => {
|
||||||
<Logo />
|
<Logo />
|
||||||
|
|
||||||
<Styles.Navigation>
|
<Styles.Navigation>
|
||||||
<Button as={Link} to="/" variant="link" color="gray">
|
<Button as={Link} to="/explore" variant="link" color="gray">
|
||||||
Explore
|
Explore
|
||||||
</Button>
|
</Button>
|
||||||
<Button as={Link} to="/mint" variant="link" color="gray">
|
<Button as={Link} to="/mint" variant="link" color="gray">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Flex } from '@/components';
|
||||||
|
import { dripStitches } from '@/theme';
|
||||||
|
|
||||||
|
const { styled } = dripStitches;
|
||||||
|
|
||||||
|
export abstract class Explore {
|
||||||
|
static readonly Container = styled(Flex, {
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '64.75rem', //TODO replace for max-width
|
||||||
|
margin: '0 auto',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Header } from './header';
|
||||||
|
import { Explore as ES } from './explore.styles';
|
||||||
|
import { ListNfas } from './list-nfas/list-nfas';
|
||||||
|
|
||||||
|
export const Explore: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<ES.Container>
|
||||||
|
<Header />
|
||||||
|
<ListNfas />
|
||||||
|
</ES.Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Flex } from '@/components';
|
||||||
|
import { dripStitches } from '@/theme';
|
||||||
|
|
||||||
|
const { styled } = dripStitches;
|
||||||
|
|
||||||
|
export abstract class Header {
|
||||||
|
static readonly Container = styled(Flex, {
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '$6',
|
||||||
|
my: '$16',
|
||||||
|
});
|
||||||
|
|
||||||
|
static readonly Text = styled('h2', {
|
||||||
|
fontSize: '$4xl',
|
||||||
|
maxWidth: '46rem',
|
||||||
|
});
|
||||||
|
|
||||||
|
static readonly GrayText = styled('span', {
|
||||||
|
color: '$slate11',
|
||||||
|
});
|
||||||
|
|
||||||
|
static readonly WhiteText = styled('span', {
|
||||||
|
color: '$slate12',
|
||||||
|
});
|
||||||
|
|
||||||
|
static readonly ButtonContainer = styled(Flex, {
|
||||||
|
gap: '$3',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Button } from '@/components';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Header as HS } from './header.styles';
|
||||||
|
export const Header = () => (
|
||||||
|
<HS.Container>
|
||||||
|
<HS.Text>
|
||||||
|
<HS.GrayText>
|
||||||
|
Created with a focus on decentralizing your applications,
|
||||||
|
</HS.GrayText>
|
||||||
|
<HS.WhiteText> NFAs are the only thing you need.</HS.WhiteText>
|
||||||
|
</HS.Text>
|
||||||
|
<HS.ButtonContainer>
|
||||||
|
<Button as={Link} to="/mint" colorScheme="blue" variant="outline">
|
||||||
|
Create an NFA
|
||||||
|
</Button>
|
||||||
|
{/* TODO replace with create ap route */}
|
||||||
|
<Button as={Link} to="/" colorScheme="gray" variant="outline">
|
||||||
|
Host an Access Point
|
||||||
|
</Button>
|
||||||
|
</HS.ButtonContainer>
|
||||||
|
</HS.Container>
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './explore';
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Flex } from '@/components';
|
||||||
|
import { NFAList } from './nfa-list';
|
||||||
|
import { ResultsSearch } from './results-search';
|
||||||
|
|
||||||
|
export const ListNfas: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<Flex css={{ flexDirection: 'column' }}>
|
||||||
|
<ResultsSearch />
|
||||||
|
<NFAList />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -52,7 +52,7 @@ export const NFAList = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex css={{ flexDirection: 'column', my: '$5', gap: '$2' }}>
|
<Flex css={{ flexDirection: 'column', gap: '$2' }}>
|
||||||
<Flex css={{ gap: '$2' }}>
|
<Flex css={{ gap: '$2' }}>
|
||||||
{/* TODO this will be remove when we have pagination component */}
|
{/* TODO this will be remove when we have pagination component */}
|
||||||
<span>items per page: {pageSize}</span>
|
<span>items per page: {pageSize}</span>
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Dropdown, DropdownItem, Flex, Input } from '@/components';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { ResultsContainer, ResultsNumber, ResultsText } from './results.styles';
|
||||||
|
|
||||||
|
const orderResults: DropdownItem[] = [
|
||||||
|
{ value: 'a-z', label: 'Sort A-Z' },
|
||||||
|
{ value: 'z-a', label: 'Sort Z-A' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ResultsSearch: React.FC = () => {
|
||||||
|
const [selectedValue, setSelectedValue] = useState<DropdownItem>(
|
||||||
|
orderResults[0]
|
||||||
|
); //TODO replace for context
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex css={{ justifyContent: 'space-between' }}>
|
||||||
|
<ResultsContainer>
|
||||||
|
<ResultsText>All NFAs </ResultsText>
|
||||||
|
<ResultsNumber>(3,271)</ResultsNumber>
|
||||||
|
</ResultsContainer>
|
||||||
|
<Flex css={{ gap: '$3' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="Search"
|
||||||
|
leftIcon="search"
|
||||||
|
css={{ width: '23rem' }}
|
||||||
|
/>
|
||||||
|
<Dropdown
|
||||||
|
items={orderResults}
|
||||||
|
selectedValue={selectedValue}
|
||||||
|
onChange={setSelectedValue}
|
||||||
|
backgroundColor="slate4"
|
||||||
|
textColor="slate11"
|
||||||
|
optionsWidth="40"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { dripStitches } from '@/theme';
|
||||||
|
|
||||||
|
const { styled } = dripStitches;
|
||||||
|
|
||||||
|
export const ResultsContainer = styled('div', {
|
||||||
|
fontSize: '$xl',
|
||||||
|
fontWeight: '$bold',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ResultsText = styled('span', {
|
||||||
|
color: '$slate12',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ResultsNumber = styled('span', {
|
||||||
|
color: '$slate11',
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { Flex } from '@/components';
|
import { Flex } from '@/components';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { NFAList } from './nfa-list/nfa-list';
|
|
||||||
|
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -9,7 +8,6 @@ export const Home = () => {
|
||||||
<Link to="/mint">
|
<Link to="/mint">
|
||||||
<u>Mint NFA!</u>
|
<u>Mint NFA!</u>
|
||||||
</Link>
|
</Link>
|
||||||
<NFAList />
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './home';
|
export * from './home';
|
||||||
export * from './mint';
|
export * from './mint';
|
||||||
export * from './components-test';
|
export * from './components-test';
|
||||||
|
export * from './explore';
|
||||||
export * from './access-point';
|
export * from './access-point';
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,19 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ['./src/**/*.tsx'],
|
content: ['./src/**/*.tsx'],
|
||||||
|
safelist: [
|
||||||
|
{
|
||||||
|
pattern: /(bg|border|text)-(slate)(4|11|12)/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /w-(0|[1-9][0-9]?|100)/,
|
||||||
|
},
|
||||||
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
//TODO if we're gonna have ligth mode we should add also the light colors cause tailwind doesn't have them
|
//TODO if we're gonna have ligth mode we should add also the light colors cause tailwind doesn't have them
|
||||||
|
slate4: 'rgba(38, 41, 43, 1)',
|
||||||
slate5: 'rgba(43, 47, 49, 1)',
|
slate5: 'rgba(43, 47, 49, 1)',
|
||||||
slate6: 'rgba(49, 53, 56, 1)',
|
slate6: 'rgba(49, 53, 56, 1)',
|
||||||
slate7: 'rgba(58, 63, 66, 1)',
|
slate7: 'rgba(58, 63, 66, 1)',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue