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 { themeGlobals } from '@/theme/globals';
|
||||
import { ComponentsTest, CreateAP, Home, Mint } from './views';
|
||||
import { MintTest } from './views/mint-test';
|
||||
import { ComponentsTest, Home, Mint, Explore, CreateAP } from './views';
|
||||
import { AppPage, ToastProvider } from './components';
|
||||
|
||||
export const App = () => {
|
||||
|
|
@ -13,12 +12,12 @@ export const App = () => {
|
|||
<AppPage>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/explore" element={<Explore />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/create-ap" element={<CreateAP />} />
|
||||
<Route path="/create-ap/:id" element={<CreateAP />} />
|
||||
{/** TODO remove for release */}
|
||||
<Route path="/components-test" element={<ComponentsTest />} />
|
||||
<Route path="/mint-test" element={<MintTest />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
</Routes>
|
||||
</AppPage>
|
||||
|
|
|
|||
|
|
@ -46,63 +46,132 @@ const DropdownOption = ({ option }: DropdownOptionProps) => (
|
|||
);
|
||||
|
||||
type DropdownButtonProps = {
|
||||
/**
|
||||
* The selected value of the dropdown.
|
||||
*/
|
||||
selectedValue: DropdownItem | undefined;
|
||||
/**
|
||||
* If it's true, the list of options will be displayed
|
||||
*/
|
||||
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) => (
|
||||
<Listbox.Button
|
||||
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
|
||||
? 'border-b-0 rounded-t-xl bg-black border-slate6'
|
||||
: 'rounded-xl bg-transparent'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selectedValue && selectedValue.label ? 'text-slate12' : 'text-slate11'
|
||||
} break-words`}
|
||||
const DropdownButton = ({
|
||||
selectedValue,
|
||||
open, //TODO maybe would be deprecated
|
||||
backgroundColor,
|
||||
textColor,
|
||||
}: DropdownButtonProps) => {
|
||||
const textColorCss = textColor ? `text-${textColor}` : 'text-slate12';
|
||||
const borderColor = backgroundColor
|
||||
? `border-${backgroundColor}`
|
||||
: 'border-slate7';
|
||||
const backgroundColorClass = backgroundColor
|
||||
? `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="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4">
|
||||
<Icon name="chevron-down" />
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
);
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selectedValue && selectedValue.label
|
||||
? `${textColorCss}`
|
||||
: 'text-slate11'
|
||||
} 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 = {
|
||||
/**
|
||||
* The key of the item.
|
||||
*/
|
||||
value: string;
|
||||
/**
|
||||
* The label to display of the item.
|
||||
*/
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type DropdownProps = {
|
||||
/**
|
||||
* List of items to be displayed in the dropdown.
|
||||
*/
|
||||
items: DropdownItem[];
|
||||
/**
|
||||
* The selected value of the dropdown.
|
||||
*/
|
||||
selectedValue: DropdownItem | undefined;
|
||||
/**
|
||||
* Callback when the selected value changes.
|
||||
*/
|
||||
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> = ({
|
||||
items,
|
||||
selectedValue,
|
||||
onChange,
|
||||
backgroundColor,
|
||||
textColor,
|
||||
optionsWidth,
|
||||
}) => {
|
||||
const handleDropdownChange = (option: DropdownItem) => {
|
||||
onChange(option);
|
||||
};
|
||||
const width = optionsWidth ? `w-${optionsWidth}` : 'w-full';
|
||||
|
||||
return (
|
||||
<Listbox value={selectedValue} by="value" onChange={handleDropdownChange}>
|
||||
{({ open }) => (
|
||||
<div className="relative max-w-full">
|
||||
<DropdownButton selectedValue={selectedValue} open={open} />
|
||||
<DropdownButton
|
||||
selectedValue={selectedValue}
|
||||
open={open}
|
||||
backgroundColor={backgroundColor}
|
||||
textColor={textColor}
|
||||
/>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
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) => (
|
||||
<DropdownOption key={option.value} option={option} />
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
<InputStyled
|
||||
{...props}
|
||||
ref={ref}
|
||||
css={{ ...(leftIcon && { pl: '$10' }) }}
|
||||
css={{ ...(leftIcon && { pl: '$10' }), ...(props?.css || {}) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const NavBar: React.FC = () => {
|
|||
<Logo />
|
||||
|
||||
<Styles.Navigation>
|
||||
<Button as={Link} to="/" variant="link" color="gray">
|
||||
<Button as={Link} to="/explore" variant="link" color="gray">
|
||||
Explore
|
||||
</Button>
|
||||
<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 (
|
||||
<Flex css={{ flexDirection: 'column', my: '$5', gap: '$2' }}>
|
||||
<Flex css={{ flexDirection: 'column', gap: '$2' }}>
|
||||
<Flex css={{ gap: '$2' }}>
|
||||
{/* TODO this will be remove when we have pagination component */}
|
||||
<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 { Link } from 'react-router-dom';
|
||||
import { NFAList } from './nfa-list/nfa-list';
|
||||
|
||||
export const Home = () => {
|
||||
return (
|
||||
|
|
@ -9,7 +8,6 @@ export const Home = () => {
|
|||
<Link to="/mint">
|
||||
<u>Mint NFA!</u>
|
||||
</Link>
|
||||
<NFAList />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export * from './home';
|
||||
export * from './mint';
|
||||
export * from './components-test';
|
||||
export * from './explore';
|
||||
export * from './access-point';
|
||||
|
|
|
|||
|
|
@ -3,10 +3,19 @@
|
|||
|
||||
module.exports = {
|
||||
content: ['./src/**/*.tsx'],
|
||||
safelist: [
|
||||
{
|
||||
pattern: /(bg|border|text)-(slate)(4|11|12)/,
|
||||
},
|
||||
{
|
||||
pattern: /w-(0|[1-9][0-9]?|100)/,
|
||||
},
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
//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)',
|
||||
slate6: 'rgba(49, 53, 56, 1)',
|
||||
slate7: 'rgba(58, 63, 66, 1)',
|
||||
|
|
|
|||
Loading…
Reference in New Issue