@chakra-ui/react#SimpleGrid TypeScript Examples
The following examples show how to use
@chakra-ui/react#SimpleGrid.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DimensionPanel.tsx From openchakra with MIT License | 6 votes |
DimensionPanel = () => {
const { setValueFromEvent } = useForm()
const overflow = usePropsSelector('overflow')
return (
<>
<SimpleGrid columns={2} spacing={1}>
<TextControl hasColumn label="Width" name="width" />
<TextControl hasColumn label="Height" name="height" />
</SimpleGrid>
<SimpleGrid columns={2} spacing={1}>
<TextControl hasColumn label="Min W" name="minWidth" />
<TextControl hasColumn label="Min H" name="minHeight" />
<TextControl hasColumn label="Max W" name="maxWidth" />
<TextControl hasColumn label="Max H" name="maxHeight" />
</SimpleGrid>
<FormControl label="Overflow">
<Select
size="sm"
value={overflow || ''}
onChange={setValueFromEvent}
name="overflow"
>
<option>visible</option>
<option>hidden</option>
<option>scroll</option>
</Select>
</FormControl>
</>
)
}
Example #2
Source File: index.tsx From ksana.in with Apache License 2.0 | 6 votes |
export function Features() {
return (
<Container maxW={'5xl'} mx="auto" as="section" mt="16">
<Stack p={4} spacing="16">
<Heading textAlign="center" as="h3">
Fitur Kunci Ksana.in
</Heading>
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={10}>
<Feature
icon={<Icon as={FcLink} w={10} h={10} />}
title={'Mempercantik Tautan'}
text={'Tidak perlu lagi mengingat tautan yang panjang, pesan tautan dambaanmu sekarang'}
/>
<Feature
icon={<Icon as={FcTreeStructure} w={10} h={10} />}
title={'Bagikan Tautan'}
text={
'Sangat mudah membagikan tautan ke berbagai sosial media dan pesan instan, langsung dari halaman dashboard'
}
/>
<Feature
icon={<Icon as={FcBullish} w={10} h={10} />}
title={'Pantau Statistik'}
text={'Pantau jumlah pengguna yang mengunjungi tautanmu dengan mudah'}
/>
</SimpleGrid>
</Stack>
</Container>
)
}
Example #3
Source File: offline-data.tsx From portfolio with MIT License | 6 votes |
OfflineData = () => {
return (
<PageSlideFade>
<StaggerChildren>
<SimpleGrid columns={[2, 2, 3]} spacing={4} mt={12}>
{repositories.map((repo, index) => (
<MotionBox whileHover={{ y: -5 }} key={index}>
<RepositoryCard
key={index}
title={repo.title}
description={repo.description}
cover={repo.cover}
blurHash={repo.blurHash}
technologies={repo.technologies}
url={repo.url}
live={repo.live}
stars={repo.stars}
fork={repo.fork}
/>
</MotionBox>
))}
</SimpleGrid>
</StaggerChildren>
</PageSlideFade>
);
}
Example #4
Source File: projects.tsx From portfolio with MIT License | 6 votes |
Projects: React.FC<ProjectsProps> = ({ projects }) => {
return (
<VStack align="start" spacing={8}>
<Header underlineColor={ORANGE} mt={0} mb={0}>
Projects
</Header>
<AnimateSharedLayout>
<SimpleGrid columns={1} spacing={4} mt={5} w="100%">
{projects.map((project, index) => (
<MotionBox whileHover={{ y: -5 }} key={index}>
<ProjectCard
key={project.id}
title={project.title}
description={project.desc}
blurHash={project.blurHash}
logo={project.logo}
link={project.link}
technologies={project.technologies}
/>
</MotionBox>
))}
</SimpleGrid>
</AnimateSharedLayout>
</VStack>
);
}
Example #5
Source File: index.tsx From ksana.in with Apache License 2.0 | 6 votes |
export default function BlogIndex({ data }: IBlogProps) {
return (
<Layout>
<MetaHead
title="Beranda Blog | Ksana.in"
description="Ksana.in adalah layanan pemendek tautan / URL yang gratis dan mudah untuk digunakan, buatan asli anak Indonesia"
/>
<VStack spacing={4} textAlign="center" as="section" mt="32">
<VStack spacing={4} textAlign="center">
<Heading
as="h1"
fontWeight={700}
fontSize={{ base: '3xl', sm: '4xl', md: '5xl' }}
lineHeight={'110%'}
color="orange.400"
>
Blog Ksana.in
</Heading>
</VStack>
</VStack>
<Container maxW={'4xl'} mx="auto" as="section" mt="8">
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={8} py={4}>
{data &&
data.length > 0 &&
data.map((post: IPost) => <BlogCardPost key={post.slug} post={post} />)}
</SimpleGrid>
</Container>
</Layout>
)
}
Example #6
Source File: repositories-list.tsx From notebook with MIT License | 5 votes |
RepositoriesList = () => {
return (
<>
<AnimatePage>
<Box minH={"50vh"}>
<Flex p="2" justifyContent="center">
<Heading
as="h1"
size="xl"
bgGradient="linear(to-l, #7928CA, #FF0080)"
bgClip="text"
_focus={{ boxShadow: "none", outline: "none" }}
_hover={{
textDecoration: "none",
bgGradient: "linear(to-r, red.500, yellow.500)"
}}
>
Repositories
</Heading>
</Flex>
{/* <SlideFade in={true} offsetY="50vh"> */}
<SimpleGrid
columns={[1, 2, 2, 3]}
mt="40px"
gridGap="10px"
position="relative"
overflow="hidden"
>
{repositoriesList.map((repo, index) => (
<motion.div whileHover={{ y: -10 }} key={index}>
<RepositoriesListItem repo={repo} />
</motion.div>
))}
</SimpleGrid>
{/* </SlideFade> */}
</Box>
</AnimatePage>
</>
);
}
Example #7
Source File: live-data.tsx From portfolio with MIT License | 5 votes |
LiveData = () => {
const { get, loading, error, data } = useFetch("https://api.github.com");
const [repos, setRepos] = useState([]);
const [isLargerThan720] = useMediaQuery("(min-width: 720px)");
const [isLargerThan982] = useMediaQuery("(min-width: 982px)");
let columnWidth = 390;
if (isLargerThan982) {
columnWidth = 390;
} else {
if (isLargerThan720) {
columnWidth = 300;
} else {
columnWidth = "100%";
}
}
useEffect(() => {
get("/users/MA-Ahmad/repos").then(res => {
setRepos(
res?.sort((a, b) => b.stargazers_count - a.stargazers_count).slice(0, 8)
);
});
}, []);
return (
<PageSlideFade>
{loading ? (
<SimpleGrid columns={[1, 1, 2]} spacing={4} mt={4}>
<CardSkeleton />
</SimpleGrid>
) : (
<Box mt={4}>
<StackGrid columnWidth={columnWidth}>
{repos?.map((repo, index) => (
<RepositoryCard
title={repo.name}
description={repo.description}
language={repo.language}
url={repo.svn_url}
created_at={repo.created_at}
stargazers_count={repo.stargazers_count}
forks_count={repo.forks_count}
/>
))}
</StackGrid>
</Box>
)}
</PageSlideFade>
);
}
Example #8
Source File: App.tsx From engine with MIT License | 5 votes |
App: view = ({
data = observe.structure.data,
viewsCount = observe.structure.count.views,
producersCount = observe.structure.count.producers,
}) => {
if (!data || !viewsCount || !producersCount) {
return;
}
return (
<ChakraProvider>
<SimpleGrid columns={2}>
<Box bg="gray.100" h="100vh">
<Tabs>
<TabList position="relative">
<Tab>State</Tab>
<Tab>
Views <Tag>{viewsCount}</Tag>
</Tab>
<Tab>
Producers <Tag>{producersCount}</Tag>
</Tab>
<Tab>Stats</Tab>
</TabList>
<TabPanels>
<TabPanel pr="0">
<List>
<Box overflowY="scroll" h="92vh">
<StateTree data={data} />
</Box>
</List>
</TabPanel>
<TabPanel pr="0">
<ViewsTab />
</TabPanel>
<TabPanel pr="0">
<ProducersTab />
</TabPanel>
<TabPanel pr="0">
<StatsTab />
</TabPanel>
</TabPanels>
</Tabs>
</Box>
<Box bg="gray.200" borderLeft="solid 1px" borderColor="gray.300">
<EditElement />
<ElementDescription />
</Box>
</SimpleGrid>
</ChakraProvider>
);
}
Example #9
Source File: ColorPicker.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
ColorPicker = ({ colors, selectedColor, changeCallback }: ColorPickerProps) => {
const [color, setColor] = useState(selectedColor ?? colors[0]);
const handleColorInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
handleColorChange(e.target.value);
};
const handleColorChange = (color: string) => {
setColor(color);
if (typeof changeCallback === 'function') changeCallback(color);
};
return (
<>
<Popover variant="picker">
<PopoverTrigger>
<Button
aria-label={color}
background={color}
height="64px"
width="64px"
padding={0}
minWidth="unset"
borderRadius={3}
></Button>
</PopoverTrigger>
<PopoverContent width="196px">
<PopoverArrow bg={color} />
<PopoverCloseButton color="white" />
<PopoverHeader
height="100px"
backgroundColor={color}
borderTopLeftRadius={5}
borderTopRightRadius={5}
color="white"
>
<Center height="100%">{color}</Center>
</PopoverHeader>
<PopoverBody height="96px">
<SimpleGrid columns={5} spacing={2}>
{colors.map(c => (
<Button
key={c}
aria-label={c}
background={c}
height="32px"
width="32px"
padding={0}
minWidth="unset"
borderRadius={3}
_hover={{ background: c }}
onClick={() => {
handleColorChange(c);
}}
></Button>
))}
</SimpleGrid>
<Input
borderRadius={3}
marginTop={3}
placeholder="red.100"
size="sm"
value={color}
onChange={handleColorInputChange}
/>
</PopoverBody>
</PopoverContent>
</Popover>
</>
);
}
Example #10
Source File: Controls.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
Controls = () => {
const [, forceUpdate] = React.useReducer((i) => i + 1, 0);
const [ selectedKey, setSelectedKey ] = React.useState<number>();
const controlsManager = ControlsManager.getInstance();
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (!selectedKey) return;
controlsManager.setKey(selectedKey, e.keyCode);
setSelectedKey(undefined);
forceUpdate();
console.log(selectedKey);
}
document.addEventListener('keydown', onKeyDown);
return () => {
document.removeEventListener('keydown', onKeyDown);
}
}, [selectedKey]);
return (
<div>
<Text fontSize="2xl" paddingBottom="0px">
Player
</Text>
<SimpleGrid columns={2} spacing={5} paddingBottom="2">
{
Object.keys(controlsManager.playerKeys).map((key, i) =>
<Key key={i} keyName={key.charAt(0).toUpperCase() + key.slice(1)} keyCode={(controlsManager.playerKeys as any)[key]} selectedKey={selectedKey} onSelect={setSelectedKey} />)
}
</SimpleGrid>
<Text fontSize="2xl" paddingBottom="0px">
Misc
</Text>
<SimpleGrid columns={2} spacing={5}>
<Key keyName="Chat" keyCode={controlsManager.chatKey} selectedKey={selectedKey} onSelect={setSelectedKey} />
<Key keyName="Settings" keyCode={controlsManager.settingsKey} selectedKey={selectedKey} onSelect={setSelectedKey} />
</SimpleGrid>
</div>
)
}
Example #11
Source File: Hustlers.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
Hustlers = () => {
const [hustlers, setHustlers] = React.useState<any>();
useEffect(() => {
if (!(window.ethereum as any)?.selectedAddress) return;
fetch(`https://api.dopewars.gg/wallets/${ethers.utils.getAddress(
(window.ethereum as any).selectedAddress,
)}/hustlers`).then(res => res.json()).then(res => setHustlers(res));
}, []);
return (
<div>
{hustlers ? <SimpleGrid columns={2} spacing={5} paddingBottom="8">
{
hustlers.map((hustler: any, i: number) =>
<VStack key={i}>
<Text paddingBottom="0px">
{hustler.id} {hustler.name ? " - " + hustler.name : ""}
</Text>
<object width="70%" type="image/svg+xml" data={hustler.svg} />
{ localStorage.getItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`) !== hustler.id ? <Popover>
<PopoverTrigger>
<Button variant="primary">
Set as selected hustler
</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Are you sure?</PopoverHeader>
<PopoverBody>The game needs to be reloaded in order to modify your selected hustler</PopoverBody>
<PopoverFooter>
<Button variant="primary" onClick={() => {
localStorage.setItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`, hustler.id);
window.location.reload();
}}>
Confirm
</Button>
</PopoverFooter>
</PopoverContent>
</Popover> : undefined }
</VStack>
)
}
</SimpleGrid> : <Center padding="4">
<Spinner size="lg"/>
</Center>
}
<Center>
<a href="/inventory">
<Button variant="primary">
Details
</Button>
</a>
</Center>
</div>
)
}
Example #12
Source File: Hero.tsx From ksana.in with Apache License 2.0 | 5 votes |
export function Hero() {
const textColor = useColorModeValue('gray.500', 'gray.300')
return (
<Box w={'full'}>
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={10}>
<Container maxW={'6xl'} as="section" mt="32">
<VStack spacing={{ base: 8, md: 10 }} px={{ base: 8, md: 10 }}>
<Heading
as="h2"
textAlign="center"
fontWeight={700}
fontSize={{ base: '4xl', sm: '5xl', md: '6xl' }}
lineHeight={'110%'}
>
Pemendek tautan yang{' '}
<Text color="orange.400" as="span">
mudah
</Text>{' '}
dan{' '}
<Text color="orange.400" as="span">
gratis
</Text>
</Heading>
<Text
as="span"
textAlign="center"
color={textColor}
fontSize={{ base: 'lg', sm: 'xl', md: '2xl' }}
lineHeight={'110%'}
>
Percantik tautanmu, jadikan agar mudah diingat, bagikan ke orang lain dengan percaya
diri
</Text>
<Button
size="lg"
rounded="full"
px={6}
color={'white'}
bg="orange.400"
_hover={{
bg: 'orange.500'
}}
as={'a'}
href={login}
leftIcon={<HiPlay />}
>
Coba sekarang
</Button>
</VStack>
</Container>
<Flex as="section" mt={{ base: 0, md: 20 }} justifyContent="center">
<Image
width={400}
height={400}
src={'/images/illustrations/ill_by_manypixels.svg'}
alt="Women with Internet"
priority={true}
/>
</Flex>
</SimpleGrid>
</Box>
)
}
Example #13
Source File: Items.tsx From ksana.in with Apache License 2.0 | 4 votes |
export function Items({ user, isFormVisible, onShowForm }: IUrlListProps) {
const { data, isLoading = true } = useUrls(user?.id || '')
const [searchText, setSearchText] = useState<string>('')
const [view, setView] = useState<string>(VIEW.LIST)
const [filteredData, setFilteredData] = useState<IUrl[]>(data)
useEffect(() => {
if (!isLoading) {
if (searchText === '') {
setFilteredData(data)
} else if (searchText && searchText.length > 1) {
const foundData = data.filter((d: IUrl) => {
const containUrl = d.real_url.toLowerCase().includes(searchText.toLowerCase())
const containSlug = d.slug.toLowerCase().includes(searchText.toLowerCase())
return containSlug || containUrl
})
setFilteredData(foundData)
}
}
}, [isLoading, searchText, data])
if (isLoading) {
return <LoadingSkeleton />
}
const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value)
}
const isGrid = view === VIEW.GRID
const isList = view === VIEW.LIST
const handleViewGrid = () => {
setView(VIEW.GRID)
}
const handleViewList = () => {
setView(VIEW.LIST)
}
return (
<>
{!isLoading && data && data.length > 0 ? (
<>
<TotalStats data={data} />
<SearchInput onChangeSearch={handleSearch} searchText={searchText} />
<Flex justifyContent="flex-end" alignItems="center">
<ButtonGroup spacing="2" variant="outline">
<IconButton
variant="outline"
borderColor={'orange.400'}
color="orange.400"
_hover={{
bg: 'orange.200'
}}
_focus={{
bg: 'orange.200'
}}
_active={{
bg: 'orange.400',
color: 'white'
}}
aria-label="View Grid"
isActive={isGrid}
onClick={handleViewGrid}
icon={<HiViewGrid />}
/>
<IconButton
variant="outline"
borderColor={'orange.400'}
color="orange.400"
_hover={{
bg: 'orange.200'
}}
_focus={{
bg: 'orange.200'
}}
_active={{
bg: 'orange.400',
color: 'white'
}}
aria-label="View List"
isActive={isList}
onClick={handleViewList}
icon={<HiViewList />}
/>
</ButtonGroup>
</Flex>
{filteredData.length > 0 ? (
<SimpleGrid columns={isGrid ? 2 : 1} spacing={2}>
{filteredData.map((urlItem: IUrl) => (
<Item data={urlItem} user={user} key={urlItem.id} />
))}
</SimpleGrid>
) : (
<ErrorDataNotFound
useCta={false}
title="Tidak menemukan apapun nih, coba kata kunci lain!"
/>
)}
</>
) : (
<>{!isFormVisible ? <ErrorDataNotFound useCta ctaAction={onShowForm} /> : null}</>
)}
</>
)
}
Example #14
Source File: Music.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
Music = (props: {
musicManager: MusicManager
}) => {
const [, forceUpdate] = React.useReducer((i) => i + 1, 0);
const [ songProgress, setSongProgress ] = React.useState(props.musicManager.currentSong?.song.seek);
React.useEffect(() => {
let intervalId: NodeJS.Timer;
if (props.musicManager.currentSong)
intervalId = setInterval(() => {
setSongProgress(props.musicManager.currentSong!.song.seek);
});
return () => {
clearInterval(intervalId);
}
}, []);
console.log(props.musicManager.soundManager.volume);
return (
<div>
<HStack style={{
alignItems: "stretch",
marginBlock: "1rem",
}}>
{
props.musicManager.currentSong &&
<Container style={{
padding: "0.5rem",
minWidth: "60%",
borderRadius: "7px",
backgroundColor: "rgba(255,255,255,0.5)",
}}>
<HStack>
<div style={{
width: "70%"
}}>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Currently playing
</Text>
<Text paddingBottom="0px">
{props.musicManager.currentSong.name}
</Text>
<Slider
value={songProgress}
onChange={(v) => {
props.musicManager.currentSong?.song.setSeek(v);
}}
max={props.musicManager.currentSong!.song.duration}
width="100%"
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb style={{
boxShadow: "none"
}} />
</Slider>
</div>
{
props.musicManager.upcomingSong && <div>
<Text fontWeight="bold" paddingBottom="0px">
Upcoming
</Text>
<Text>
{props.musicManager.upcomingSong.name}
</Text>
</div>
}
</div>
<Spacer />
<VStack>
{
<Button variant="primary" onClick={() => {
props.musicManager.currentSong!.song.isPaused ?
props.musicManager.currentSong!.song.resume() :
props.musicManager.currentSong!.song.pause();
forceUpdate();
}}>
{
props.musicManager.currentSong.song.isPaused ? "Resume" : "Pause"
}
</Button>
}
<Button variant="primary" onClick={() => {
props.musicManager.shuffle(undefined, undefined, false);
forceUpdate();
}}>
Skip
</Button>
</VStack>
</HStack>
</Container>
}
<Container style={{
padding: "0.5rem",
borderRadius: "7px",
minHeight: "100%",
backgroundColor: "rgba(255,255,255,0.5)",
}}>
<div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Volume
</Text>
<Slider
defaultValue={props.musicManager.soundManager.volume * 100}
onChange={(v) => props.musicManager.soundManager.setVolume(v / 100)}
width="70%"
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Rate
</Text>
<Slider
defaultValue={props.musicManager.soundManager.rate * 100}
onChange={(v) => props.musicManager.soundManager.setRate(v / 100)}
width="70%"
max={200}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Detune
</Text>
<Slider
defaultValue={props.musicManager.soundManager.detune}
onChange={(v) => props.musicManager.soundManager.setDetune(v)}
width="70%"
max={1200}
min={-1200}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
</div>
</Container>
</HStack>
<SimpleGrid columns={2} spacing={5} paddingBottom="2">
{
props.musicManager.songs.map((song, i) =>
<SongComponent key={i} song={song} musicManager={props.musicManager} updateState={forceUpdate} />)
}
</SimpleGrid>
</div>
)
}
Example #15
Source File: Footer.tsx From ksana.in with Apache License 2.0 | 4 votes |
export function Footer({ withBacklink }: IFooterProps) {
const boxColor = useColorModeValue('gray.700', 'gray.200')
return (
<Box color={boxColor} as="footer" width="100%">
{withBacklink ? (
<svg
className="waves"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 24 150 28"
preserveAspectRatio="none"
shapeRendering="auto"
>
<defs>
<path
id="gentle-wave"
d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z"
/>
</defs>
<g className="parallax">
<use xlinkHref="#gentle-wave" x="5" y="0" fill="rgba(237, 137, 54, 0.18)" />
<use xlinkHref="#gentle-wave" x="20" y="3" fill="rgba(237, 137, 54, 0.3)" />
<use xlinkHref="#gentle-wave" x="48" y="5" fill="rgba(237, 137, 54, 0.4)" />
<use xlinkHref="#gentle-wave" x="90" y="30" fill="rgba(237, 137, 54, 0.7)" />
</g>
</svg>
) : null}
{withBacklink ? (
<Box width="100%">
<Container maxW={'5xl'}>
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={8} py={4}>
<Stack align={'flex-start'}>
<Text fontWeight="700" color="orange.400" fontSize={'lg'} mb={2}>
Lebih banyak
</Text>
<Link href={tentang}>Tentang Ksana.in</Link>
<Link href={blog}>Blog</Link>
<Link href={login}>Masuk</Link>
</Stack>
<Stack align={'flex-start'}>
<Text fontWeight="700" color="orange.400" fontSize={'lg'} mb={2}>
Kebijakan
</Text>
<Link href={kebijakanPrivasi}>Kebijakan Privasi</Link>
<Link href={ketentuanLayanan}>Ketentuan Layanan</Link>
</Stack>
<Stack align={'flex-start'}>
<Text fontWeight="700" color="orange.400" fontSize={'lg'} mb={2}>
Sumber daya
</Text>
<Link
href="https://github.com/mazipan/ksana.in/issues/new"
target="_blank"
rel="noopener noreferrer"
>
Laporkan Isu
</Link>
<Link href={splitbeeAnalytics} target="_blank" rel="noopener noreferrer">
Statistik Ksana.in
</Link>
<Link
href="https://trakteer.id/mazipan/tip?utm_source=ksana"
target="_blank"
title="Dukung Ksana.in"
rel="noopener noreferrer"
>
Dukung Ksana.in
</Link>
</Stack>
<Stack align={'flex-start'}>
<Text fontWeight="700" color="orange.400" fontSize={'lg'} mb={2}>
Karya lain
</Text>
<Link
href="https://www.baca-quran.id/?utm_source=ksana"
target="_blank"
title="Cek Baca-Quran.id"
rel="noopener noreferrer"
>
Baca-Quran.id
</Link>
<Link
href="https://pramuka.online/?utm_source=ksana"
target="_blank"
title="Cek Pramuka.Online"
rel="noopener noreferrer"
>
Pramuka.Online
</Link>
</Stack>
</SimpleGrid>
</Container>
</Box>
) : null}
<Box bg="orange.400" width="100%">
<Container maxW={'5xl'}>
<Flex
as={Stack}
py={4}
alignItems="center"
direction={{ base: 'column', md: 'row' }}
spacing={4}
justify={{ md: 'space-between' }}
align={{ md: 'center' }}
>
<Text>
© 2021{' '}
<Link href={'/'} textDecoration="underline">
{BRAND}
</Link>{' '}
dibuat oleh{' '}
<Link
textDecoration="underline"
href={'https://mazipan.space/'}
target="_blank"
rel="noopener noreferrer"
>
Irfan Maulana
</Link>
</Text>
</Flex>
</Container>
</Box>
</Box>
)
}
Example #16
Source File: tentang.tsx From ksana.in with Apache License 2.0 | 4 votes |
function About() {
const colorText = useColorModeValue('gray.500', 'gray.300')
const bgBox = useColorModeValue('white', 'gray.800')
return (
<Layout>
<MetaHead
title="Tentang Kami | Ksana.in"
description="Ksana.in adalah layanan pemendek tautan / URL yang gratis dan mudah untuk digunakan, buatan asli anak Indonesia"
/>
<VStack spacing={2} textAlign="center" as="section" mt="32">
<Heading
as="h1"
fontWeight={700}
fontSize={{ base: '3xl', sm: '4xl', md: '5xl' }}
lineHeight={'110%'}
color="orange.400"
>
Tentang Kami
</Heading>
<Image width={200} height={122} src={'/images/orange/ksana.svg'} alt="Ksana.in" />
</VStack>
<Container maxW={'4xl'} mx="auto" as="section" mt="8">
<VStack spacing={4}>
<Text color={colorText}>
{BRAND} adalah layanan pemendek tautan / URL yang gratis dan mudah untuk digunakan.
Layanan ini diinisiasi oleh Irfan Maulana dalam rangka mempelajari layanan baru dari
Supabase.io, membuat sesuatu projek nyata untuk bisa mengimplementasikan langsung apa
yang memang sedang ingin dipelajari.
</Text>
<Text color={colorText}>
{BRAND} tidak bisa dibuat tanpa beberapa layanan dan alat bantu berikut:
</Text>
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={2}>
{tools.map((t: ITools) => (
<Box
key={t.title}
bg={bgBox}
boxShadow={'2xl'}
rounded={'md'}
overflow={'hidden'}
p={6}
>
<Link
href={t.url}
target="_blank"
rel="noopener noreferrer"
color="orange.400"
fontSize={{ base: 'lg', md: 'xl' }}
fontWeight="bold"
>
{t.title}
</Link>
</Box>
))}
</SimpleGrid>
<Text color={colorText}>
{BRAND} dibuat secara terbuka agar bisa dijadikan bahan pembelajaran bersama, semua kode
dan assets tersedia gratis untuk semua pembelajar
</Text>
<HStack
w="80%"
bg={bgBox}
boxShadow={'2xl'}
rounded={'md'}
overflow={'hidden'}
p={6}
spacing={4}
justifyContent="space-between"
wrap="wrap"
>
<Link
href={github}
target="_blank"
rel="noopener noreferrer"
color="orange.400"
fontSize={{ base: 'lg', md: 'xl' }}
fontWeight="bold"
>
ksana.in/gh
</Link>
<ImageChakra
src={'https://img.shields.io/github/stars/mazipan/ksana.in?style=social'}
/>
</HStack>
<Text color={colorText}>
Untuk mendukung saya dan {BRAND} terus berkreasi membuat kode terbuka lainnya, kalian
bisa mengirimkan dana untuk membeli kopi melalui{' '}
<Link
target="_blank"
rel="noopener noreferrer"
color="orange.400"
fontWeight="bold"
href="https://trakteer.id/mazipan/tip?utm_source=ksana"
>
Trakteer.id
</Link>
</Text>
<Text color={colorText} mt="16">
Dari pembuat {BRAND}
{', '}
<Link
target="_blank"
rel="noopener noreferrer"
color="orange.400"
fontWeight="bold"
href="https://mazipan.space"
>
Irfan Maulana
</Link>
</Text>
</VStack>
</Container>
</Layout>
)
}
Example #17
Source File: CustomPropsPanel.tsx From openchakra with MIT License | 4 votes |
CustomPropsPanel = () => {
const dispatch = useDispatch()
const inputRef = useRef<HTMLInputElement>(null)
const activePropsRef = useInspectorState()
const { props, id } = useSelector(getSelectedComponent)
const { setValue } = useForm()
const [quickProps, setQuickProps] = useState('')
const [hasError, setError] = useState(false)
const onDelete = (propsName: string) => {
dispatch.components.deleteProps({
id,
name: propsName,
})
}
const activeProps = activePropsRef || []
const customProps = Object.keys(props).filter(
propsName => !activeProps.includes(propsName),
)
return (
<>
<form
onSubmit={(event: FormEvent) => {
event.preventDefault()
const [name, value] = quickProps.split(SEPARATOR)
if (name && value) {
setValue(name, value)
setQuickProps('')
setError(false)
} else {
setError(true)
}
}}
>
<InputGroup mb={3} size="sm">
<InputRightElement
children={<Box as={IoIosFlash} color="gray.300" />}
/>
<Input
ref={inputRef}
isInvalid={hasError}
value={quickProps}
placeholder={`props${SEPARATOR}value`}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
setQuickProps(event.target.value)
}
/>
</InputGroup>
</form>
{customProps.map((propsName, i) => (
<Flex
key={propsName}
alignItems="center"
px={2}
bg={i % 2 === 0 ? 'white' : 'gray.50'}
fontSize="xs"
justifyContent="space-between"
>
<SimpleGrid width="100%" columns={2} spacing={1}>
<Box fontWeight="bold">{propsName}</Box>
<Box>{props[propsName]}</Box>
</SimpleGrid>
<ButtonGroup display="flex" size="xs" isAttached>
<IconButton
onClick={() => {
setQuickProps(`${propsName}=`)
if (inputRef.current) {
inputRef.current.focus()
}
}}
variant="ghost"
size="xs"
aria-label="edit"
icon={<EditIcon path="" />}
/>
<IconButton
onClick={() => onDelete(propsName)}
variant="ghost"
size="xs"
aria-label="delete"
icon={<SmallCloseIcon path="" />}
/>
</ButtonGroup>
</Flex>
))}
</>
)
}
Example #18
Source File: PaddingPanel.tsx From openchakra with MIT License | 4 votes |
PaddingPanel = ({ type }: PaddingPanelPropsType) => {
const { setValueFromEvent } = useForm()
const all = usePropsSelector(ATTRIBUTES[type].all)
const left = usePropsSelector(ATTRIBUTES[type].left)
const right = usePropsSelector(ATTRIBUTES[type].right)
const bottom = usePropsSelector(ATTRIBUTES[type].bottom)
const top = usePropsSelector(ATTRIBUTES[type].top)
return (
<Box mb={4}>
<FormControl>
<FormLabel fontSize="xs" htmlFor="width" textTransform="capitalize">
{type}
</FormLabel>
<InputGroup size="sm">
<Input
mb={1}
placeholder="All"
size="sm"
type="text"
name={ATTRIBUTES[type].all}
value={all || ''}
onChange={setValueFromEvent}
/>
</InputGroup>
<SimpleGrid columns={2} spacing={1}>
<InputGroup size="sm">
<InputLeftElement
children={
<ArrowBackIcon path="" fontSize="md" color="gray.300" />
}
/>
<Input
placeholder="left"
size="sm"
type="text"
name={ATTRIBUTES[type].left}
value={left || ''}
onChange={setValueFromEvent}
autoComplete="off"
/>
</InputGroup>
<InputGroup size="sm">
<InputLeftElement
children={
<ArrowForwardIcon path="" fontSize="md" color="gray.300" />
}
/>
<Input
placeholder="right"
size="sm"
type="text"
value={right || ''}
name={ATTRIBUTES[type].right}
onChange={setValueFromEvent}
autoComplete="off"
/>
</InputGroup>
<InputGroup size="sm">
<InputLeftElement
children={<ArrowUpIcon path="" fontSize="md" color="gray.300" />}
/>
<Input
placeholder="top"
size="sm"
type="text"
value={top || ''}
name={ATTRIBUTES[type].top}
onChange={setValueFromEvent}
autoComplete="off"
/>
</InputGroup>
<InputGroup size="sm">
<InputLeftElement
children={
<ChevronDownIcon path="" fontSize="md" color="gray.300" />
}
/>
<Input
placeholder="bottom"
size="sm"
type="text"
value={bottom || ''}
name={ATTRIBUTES[type].bottom}
onChange={setValueFromEvent}
autoComplete="off"
/>
</InputGroup>
</SimpleGrid>
</FormControl>
</Box>
)
}
Example #19
Source File: ConnectButton.tsx From eth-dapps-nextjs-boiletplate with MIT License | 4 votes |
export default function ConnectButton({ handleOpenModal }: Props) {
const { globalState, dispatch } = useContext(globalContext)
const [ etherBalance, setEtherBalance ] = useState(0)
const [ loading, setLoading ] = useState(false)
const [ walletConnectLoading, setWalletConnectLoading ] = useState(false)
async function handleConnectWallet(wallet: string) {
wallet === 'WalletConnect' ? setWalletConnectLoading(true) : setLoading(true)
try {
const { account, web3 } = wallet === 'WalletConnect' ?
await handleWalletConnect(dispatch):
await handleInjectedProvider(dispatch)
const balance = await web3.eth.getBalance(account)
console.log('balance', balance)
setEtherBalance(parseInt(balance)/1e18)
} catch (error) {
console.error(error)
} finally {
wallet === 'WalletConnect' ? setWalletConnectLoading(false) : setLoading(false)
}
}
// console.log('globalState', globalState)
return globalState.account ? (
<Box
mt={3}
display="flex"
alignItems="center"
background="gray.700"
borderRadius="xl"
py="0"
>
<Box px="3">
<Text color="white" fontSize="md">
{etherBalance.toFixed(3)} ETH
</Text>
</Box>
<Button
onClick={handleOpenModal}
bg="gray.800"
border="1px solid transparent"
_hover={{
border: "1px",
borderStyle: "solid",
borderColor: "blue.400",
backgroundColor: "gray.700",
}}
borderRadius="xl"
m="1px"
px={3}
height="38px"
>
<Text color="white" fontSize="md" fontWeight="medium" mr="2">
{globalState.account &&
`${globalState.account.slice(0, 6)}...${globalState.account.slice(
globalState.account.length - 4,
globalState.account.length
)}`}
</Text>
<Identicon />
</Button>
</Box>
) : (
<SimpleGrid mt={3} columns={2} spacing={3}>
<Button
isLoading={loading}
spinner={<BeatLoader size={8} color="white" />}
onClick={() => handleConnectWallet('MetaMask')}
bg="blue.800"
color="blue.300"
fontSize="lg"
fontWeight="medium"
borderRadius="xl"
border="1px solid transparent"
_hover={{
borderColor: "blue.700",
color: "blue.400",
}}
_active={{
backgroundColor: "blue.800",
borderColor: "blue.700",
}}
>
Connect with MetaMask
</Button>
<Button
isLoading={walletConnectLoading}
spinner={<BeatLoader size={8} color="white" />}
onClick={() => handleConnectWallet('WalletConnect')}
bg="gray.800"
color="gray.300"
fontSize="lg"
fontWeight="medium"
borderRadius="xl"
border="1px solid transparent"
_hover={{
borderColor: "gray.700",
color: "gray.400",
}}
_active={{
backgroundColor: "gray.800",
borderColor: "gray.700",
}}
>
Connect with WalletConnect
</Button>
</SimpleGrid>
);
}
Example #20
Source File: index.tsx From ledokku with MIT License | 4 votes |
function Home() {
const context = useDocusaurusContext();
const { siteConfig = {} } = context;
return (
<ChakraProvider>
<Layout>
<Container py={20} mb={20} alignContent={'center'} maxW={'4xl'}>
<SimpleGrid
minChildWidth={300}
columns={[4, 2, 2, 2]}
gap={{ md: 6, xs: 2, sm: 2 }}
pt={4}
as="main"
>
<Box>
<Heading
color="gray.700"
fontWeight={'extrabold'}
fontFamily={'sans-serif'}
fontSize={'6xl'}
lineHeight={'110%'}
>
Ledokku
</Heading>
<Heading
color="grey.600"
fontWeight={'bold'}
fontFamily={'sans-serif'}
fontSize={{ base: 'xl', md: 'xl', sm: 'xl', xs: 'l' }}
lineHeight={'110%'}
mb={6}
px={1}
>
Take control of your app deployments
</Heading>
<Divider orientation="horizontal" />
<SimpleGrid mb={10} gap={{ xl: 4, l: 4, sm: 4, xs: 1 }}>
<Heading color="gray.600">Deploy from git</Heading>
<Heading color="gray.500">Link with databases</Heading>
<Heading color="gray.400">Open source</Heading>
<Heading color="gray.300">Save money</Heading>
<Heading color="gray.200">Based on Dokku</Heading>
<SimpleGrid mt={6} columns={16}>
<Image h={6} w={6} src="img/js.png" />
<Image h={6} w={6} src="img/ruby.png" />
<Image h={6} w={6} src="img/golang.png" />
<Image h={6} w={6} src="img/python.png" />
<Image h={6} w={6} src="img/php.png" />
<Image h={6} w={6} src="img/java.png" />
<Image
h={6}
w={6}
src="https://cdn.svgporn.com/logos/scala.svg"
/>
<Image
h={6}
w={6}
src="https://cdn.svgporn.com/logos/clojure.svg"
/>
</SimpleGrid>
</SimpleGrid>
<SimpleGrid mt={12}>
<Link href="/docs/getting-started">
<Button
colorScheme={'white'}
w={'50%'}
bg={'gray.900'}
_hover={{
bg: 'gray.500',
}}
>
Get started
</Button>
</Link>
</SimpleGrid>
</Box>
<Box mt={6}>
<Box w={{ md: 450, sm: 300, xs: 300 }} boxShadow="lg">
<Image src="img/dashboardLanding.png" />
</Box>
<Box
mt={-16}
ml={6}
mr={6}
w={{ md: 400, sm: 250, xs: 250 }}
boxShadow="lg"
>
<Image src="img/terminal.png" />
</Box>
</Box>
</SimpleGrid>
</Container>
</Layout>
</ChakraProvider>
);
}
Example #21
Source File: create-database.tsx From ledokku with MIT License | 4 votes |
CreateDatabase = () => {
const location = useLocation();
const history = useHistory();
const toast = useToast();
const { data: dataDb } = useDatabaseQuery();
const [arrayOfCreateDbLogs, setArrayofCreateDbLogs] = useState<RealTimeLog[]>(
[]
);
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [createDatabaseMutation] = useCreateDatabaseMutation();
const [
isDbCreationSuccess,
setIsDbCreationSuccess,
] = useState<DbCreationStatus>();
useCreateDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.createDatabaseLogs;
if (logsExist) {
setArrayofCreateDbLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (logsExist.type === 'end:success') {
setIsDbCreationSuccess(DbCreationStatus.SUCCESS);
} else if (logsExist.type === 'end:failure') {
setIsDbCreationSuccess(DbCreationStatus.FAILURE);
}
}
},
});
const createDatabaseSchema = yup.object({
type: yup
.string()
.oneOf(['POSTGRESQL', 'MYSQL', 'MONGODB', 'REDIS'])
.required(),
name: yup.string().when('type', (type: DatabaseTypes) => {
return yup
.string()
.required('Database name is required')
.matches(/^[a-z0-9-]+$/)
.test(
'Name already exists',
`You already have created ${type} database with this name`,
(name) =>
!dataDb?.databases.find(
(db) => db.name === name && type === db.type
)
);
}),
});
const [
isDokkuPluginInstalled,
{ data, loading, error: isDokkuPluginInstalledError },
] = useIsPluginInstalledLazyQuery({
// we poll every 5 sec
pollInterval: 5000,
});
const formik = useFormik<{ name: string; type: DatabaseTypes }>({
initialValues: {
name: location.state ? (location.state as string) : '',
type: 'POSTGRESQL',
},
validateOnChange: true,
validationSchema: createDatabaseSchema,
onSubmit: async (values) => {
try {
await createDatabaseMutation({
variables: {
input: { name: values.name, type: values.type },
},
});
setIsTerminalVisible(true);
trackGoal(trackingGoals.createDatabase, 0);
} catch (error) {
toast.error(error.message);
}
},
});
const isPluginInstalled = data?.isPluginInstalled.isPluginInstalled;
const handleNext = () => {
setIsTerminalVisible(false);
const dbId = arrayOfCreateDbLogs[arrayOfCreateDbLogs.length - 1].message;
history.push(`database/${dbId}`);
};
// Effect for checking whether plugin is installed
useEffect(() => {
isDokkuPluginInstalled({
variables: {
pluginName: dbTypeToDokkuPlugin(formik.values.type),
},
});
}, [formik.values.type, isPluginInstalled, isDokkuPluginInstalled]);
// Effect for db creation
useEffect(() => {
isDbCreationSuccess === DbCreationStatus.FAILURE
? toast.error('Failed to create database')
: isDbCreationSuccess === DbCreationStatus.SUCCESS &&
toast.success('Database created successfully');
}, [isDbCreationSuccess, toast]);
return (
<>
<HeaderContainer>
<Header />
</HeaderContainer>
<Container maxW="5xl" my="4">
<Heading as="h2" size="md">
Create a new database
</Heading>
<Box mt="12">
{isTerminalVisible ? (
<>
<Text mb="2">
Creating <b>{formik.values.type}</b> database{' '}
<b>{formik.values.name}</b>
</Text>
<Text mb="2" color="gray.500">
Creating database usually takes a couple of minutes. Breathe in,
breathe out, logs are about to appear below:
</Text>
<Terminal>
{arrayOfCreateDbLogs.map((log) => (
<Text key={arrayOfCreateDbLogs.indexOf(log)} size="small">
{log.message}
</Text>
))}
</Terminal>
{!!isDbCreationSuccess &&
isDbCreationSuccess === DbCreationStatus.SUCCESS ? (
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
onClick={() => handleNext()}
rightIcon={<FiArrowRight size={20} />}
>
Next
</Button>
</Box>
) : !!isDbCreationSuccess &&
isDbCreationSuccess === DbCreationStatus.FAILURE ? (
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
onClick={() => {
setIsTerminalVisible(false);
formik.resetForm();
}}
rightIcon={<FiArrowLeft size={20} />}
>
Back
</Button>
</Box>
) : null}
</>
) : (
<Box mt="8">
<form onSubmit={formik.handleSubmit}>
<Box mt="12">
{loading && (
<Center>
<Spinner />
</Center>
)}
{isDokkuPluginInstalledError ? (
<Alert
status="error"
variant="top-accent"
flexDirection="column"
alignItems="flex-start"
borderBottomRadius="base"
boxShadow="md"
>
<AlertTitle mr={2}>Request failed</AlertTitle>
<AlertDescription>
{isDokkuPluginInstalledError.message}
</AlertDescription>
</Alert>
) : null}
{data?.isPluginInstalled.isPluginInstalled === false &&
!loading && (
<>
<Text mt="3">
Before creating a{' '}
<b>{formik.values.type.toLowerCase()}</b> database,
you will need to run this command on your dokku
server.
</Text>
<Terminal>{`sudo dokku plugin:install https://github.com/dokku/dokku-${dbTypeToDokkuPlugin(
formik.values.type
)}.git ${dbTypeToDokkuPlugin(
formik.values.type
)}`}</Terminal>
<Text mt="3">
Couple of seconds later you will be able to proceed
further.
</Text>
</>
)}
{data?.isPluginInstalled.isPluginInstalled === true &&
!loading && (
<SimpleGrid columns={{ sm: 1, md: 3 }}>
<FormControl
id="name"
isInvalid={Boolean(
formik.errors.name && formik.touched.name
)}
>
<FormLabel>Database name</FormLabel>
<Input
autoComplete="off"
id="name"
name="name"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<FormErrorMessage>
{formik.errors.name}
</FormErrorMessage>
</FormControl>
</SimpleGrid>
)}
</Box>
<Box mt="12">
<Text mb="2">Choose your database</Text>
<Grid
templateColumns={{
base: 'repeat(2, minmax(0, 1fr))',
md: 'repeat(4, minmax(0, 1fr))',
}}
gap="4"
>
<DatabaseBox
selected={formik.values.type === 'POSTGRESQL'}
label="PostgreSQL"
icon={<PostgreSQLIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'POSTGRESQL')}
/>
<DatabaseBox
selected={formik.values.type === 'MYSQL'}
label="MySQL"
icon={<MySQLIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'MYSQL')}
/>
<DatabaseBox
selected={formik.values.type === 'MONGODB'}
label="Mongo"
icon={<MongoIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'MONGODB')}
/>
<DatabaseBox
selected={formik.values.type === 'REDIS'}
label="Redis"
icon={<RedisIcon size={40} />}
onClick={() => formik.setFieldValue('type', 'REDIS')}
/>
</Grid>
</Box>
<Box mt="12" display="flex" justifyContent="flex-end">
<Button
isLoading={formik.isSubmitting}
disabled={
data?.isPluginInstalled.isPluginInstalled === false ||
!formik.values.name ||
!!formik.errors.name ||
!dataDb?.databases
}
rightIcon={<FiArrowRight size={20} />}
type="submit"
>
Create
</Button>
</Box>
</form>
</Box>
)}
</Box>
</Container>
</>
);
}
Example #22
Source File: AddAppProxyPorts.tsx From ledokku with MIT License | 4 votes |
AddAppProxyPorts = ({
appId,
appProxyPortsRefetch,
open,
onClose,
}: AddAppProxyPortsProps) => {
const [addAppProxyPortMutation] = useAddAppProxyPortMutation();
const toast = useToast();
const formik = useFormik<{ host: string; container: string }>({
initialValues: {
host: '',
container: '',
},
validateOnChange: true,
validationSchema: createAppProxyPortSchema,
onSubmit: async (values) => {
try {
await addAppProxyPortMutation({
variables: {
input: {
appId,
host: values.host,
container: values.container,
},
},
});
await appProxyPortsRefetch();
toast.success('Port mapping created successfully');
onClose();
} catch (error) {
toast.error(error.message);
}
},
});
if (!open) {
return null;
}
return (
<Modal isOpen={open} onClose={onClose} isCentered size="xl">
<ModalOverlay />
<ModalContent>
<ModalHeader>Add port mapping</ModalHeader>
<ModalCloseButton />
<ModalBody>
<SimpleGrid columns={{ sm: 1, md: 2 }} spacing={3}>
<FormControl
id="host"
isInvalid={Boolean(formik.errors.host && formik.touched.host)}
>
<FormLabel>Host port:</FormLabel>
<Input
name="host"
value={formik.values.host}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<FormErrorMessage>{formik.errors.host}</FormErrorMessage>
</FormControl>
<FormControl
id="container"
isInvalid={Boolean(
formik.errors.container && formik.touched.container
)}
>
<FormLabel>Container port:</FormLabel>
<Input
name="container"
value={formik.values.container}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<FormErrorMessage>{formik.errors.container}</FormErrorMessage>
</FormControl>
</SimpleGrid>
</ModalBody>
<ModalFooter>
<Button mr={3} onClick={onClose}>
Cancel
</Button>
<Button
colorScheme="red"
isLoading={formik.isSubmitting}
onClick={() => formik.handleSubmit()}
>
Create
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
Example #23
Source File: FcmLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
FcmLayout = (): JSX.Element => {
const dispatch = useAppDispatch();
const alertRef = useRef(null);
const confirmationActions: NodeJS.Dict<any> = {
clearConfiguration: {
message: (
'Are you sure you want to clear your FCM Configuration?<br /><br />' +
'Doing so will prevent notifications from being delivered until ' +
'your configuration is re-loaded'
),
func: async () => {
const success = await clearFcmConfiguration();
if (success) {
dispatch(setConfig({ name: 'fcm_client', 'value': null }));
dispatch(setConfig({ name: 'fcm_server', 'value': null }));
}
}
}
};
const serverLoaded = (useAppSelector(state => state.config.fcm_server !== null) ?? false);
const clientLoaded = (useAppSelector(state => state.config.fcm_client !== null) ?? false);
const [isDragging, setDragging] = useBoolean();
const [errors, setErrors] = useState([] as Array<ErrorItem>);
const [requiresConfirmation, setRequiresConfirmation] = useState(null as string | null);
const alertOpen = errors.length > 0;
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
dragCounter = 0;
setDragging.off();
// I'm not sure why, but we need to copy the file data _before_ we read it using the file reader.
// If we do not, the data transfer file list gets set to empty after reading the first file.
const listCopy: Array<Blob> = [];
for (let i = 0; i < e.dataTransfer.files.length; i++) {
listCopy.push(e.dataTransfer.files.item(i) as Blob);
}
// Actually read the files
const errors: Array<ErrorItem> = [];
for (let i = 0; i < listCopy.length; i++) {
try {
const fileStr = await readFile(listCopy[i]);
const validClient = isValidClientConfig(fileStr);
const validServer = isValidServerConfig(fileStr);
const jsonData = JSON.parse(fileStr);
if (validClient) {
const test = isValidFirebaseUrl(jsonData);
if (test) {
await saveFcmClient(jsonData);
dispatch(setConfig({ name: 'fcm_client', 'value': jsonData }));
} else {
throw new Error(
'Your Firebase setup does not have a real-time database enabled. ' +
'Please enable the real-time database in your Firebase Console.'
);
}
} else if (validServer) {
await saveFcmServer(jsonData);
dispatch(setConfig({ name: 'fcm_server', 'value': jsonData }));
} else {
throw new Error('Invalid Google FCM File!');
}
} catch (ex: any) {
errors.push({ id: String(i), message: ex?.message ?? String(ex) });
}
}
if (errors.length > 0) {
setErrors(errors);
}
};
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (dragCounter === 0) {
setDragging.on();
}
dragCounter += 1;
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.stopPropagation();
e.preventDefault();
};
const onDragLeave = () => {
dragCounter -= 1;
if (dragCounter === 0) {
setDragging.off();
}
};
const closeAlert = () => {
setErrors([]);
};
const confirm = (confirmationType: string | null) => {
setRequiresConfirmation(confirmationType);
};
return (
<Box
p={3}
borderRadius={10}
onDragEnter={(e) => onDragEnter(e)}
onDragLeave={() => onDragLeave()}
onDragOver={(e) => onDragOver(e)}
onDrop={(e) => onDrop(e)}
>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Controls</Text>
<Divider orientation='horizontal' />
<Flex flexDirection="row" justifyContent="flex-start">
<Menu>
<MenuButton
as={Button}
rightIcon={<BsChevronDown />}
width="12em"
mr={5}
>
Manage
</MenuButton>
<MenuList>
<MenuItem icon={<FiTrash />} onClick={() => confirm('clearConfiguration')}>
Clear Configuration
</MenuItem>
</MenuList>
</Menu>
</Flex>
</Stack>
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Configuration</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
Drag and drop your JSON configuration files from your Google Firebase Console. If you
do not have these configuration files. Please go to
<span style={{ color: baseTheme.colors.brand.primary }}>
<Link href='https://bluebubbles.app/install' color='brand.primary' target='_blank'> Our Website </Link>
</span>
to learn how.
</Text>
<Text>
These configurations enable the BlueBubbles server to send notifications and other
messages to all of the clients via Google FCM. Google Play Services is required
for Android Devices.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<SimpleGrid columns={2} spacing={5}>
<DropZone
text="Drag n' Drop Google Services JSON"
loadedText="Google Services JSON Successfully Loaded!"
isDragging={isDragging}
isLoaded={clientLoaded}
/>
<DropZone
text="Drag n' Drop Admin SDK JSON"
loadedText="Admin SDK JSON Successfully Loaded!"
isDragging={isDragging}
isLoaded={serverLoaded}
/>
</SimpleGrid>
</Stack>
<ErrorDialog
errors={errors}
modalRef={alertRef}
onClose={() => closeAlert()}
isOpen={alertOpen}
/>
<ConfirmationDialog
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
onAccept={() => {
if (hasKey(confirmationActions, requiresConfirmation as string)) {
confirmationActions[requiresConfirmation as string].func();
}
}}
isOpen={requiresConfirmation !== null}
/>
</Box>
);
}
Example #24
Source File: tech-stack.tsx From portfolio with MIT License | 4 votes |
TechStack = () => {
const [skillsList, setSkillsList] = useState([]);
React.useEffect(() => {
setSkillsList(skills);
}, []);
const filterSkills = tab => {
console.log(skills.filter(skill => skill.type === tab));
if (tab.length) setSkillsList(skills.filter(skill => skill.type === tab));
else setSkillsList(skills);
};
return (
<PageSlideFade>
<VStack spacing={8}>
<Section>
<VStack>
<Header mt={0} mb={1}>
Tech Stack
</Header>
<Text
fontSize={"xl"}
color={useColorModeValue("gray.500", "gray.200")}
maxW="lg"
textAlign="center"
>
A list of my favorite tools and technologies that I use on a
regular basis.
</Text>
</VStack>
</Section>
<Section>
<Tabs
variant="soft-rounded"
colorScheme="blue"
align="center"
w="100%"
>
<TabList display="flex" flexWrap="wrap">
<Tab
bg={useColorModeValue("gray.100", "gray.800")}
color={useColorModeValue("gray.600", "gray.500")}
_selected={{
color: "green.800",
bg: "green.100"
}}
mr={2}
mt={2}
onClick={() => filterSkills("")}
>
<HStack spacing={1}>
<Icon as={AiTwotoneThunderbolt} weight="fill" />
<Text>All</Text>
</HStack>
</Tab>
<Tab
bg={useColorModeValue("gray.100", "gray.800")}
color={useColorModeValue("gray.500", "gray.500")}
_selected={{
color: useColorModeValue("gray.100", "gray.800"),
bg: useColorModeValue("gray.900", "gray.100")
}}
mr={2}
mt={2}
onClick={() => filterSkills("development")}
>
<HStack spacing={1}>
<Icon as={BiDesktop} weight="fill" />
<Text>Web Development</Text>
</HStack>
</Tab>
<Tab
bg={useColorModeValue("gray.100", "gray.800")}
color={useColorModeValue("gray.600", "gray.500")}
_selected={{
color: "green.800",
bg: "green.100"
}}
mr={2}
mt={2}
onClick={() => filterSkills("design")}
>
<HStack spacing={1}>
<Icon as={GiSpiderWeb} weight="fill" />
<Text>Web Design</Text>
</HStack>
</Tab>
<Tab
bg={useColorModeValue("gray.100", "gray.800")}
color={useColorModeValue("gray.600", "gray.500")}
_selected={{
color: "red.800",
bg: "red.100"
}}
mr={2}
mt={2}
onClick={() => filterSkills("devops")}
>
<HStack spacing={1}>
<Icon as={AiOutlineCloudServer} weight="fill" />
<Text>Devops</Text>
</HStack>
</Tab>
</TabList>
<TabPanels minHeight={"45vh"}>
<TabPanel px={0}>
<MotionBox
variants={container}
initial="hidden"
animate="visible"
>
<SimpleGrid columns={[1, 1, 2]} spacing={4} mt={8}>
{skillsList.map((tool, index) => (
<SkillCard
key={index}
name={tool.name}
description={tool.description}
image={tool.image}
platform={"web"}
link={tool.link}
/>
))}
</SimpleGrid>
</MotionBox>
</TabPanel>
<TabPanel px={0}>
<MotionBox
variants={container}
initial="hidden"
animate="visible"
>
<SimpleGrid columns={[1, 2]} spacing={4} mt={8}>
{skillsList.map((tool, index) => (
<SkillCard
key={index}
name={tool.name}
description={tool.description}
image={tool.image}
platform={"web"}
link={tool.link}
/>
))}
</SimpleGrid>
</MotionBox>
</TabPanel>
<TabPanel px={0}>
<MotionBox
variants={container}
initial="hidden"
animate="visible"
>
<SimpleGrid columns={[1, 2]} spacing={4} mt={8}>
{skillsList.map((tool, index) => (
<SkillCard
key={index}
name={tool.name}
description={tool.description}
image={tool.image}
platform={"web"}
link={tool.link}
/>
))}
</SimpleGrid>
</MotionBox>
</TabPanel>
<TabPanel px={0}>
<MotionBox
variants={container}
initial="hidden"
animate="visible"
>
<SimpleGrid columns={[1, 2]} spacing={4} mt={8}>
{skillsList.map((tool, index) => (
<SkillCard
key={index}
name={tool.name}
description={tool.description}
image={tool.image}
platform={"web"}
link={tool.link}
/>
))}
</SimpleGrid>
</MotionBox>
</TabPanel>
</TabPanels>
</Tabs>
</Section>
</VStack>
</PageSlideFade>
);
}
Example #25
Source File: page-footer.tsx From notebook with MIT License | 4 votes |
export function PageFooter() {
return (
<SimpleGrid
flexDirection="column-reverse"
gridTemplateColumns={["1fr", "1fr", "1fr 1fr", "1fr 1fr"]}
borderTopWidth={2}
mt="30px"
borderTopColor="gray.900"
pt="20px"
>
<Box d={["block", "block", "none", "none"]} mb="30px">
<FooterSignup />
</Box>
<Box>
<SimpleGrid columns={[1, 1, 2, 2]}>
<Stack mb={["10px", "10px", 0, 0]}>
<Text as="span">
<ExternalFooterLink
href={`mailto:${siteConfig.author.email}`}
text="Contact us"
/>
</Text>
<Text as="span">
<ExternalFooterLink
href={siteConfig.repo.url}
text="Contribute"
/>
</Text>
<Text as="span">
<InternalFooterLink
href="/projects"
text="Open source projects"
/>
</Text>
</Stack>
<Stack>
<Text as="span">
<Popover placement="top">
<PopoverTrigger>
<Text
as="span"
_focus={{ outline: "none", boxShadow: "none" }}
fontWeight={500}
color="gray.500"
cursor="pointer"
_hover={{ color: "gray.600", textDecoration: "none" }}
>
Social Accounts
</Text>
</PopoverTrigger>
<Portal>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverBody>
<Stack
as="footer"
isInline
spacing={[1, 2]}
justifyContent="center"
alignItems="center"
>
<ExternalSocialLink
href={siteConfig.author.github}
icon={<FaGithub />}
type="gray"
label="Github Account"
/>
<ExternalSocialLink
href={siteConfig.author.dev}
icon={<FaDev />}
type="gray"
label="Dev Account"
/>
<ExternalSocialLink
href={siteConfig.author.linkedin}
icon={<FaLinkedin />}
type="linkedin"
label="LinkedIn Account"
/>
<ExternalSocialLink
href={siteConfig.author.twitter}
icon={<FaTwitter />}
type="twitter"
label="Twitter Account"
/>
<ExternalSocialLink
href={siteConfig.author.quora}
icon={<FaQuora />}
type="red"
label="Quora Account"
/>
</Stack>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
</Text>
<Text as="span">
<ExternalFooterLink
href={`mailto:${siteConfig.author.email}`}
text="Sponsor"
/>
</Text>
<Text as="span">
<ExternalFooterLink
href={"/#faqs"}
isExternal={false}
text="FAQs"
/>
</Text>
</Stack>
</SimpleGrid>
<Text mt="20px" color="gray.500">
Made with ? by{" "}
<ChakraLink
_focus={{ boxShadow: "none", outline: "none" }}
target="_blank"
href={siteConfig.author.github}
fontWeight={600}
color={"gray.400"}
bgClip="text"
bgGradient="linear(to-l, #7928CA,#FF0080)"
_hover={{
bgGradient: "linear(to-r, red.500, yellow.500)"
}}
>
Muhammad Ahmad
</ChakraLink>{" "}
</Text>
</Box>
<Box d={["none", "none", "block", "block"]}>
<FooterSignup />
</Box>
</SimpleGrid>
);
}
Example #26
Source File: NotificationsWalkthrough.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
NotificationsWalkthrough = (): JSX.Element => {
const dispatch = useAppDispatch();
const alertRef = useRef(null);
const serverLoaded = (useAppSelector(state => state.config.fcm_server !== null) ?? false);
const clientLoaded = (useAppSelector(state => state.config.fcm_client !== null) ?? false);
const [isDragging, setDragging] = useBoolean();
const [errors, setErrors] = useState([] as Array<ErrorItem>);
const alertOpen = errors.length > 0;
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
dragCounter = 0;
setDragging.off();
// I'm not sure why, but we need to copy the file data _before_ we read it using the file reader.
// If we do not, the data transfer file list gets set to empty after reading the first file.
const listCopy: Array<Blob> = [];
for (let i = 0; i < e.dataTransfer.files.length; i++) {
listCopy.push(e.dataTransfer.files.item(i) as Blob);
}
// Actually read the files
const errors: Array<ErrorItem> = [];
for (let i = 0; i < listCopy.length; i++) {
try {
const fileStr = await readFile(listCopy[i]);
const validClient = isValidClientConfig(fileStr);
const validServer = isValidServerConfig(fileStr);
const jsonData = JSON.parse(fileStr);
if (validClient) {
const test = isValidFirebaseUrl(jsonData);
if (test) {
await saveFcmClient(jsonData);
dispatch(setConfig({ name: 'fcm_client', 'value': jsonData }));
} else {
throw new Error(
'Your Firebase setup does not have a real-time database enabled. ' +
'Please enable the real-time database in your Firebase Console.'
);
}
} else if (validServer) {
await saveFcmServer(jsonData);
dispatch(setConfig({ name: 'fcm_server', 'value': jsonData }));
} else {
throw new Error('Invalid Google FCM File!');
}
} catch (ex: any) {
errors.push({ id: String(i), message: ex?.message ?? String(ex) });
}
}
if (errors.length > 0) {
setErrors(errors);
}
};
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (dragCounter === 0) {
setDragging.on();
}
dragCounter += 1;
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.stopPropagation();
e.preventDefault();
};
const onDragLeave = () => {
dragCounter -= 1;
if (dragCounter === 0) {
setDragging.off();
}
};
const closeAlert = () => {
setErrors([]);
};
return (
<SlideFade in={true} offsetY='150px'>
<Box
px={5}
onDragEnter={(e) => onDragEnter(e)}
onDragLeave={() => onDragLeave()}
onDragOver={(e) => onDragOver(e)}
onDrop={(e) => onDrop(e)}
>
<Text fontSize='4xl'>Notifications & Firebase</Text>
<Text fontSize='md' mt={5}>
BlueBubbles utilizes Google FCM (Firebase Cloud Messaging) to deliver notifications to your devices.
We do this so the client do not need to hold a connection to the server at all times. As a result,
BlueBubbles can deliver notifications even when the app is running in the background. It also means
BlueBubbles will use less battery when running in the background.
</Text>
<Alert status='info' mt={5}>
<AlertIcon />
If you do not complete this setup, you will not receive notifications!
</Alert>
<Text fontSize='md' mt={5}>
The setup with Google FCM is a bit tedious, but it is a "set it and forget it" feature. Follow the
instructions here: <Link
as='span'
href='https://bluebubbles.app/install/'
color='brand.primary'
target='_blank'>https://bluebubbles.app/install</Link>
</Text>
<Text fontSize='3xl' mt={5}>Firebase Configurations</Text>
<SimpleGrid columns={2} spacing={5} mt={5}>
<DropZone
text="Drag n' Drop google-services.json"
loadedText="google-services.json Successfully Loaded!"
isDragging={isDragging}
isLoaded={serverLoaded}
/>
<DropZone
text="Drag n' Drop *-firebase-adminsdk-*.json"
loadedText="*-firebase-adminsdk-*.json Successfully Loaded!"
isDragging={isDragging}
isLoaded={clientLoaded}
/>
</SimpleGrid>
</Box>
<ErrorDialog
errors={errors}
modalRef={alertRef}
onClose={() => closeAlert()}
isOpen={alertOpen}
/>
</SlideFade>
);
}
Example #27
Source File: HomeLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
HomeLayout = (): JSX.Element => {
const address = useAppSelector(state => state.config.server_address);
const fcmClient = useAppSelector(state => state.config.fcm_client);
const password = useAppSelector(state => state.config.password);
const port = useAppSelector(state => state.config.socket_port);
const qrCode = fcmClient ? buildQrData(password, address, fcmClient) : null;
return (
<Box p={3} borderRadius={10}>
<Flex flexDirection="column">
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Connection Details</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
This page will detail your current connection details. This includes your
server address and your local port.
</Text>
<br />
<UnorderedList>
<ListItem><strong>Server Address:</strong> This is the address that your clients will connect to</ListItem>
<ListItem><strong>Local Port:</strong> This is the port that the HTTP server is running on,
and the port you will use when port forwarding
for a dynamic DNS
</ListItem>
</UnorderedList>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<Flex flexDirection="row" justifyContent="space-between">
<Stack>
<Flex flexDirection="row" alignItems='center'>
<Text fontSize='md' fontWeight='bold' mr={2}>Server Address: </Text>
{(!address) ? (
<SkeletonText noOfLines={1} />
) : (
<Text fontSize='md'>{address}</Text>
)}
<Tooltip label='Copy Address'>
<IconButton
ml={3}
size='md'
aria-label='Copy Address'
icon={<BiCopy size='22px' />}
onClick={() => copyToClipboard(address)}
/>
</Tooltip>
<Popover placement='bottom' isLazy={true}>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }} >
<Tooltip label='Show QR Code'>
<IconButton
ml={1}
size='md'
aria-label='Show QR Code'
icon={<AiOutlineQrcode size='24px' />}
/>
</Tooltip>
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>QR Code</PopoverHeader>
<PopoverBody>
<Flex justifyContent='center' flexDirection='column' alignItems='center'>
<Text>
Your QR Code contains your server configuration so that clients can connect.
Your QR Code should remain <strong>private</strong> as it contains sensitive information!
</Text>
<Box border="5px solid" borderColor='white' mt={4} height='266px' width='266px' borderRadius='lg' mb={3}>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore: ts2876 */}
{(qrCode) ? <QRCode value={qrCode as string} /> : null}
</Box>
</Flex>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Flex flexDirection="row">
<Text fontSize='md' fontWeight='bold' mr={2}>Local Port: </Text>
{(!port) ? (
<SkeletonText noOfLines={1} />
) : (
<Text fontSize='md'>{port}</Text>
)}
</Flex>
</Stack>
<Divider orientation="vertical" />
</Flex>
</Stack>
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>iMessage Highlights</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
These are just some fun stats that I included to give you a quick "snapshot"
of your iMessage history on the Mac Device. This does not include messages that
are on Apple's servers, only what is local to this device.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
{ /* Delays are so older systems do not freeze when requesting data from the databases */ }
<SimpleGrid columns={3} spacing={5}>
<TotalMessagesStatBox />
<TopGroupStatBox delay={200} />
<BestFriendStatBox delay={400} />
<DailyMessagesStatBox delay={600} />
<TotalPicturesStatBox delay={800} />
<TotalVideosStatBox delay={1000} />
</SimpleGrid>
</Stack>
</Flex>
</Box>
);
}