@chakra-ui/react#Container TypeScript Examples
The following examples show how to use
@chakra-ui/react#Container.
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: HeaderFooterContainer.tsx From coindrop with GNU General Public License v3.0 | 6 votes |
HeaderFooterContainer: FC = ({ children }) => {
const theme = useTheme();
return (
<Container
maxW={theme.breakpoints.xl}
>
{children}
</Container>
);
}
Example #2
Source File: metrics.tsx From ledokku with MIT License | 6 votes |
Metrics = () => {
return (
<div>
<HeaderContainer>
<Header />
<HomeHeaderTabNav />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Heading as="h2" size="md" py={5}>
Metrics
</Heading>
<Text fontSize="sm" color="gray.400">
Coming soon
</Text>
</Container>
</div>
);
}
Example #3
Source File: index.tsx From ksana.in with Apache License 2.0 | 6 votes |
export function CounterUrls() {
const { isLoading, urls } = useCounter()
return (
<Container maxW={'5xl'} mx="auto" as="section" mt="16">
<Stack p={4} spacing="16">
<Heading textAlign="center" as="h3">
Total Tautan
</Heading>
{isLoading && <LoadingSkeleton />}
{!isLoading && <Counter count={urls} />}
</Stack>
</Container>
)
}
Example #4
Source File: Layout.tsx From next-crud with MIT License | 6 votes |
Layout: React.FC<IProps> = ({ title, backRoute, children }) => {
return (
<Box height="100vh">
<Header title={title} backRoute={backRoute} />
<Container mt={4}>
<Center>{children}</Center>
</Container>
</Box>
)
}
Example #5
Source File: ContentContainer.tsx From coindrop with GNU General Public License v3.0 | 6 votes |
ContentContainer: FC<ContentContainerProps> = ({ boxProps, children }) => {
const theme = useTheme();
return (
<Container
my={24}
maxW={theme.breakpoints.xl}
// eslint-disable-next-line react/jsx-props-no-spreading
{...boxProps}
>
{children}
</Container>
);
}
Example #6
Source File: activity.tsx From ledokku with MIT License | 6 votes |
Activity = () => {
return (
<div>
<HeaderContainer>
<Header />
<HomeHeaderTabNav />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Heading as="h2" size="md" py={5}>
Activity
</Heading>
<Text fontSize="sm" color="gray.400">
Coming soon
</Text>
</Container>
</div>
);
}
Example #7
Source File: IntroStepper.tsx From dope-monorepo with GNU General Public License v3.0 | 6 votes |
export default function IntroStepper(props: Props) {
const [ loading, setLoading ] = useState(false);
useEffect(() => {
props.manager.events.on('game', () => setLoading(true));
}, []);
return (
<ChakraProvider theme={theme}>
<Center style={{
height: "100vh",
backdropFilter: "brightness(50%)",
}}>
{loading ? <Spinner size="xl" color="white" /> : <Container style={{
padding: "1rem",
borderStyle: "solid",
boxShadow: "0px 0px 15px rgba(0,0,0,1)",
borderColor: "black",
borderWidth: "0px",
backgroundColor: "white",
borderRadius: "7px",
}}>
{
props.hustlerData?.length > 0 ?
<HasHustler
manager={props.manager}
hustlerData={props.hustlerData}
/> :
<NoHustler
manager={props.manager}
hustlerData={props.hustlerData}
/>
}
</Container>}
</Center>
</ChakraProvider>
);
}
Example #8
Source File: TrackPage.tsx From takeout-app with MIT License | 6 votes |
TrackViewSkeleton: React.FC = () => {
return (
<Container maxW={["auto", "auto", "auto", "1700px"]} px="15px" py="22px">
<Flex alignItems="top" justifyContent="space-between" direction={["column", "column", "column", "row"]}>
<Box w="100%">
<AspectRatio ratio={16 / 9}>
<Skeleton w="100%" h="100%" />
</AspectRatio>
</Box>
<Box maxW={["auto", "auto", "auto", "400px"]} minH="400px" w="100%" ml="30px"></Box>
</Flex>
<Flex alignItems="top" justifyContent="space-between" direction={["column", "column", "column", "row"]} mt="12px">
<Box w="100%">
<Skeleton w="100%" h="100px" />
</Box>
<Box maxW={["auto", "auto", "auto", "400px"]} w="100%" ml="30px" />
</Flex>
</Container>
);
}
Example #9
Source File: faq.tsx From coindrop with GNU General Public License v3.0 | 5 votes |
FAQ: FunctionComponent = () => {
const theme = useTheme();
const panelBgColor = useColorModeValue("gray.50", undefined);
return (
<Box>
<Box my={6}>
<Heading as="h1" textAlign="center">
FAQ
</Heading>
<Text textAlign="center">
Frequently Asked Questions
</Text>
</Box>
<Container maxW={theme.breakpoints.lg}>
<Accordion defaultIndex={-1} allowToggle>
{accordionText.map(({title, body}) => (
<AccordionItem key={title}>
<AccordionButton>
<Box flex="1" textAlign="left">
{title}
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel>
<Box
p={4}
bg={panelBgColor}
>
{body}
</Box>
</AccordionPanel>
</AccordionItem>
))}
</Accordion>
</Container>
<Text textAlign="center" mt={4} fontSize="sm">
{"Do you have a question that's not answered here? Send it to "}
<Link href={`mailto:${coindropEmail}`} isExternal>
{coindropEmail}
</Link>
</Text>
</Box>
);
}
Example #10
Source File: index.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
export default function Debug(props: DebugData) {
const handleKey = (e: KeyboardEvent) => {
if (e.key === 'Escape')
{
props.manager.events.emit('close');
e.stopPropagation();
}
}
useEffect(() => {
document.addEventListener('keyup', handleKey);
return () => {
document.removeEventListener('keyup', handleKey);
}
});
return (
<ChakraProvider theme={theme}>
<Container style={{
display: 'flex',
overflow: 'auto',
position: "absolute",
top: "2%",
right: "2%",
width: "40%",
height: "50%",
backgroundColor: "rgba(255,255,255,0.8)",
borderRadius: "10px",
}}>
<div style={{
position: "relative",
padding: "1rem",
}}>
<Tabs>
<TabList>
<Tab fontSize="0.8rem">Player</Tab>
<Tab fontSize="0.8rem">World</Tab>
<Tab fontSize="0.8rem">Hustlers</Tab>
<Tab fontSize="0.8rem">Item Entities</Tab>
<Tab fontSize="0.8rem">Lights</Tab>
</TabList>
<TabPanels>
<TabPanel>
<PlayerPanel player={props.player} />
</TabPanel>
<TabPanel>
<WorldPanel map={props.map} />
</TabPanel>
<TabPanel>
<HustlersPanel hustlers={props.hustlers} />
</TabPanel>
<TabPanel>
<ItemEntitiesPanel itemEntities={props.itemEntities} />
</TabPanel>
<TabPanel>
<LightsPanel player={props.player} lights={props.lights} />
</TabPanel>
</TabPanels>
</Tabs>
</div>
</Container>
</ChakraProvider>
)
}
Example #11
Source File: ControlAttendeeEdit.tsx From takeout-app with MIT License | 5 votes |
ControlAttendeeEdit: React.FC<Props> = () => {
const match = useRouteMatch<{ id: string }>();
const id = parseInt(match.params.id, 10);
const { data } = ControlApi.useAttendee(id);
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit, reset } = useForm<ControlUpdateAttendeeRequestAttendee>({
defaultValues: {
name: React.useMemo(() => data?.attendee?.name, [data]),
is_staff: React.useMemo(() => data?.attendee?.is_staff, [data]),
is_speaker: React.useMemo(() => data?.attendee?.is_speaker, [data]),
is_committer: React.useMemo(() => data?.attendee?.is_committer, [data]),
presentation_slugs: React.useMemo(() => data?.attendee?.presentation_slugs || [], [data]),
},
});
const onSubmit = handleSubmit(async (data) => {
if (isRequesting) return;
setIsRequesting(true);
try {
await ControlApi.updateAttendee(id, data);
setErrorAlert(null);
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setIsRequesting(false);
});
React.useEffect(() => {
if (data) reset(data.attendee);
}, [data]);
if (!data) return <p>Loading</p>;
// TODO: link to registration page and support email
return (
<>
{errorAlert}
<Container mt="20px">
<form onSubmit={onSubmit}>
<Text>
<Link href={data.ticket.admin_url} isExternal textDecoration="underline">
{data.ticket.reference}
</Link>
</Text>
<FormControl mt={4} id="attendee__name" isRequired>
<FormLabel>Name</FormLabel>
<Input {...register("name")} />
</FormControl>
<FormControl mt={4} id="attendee__staff" isRequired>
<FormLabel>Staff</FormLabel>
<Checkbox {...register("is_staff")} />
</FormControl>
<FormControl mt={4} id="attendee__speaker" isRequired>
<FormLabel>Speaker</FormLabel>
<Checkbox {...register("is_speaker")} />
</FormControl>
<FormControl mt={4} id="attendee__committer" isRequired>
<FormLabel>Committer</FormLabel>
<Checkbox {...register("is_committer")} />
</FormControl>
<FormControl mt={4} id="attendee__presentation_slugs">
<FormLabel>Presentation Slugs</FormLabel>
<Input {...register("presentation_slugs.0")} />
</FormControl>
<Button mt={4} size="lg" type="submit" isLoading={isRequesting}>
Save
</Button>
</form>
</Container>
</>
);
}
Example #12
Source File: [slug].tsx From ksana.in with Apache License 2.0 | 5 votes |
export default function BlogDetail({ post }: IBlogDetail) {
return (
<Layout>
<MetaHead title={`${post.title} | Ksana.in`} description={post.excerpt} />
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(makeBreadcrumbBlogSchema({ title: post.title, slug: post.slug }))
}}
></script>
</Head>
<VStack spacing={4} textAlign="center" as="section" mt="32">
<Breadcrumb>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem>
<BreadcrumbLink href="/blog">Blog</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem isCurrentPage>
<BreadcrumbLink href={`/blog/${post.slug}`}>{post.title}</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
<Container maxW={'4xl'} mx="auto" as="section" mt="8">
<VStack spacing={4} textAlign="center" className="blog-detail">
<Heading
as="h1"
fontWeight={700}
fontSize={{ base: '3xl', sm: '4xl', md: '5xl' }}
lineHeight={'110%'}
color="orange.400"
>
{post.title}
</Heading>
<Button leftIcon={<HiClock />} colorScheme="gray" variant="solid" size="xs">
{post.date}
</Button>
</VStack>
</Container>
</VStack>
<Container maxW={'4xl'} mx="auto" as="section" mt="8">
<div className="markdown">
<div
dangerouslySetInnerHTML={{
__html: `${post.content}`
}}
></div>
</div>
</Container>
</Layout>
)
}
Example #13
Source File: ControlLogin.tsx From takeout-app with MIT License | 5 votes |
ControlLogin: React.FC<Props> = () => {
const history = useHistory();
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit } = useForm<{
password: string;
}>({ defaultValues: { password: "" } });
const onSubmit = handleSubmit(async (data) => {
if (isRequesting) return;
setIsRequesting(true);
try {
await ControlApi.createControlSession(data.password);
setErrorAlert(null);
history.push("/control");
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setIsRequesting(false);
});
// TODO: link to registration page and support email
return (
<>
{errorAlert}
<Container mt="20px">
<p>Beep beep, beep boop?</p>
<form onSubmit={onSubmit}>
<FormControl mt={4} id="login_password" isRequired>
<FormLabel>Control Password</FormLabel>
<Input {...register("password")} type="password" />
</FormControl>
<Button mt={4} size="lg" type="submit" isLoading={isRequesting}>
Take control
</Button>
</form>
</Container>
</>
);
}
Example #14
Source File: Header.tsx From ledokku with MIT License | 5 votes |
Header = () => {
const { user, logout } = useAuth();
return (
<nav>
<Container maxW="5xl">
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
h={16}
>
<Box display="flex" alignItems="center">
<Heading as="h3" fontSize="medium">
<Link to="/">Ledokku</Link>
</Heading>
</Box>
<div>
<Menu placement="bottom-end">
<MenuButton>
{user?.avatarUrl && (
<Image
h={8}
w={8}
borderRadius="full"
src={user.avatarUrl}
alt="Avatar"
/>
)}
</MenuButton>
<MenuList fontSize="sm" color="gray.700">
<MenuItem as={Link} to="/dashboard">
Dashboard
</MenuItem>
<MenuDivider />
<MenuItem
as="a"
href="https://github.com/ledokku/ledokku"
target="_blank"
rel="noopener noreferrer"
>
Github
</MenuItem>
<MenuDivider />
<MenuItem onClick={() => logout()}>Logout</MenuItem>
</MenuList>
</Menu>
</div>
</Box>
</Container>
</nav>
);
}
Example #15
Source File: Post.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
Post: FunctionComponent<PostTypePostHydrate> = ({
author,
datePublished,
dateModified,
title,
description,
images,
slug,
content,
}) => {
const { avatar: authorAvatar, handle: authorHandle, url: authorUrl } = authors[author];
const theme = useTheme();
return (
<>
<NextSeo
title={`${title} | Coindrop blog`}
description={description}
/>
<ArticleJsonLd
url={`https://coindrop.to/blog/${slug}`}
title={title}
images={images}
datePublished={datePublished}
dateModified={dateModified}
authorName={author}
publisherName="Coindrop"
publisherLogo="https://coindrop.to/piggy-256.png" // TODO: change this to a valid AMP logo size https://developers.google.com/search/docs/data-types/article
description={description}
/>
<article>
<Heading
as="h1"
size="2xl"
textAlign="center"
my={6}
>
{title}
</Heading>
<Flex
direction={["column", null, "row"]}
align={["initial", null, "center"]}
alignItems="center"
justify="center"
mb={4}
>
<Text
id="publish-date"
mb={[4, null, "auto"]}
mt={[0, null, "auto"]}
textAlign="center"
mr={[null, null, 12]}
>
{`${dayjs(datePublished).format('dddd, MMMM D, YYYY')} (${dayjs(datePublished).fromNow()})`}
</Text>
<Flex
id="author"
align="center"
justify="center"
>
<Avatar name={author} src={authorAvatar} size="sm" />
<Flex direction="column" ml={1} align="flex-start">
<Text fontSize="sm">
<Text>
{author}
</Text>
<Link href={authorUrl} isExternal>
{authorHandle}
</Link>
</Text>
</Flex>
</Flex>
</Flex>
<hr />
<Container
mt={8}
maxW={theme.breakpoints.md}
>
{content}
{dateModified && (
<>
<Text
id="modified-date"
fontSize="sm"
textAlign="center"
>
{`Last updated ${dayjs(dateModified).format('dddd, MMMM D, YYYY')} (${dayjs(dateModified).fromNow()})`}
</Text>
<Text
fontSize="xs"
textAlign="center"
>
<Link
href={`https://github.com/remjx/coindrop/commits/master/blog/posts/${slug}/index.mdx`}
>
<u>View edits</u>
</Link>
</Text>
</>
)}
</Container>
</article>
</>
);
}
Example #16
Source File: TrackView.tsx From takeout-app with MIT License | 4 votes |
TrackView: React.FC<Props> = ({ track, streamOptionsState }) => {
const [streamOptions, setStreamOptions] = streamOptionsState;
const trackOptionsSelector = (instance: string) => (
<TrackStreamOptionsSelector track={track} streamOptionsState={streamOptionsState} instance={instance} />
);
// Preload candidate speaker images
React.useEffect(() => {
if (!track.card_candidate) return;
if (!track.card_candidate.speakers) return;
track.card_candidate.speakers.forEach((s) => {
const i = new Image();
i.onload = () => console.log("Preloaded", s.avatar_url);
i.src = s.avatar_url;
});
}, [track.card_candidate]);
// TODO: Chakra 側のブレークポイントの調整
// TODO: hide chat button
return (
<Container maxW={["auto", "auto", "auto", "1700px"]} px="15px" py="22px">
<Flex alignItems="top" justifyContent="space-between" direction={["column", "column", "column", "row"]}>
<Box w="100%">
<React.Suspense
fallback={
<AspectRatio ratio={16 / 9}>
<Skeleton w="100%" h="100%" />
</AspectRatio>
}
>
<TrackVideo track={track} streamOptions={streamOptionsState[0]} />
</React.Suspense>
{streamOptions.caption ? (
<React.Suspense fallback={<Skeleton w="100%" h="80px" />}>
<TrackCaption
track={track}
onUnsubscribe={() => {
setStreamOptions({ ...streamOptions, caption: false });
}}
/>
</React.Suspense>
) : null}
<Box display={["flex", "flex", "none", "none"]} justifyContent="end" my={2}>
<Box w="150px">{trackOptionsSelector("1")}</Box>
</Box>
</Box>
{streamOptions.chat && track.chat ? (
<Box
maxW={["auto", "auto", "auto", "400px"]}
h={["480px", "480px", "480px", "auto"]}
w="100%"
ml={["0", "0", "0", "30px"]}
>
<React.Suspense fallback={<Skeleton w="100%" h="100%" />}>
<TrackChat track={track} />
</React.Suspense>
</Box>
) : null}
</Flex>
<Flex alignItems="top" justifyContent="space-between" direction={["column", "column", "column", "row"]} mt="12px">
<Box w="100%">
<TrackCardView
card={track.card}
nav={
<HStack alignItems="flex-start" spacing="20px">
{track.viewerCount ? <TrackViewerCount count={track.viewerCount} /> : null}
<Box display={["none", "none", "block", "block"]}>{trackOptionsSelector("2")}</Box>
</HStack>
}
/>
</Box>
<Box maxW={["auto", "auto", "auto", "400px"]} w="100%" ml="30px">
<AppVersionAlert />
</Box>
</Flex>
</Container>
);
}
Example #17
Source File: ChatType.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
export default function ChatType(props: Props) {
const [ unreadMessages, setUnreadMessages ] = React.useState(0);
const [ inputText, setInputText ] = React.useState('');
const [ messages, setMessages ] = React.useState(props.messagesStore);
const [ canSendMessage, setCanSendMessage ] = React.useState((props.chatMessageBoxes?.length ?? 0) < 3);
const messagesListRef = React.useRef<HTMLUListElement>(null);
let state = React.useRef({
i: -1,
});
useEffect(() => {
props.manager.events.on('chat_message', (message: DataTypes[NetworkEvents.SERVER_PLAYER_CHAT_MESSAGE]) => {
setMessages(m => [...m, message]);
const lastMessageEl = messagesListRef.current?.lastElementChild as HTMLLIElement;
if (lastMessageEl &&
lastMessageEl?.parentElement?.parentElement && !isVisible(lastMessageEl, lastMessageEl?.parentElement?.parentElement))
setUnreadMessages(u => u + 1);
});
// constantly check chatMessageBoxes size and if it's less than 3, set canSendMessage to true
const interval = setInterval(() => setCanSendMessage((props.chatMessageBoxes?.length ?? 0) < 3));
return () => clearInterval(interval);
}, []);
const handleInputKey = (e: KeyboardEvent) => {
if (e.key === 'Enter' && canSendMessage) handleSubmit(inputText);
else if (e.key === 'Escape')
// send "nothing", chat will get closed & message will not get sent
handleSubmit('');
else if (e.key === 'ArrowUp') {
state.current.i = ++state.current.i % props.precedentMessages.length;
const precedentMessage = props.precedentMessages[state.current.i];
if (precedentMessage) setInputText(precedentMessage);
} else if (e.key === 'ArrowDown') {
// rolling window, wrap around
state.current.i = --state.current.i % props.precedentMessages.length;
if (state.current.i < 0) state.current.i = props.precedentMessages.length - 1;
const precedentMessage = props.precedentMessages[state.current.i];
if (precedentMessage) setInputText(precedentMessage);
}
};
const handleSubmit = (content: string) => {
if (content.length > 150)
return;
props.manager.events.emit('chat_submit', content);
};
return (
<ChakraProvider theme={theme}>
<Container
style={{
position: 'absolute',
backgroundColor: 'rgba(0,0,0,0.7)',
borderRadius: '0.5rem',
boxShadow: '0 0.5rem 1rem rgba(0, 0, 0, 0.7)',
height: '30%',
width: '30%',
left: "1%",
bottom: "1%",
}}>
<Stack style={{
paddingTop: '1rem',
height: '95%',
}}>
<div style={{
display: 'flex',
overflow: 'auto',
flexDirection: 'column-reverse',
marginBottom: '-3%',
}}>
<List ref={messagesListRef} spacing={-2} style={{
}}>
<Text style={{
color: 'blueviolet',
}}>
Welcome to the Dopeverse!
</Text>
{messages.map((message, i) => <ListItem key={i}>
<HStack style={{
opacity: '0.8'
}}>
<Text style={{
color: 'white',
}}>
{message.author}: {message.message}
</Text>
<Spacer />
<Text style={{
color: 'grey',
fontSize: '0.6rem',
}}>
{new Date(message.timestamp).toLocaleString()}
</Text>
</HStack>
</ListItem>)}
</List>
</div>
<Spacer />
<Center>
<Button
style={{
marginRight: '1%',
marginTop: '-10%'
}}
variant="primary"
backgroundColor="red.600"
hidden={inputText.length <= 150}
onClick={() => setInputText(inputText.substring(0, 150))}
>
❌ Message too long
</Button>
<Button
style={{
marginTop: '-10%',
}}
variant="primary"
hidden={unreadMessages === 0}
onClick={(e) => {
setUnreadMessages(0);
e.currentTarget.hidden = true;
if (messagesListRef.current)
(messagesListRef.current as HTMLOListElement).lastElementChild?.scrollIntoView({
behavior: 'smooth',
});
}}
>
⬇️ New message ({unreadMessages})
</Button>
</Center>
<Center>
<InputGroup width="90%" size="md">
<Input
autoFocus={true}
focusBorderColor="white"
onBlur={({ target }) => target.focus()}
pr="4.5rem"
placeholder="Message"
_placeholder={{ color: '#b8b8b8' }}
textColor="#f5f5f5"
value={inputText}
onChange={({ target }) => setInputText(target.value)}
onKeyDown={handleInputKey}
style={{
backgroundColor: 'rgba(0, 0, 0, 0.3)',
}}
/>
<InputRightElement width="4.5rem" style={{ paddingRight: '2%' }}>
<Button h="1.75rem" size="sm" disabled={!canSendMessage} onClick={() => handleSubmit(inputText)}>
Send
</Button>
</InputRightElement>
</InputGroup>
</Center>
</Stack>
</Container>
</ChakraProvider>
);
}
Example #18
Source File: AttendeeEdit.tsx From takeout-app with MIT License | 4 votes |
AttendeeEdit: React.FC = () => {
const { data: conferenceData } = Api.useConference();
const { data: session, error: sessionError } = Api.useSession();
const history = useHistory();
const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
const { register, handleSubmit, reset } = useForm<{
name: string;
gravatar_email: string;
}>({
defaultValues: {
name: React.useMemo(() => session?.attendee?.name, [session]),
gravatar_email: "",
},
});
React.useEffect(() => {
if (session?.attendee) reset({ name: session.attendee.name, gravatar_email: "" });
}, [session?.attendee]);
const onSubmit = handleSubmit(async (data) => {
//const wasReady = session!.attendee?.is_ready;
if (isRequesting) return;
setIsRequesting(true);
try {
await Api.updateAttendee(data.name, data.gravatar_email);
setErrorAlert(null);
if (conferenceData) {
history.push(`/tracks/${encodeURIComponent(conferenceData.conference.default_track)}`);
} else {
location.href = "/";
}
} catch (e) {
setErrorAlert(
<Box my={2}>
<ErrorAlert error={e} />
</Box>,
);
}
setIsRequesting(false);
});
if (!session?.attendee) {
return (
<Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
<VStack>
{sessionError ? (
<Box my={2}>
<ErrorAlert error={sessionError} />
</Box>
) : null}
<Spinner size="xl" />
</VStack>
</Container>
);
}
return (
<Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
<VStack justify="start" alignItems="start" spacing="30px">
<Heading as="h2" color={Colors.main}>
Settings
</Heading>
<HStack spacing="30px">
<Avatar size="xl" bg={Colors.defaultAvatarBg} src={session.attendee.avatar_url} loading="lazy" />
<Box maxW="750px">
<Text mb={2}>
Confirm your name and avatar used at live chat. These informations may be shared with other attendees once
submitted.
</Text>
<Text>
Be remember to abide by{" "}
<Link href="https://rubykaigi.org/2021-takeout/policies" isExternal textDecoration="underline">
our policies
</Link>
.
</Text>
</Box>
</HStack>
<form onSubmit={onSubmit}>
<VStack justify="start" alignItems="start" spacing="30px">
<FormControl id="login_reference" isRequired>
<FormLabel>Name</FormLabel>
<FormHelperText my={1}>Feel free to use nicknames, usernames, or handles :)</FormHelperText>
<Input {...register("name")} maxW="460px" autoFocus />
</FormControl>
<FormControl id="login_email">
<FormLabel>Gravatar Email Address</FormLabel>
<FormHelperText my={1}>
We use avatar images registered on{" "}
<Link href="https://www.gravatar.com" isExternal textDecoration="underline">
Gravatar
</Link>
. Fill the following field if you desire to choose different email address for your Gravatar image.
</FormHelperText>
<Input
{...register("gravatar_email")}
type="email"
maxW="460px"
placeholder="(leave empty to remain unchanged)"
/>
</FormControl>
<Button type="submit" w="160px" h="46px" colorScheme="rk" isLoading={isRequesting}>
{session.attendee.is_ready ? "Save" : "Continue"}
</Button>
</VStack>
</form>
{errorAlert}
</VStack>
</Container>
);
}
Example #19
Source File: env.tsx From ledokku with MIT License | 4 votes |
Env = () => {
const { id: appId } = useParams<{ id: string }>();
const { data, loading /* error */ } = useAppByIdQuery({
variables: {
appId,
},
ssr: false,
skip: !appId,
});
const {
data: envVarData,
loading: envVarLoading,
error: envVarError,
} = useEnvVarsQuery({
variables: {
appId,
},
fetchPolicy: 'network-only',
});
if (!data) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
return (
<div>
<HeaderContainer>
<Header />
<AppHeaderInfo app={app} />
<AppHeaderTabNav app={app} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Box py="5">
<Heading as="h2" size="md">
Set env variables
</Heading>
<Text color="gray.400" fontSize="sm">
Environment variables change the way your app behaves. They are
available both at run time and during the application
build/compilation step for buildpack-based deploys.{' '}
<Link
textDecoration="underline"
href="https://dokku.com/docs/configuration/environment-variables/"
isExternal
>
Read more.
</Link>
</Text>
</Box>
{!envVarLoading && !envVarError && envVarData?.envVars.envVars && (
<Box mb="8">
{envVarData.envVars.envVars.map((envVar) => {
return (
<EnvForm
key={envVar.key}
name={envVar.key}
value={envVar.value}
appId={appId}
/>
);
})}
<EnvForm
key="newVar"
name=""
value=""
appId={appId}
isNewVar={true}
/>
</Box>
)}
</Container>
</div>
);
}
Example #20
Source File: PublicPiggybankPage.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
PublicPiggybankPage: FunctionComponent = () => {
const { query: { piggybankName } } = useRouter();
const { piggybankDbData } = useContext(PublicPiggybankDataContext);
const theme = useTheme();
const { user } = useUser();
const { colorMode } = useColorMode();
const accentColorLevelInitial = getAccentColorLevelInitial(colorMode);
const accentColorLevelHover = getAccentColorLevelHover(colorMode);
const {
name,
website,
accentColor = "orange",
verb,
owner_uid,
} = piggybankDbData;
const accentColorInitial = theme.colors[accentColor][accentColorLevelInitial];
const accentColorHover = theme.colors[accentColor][accentColorLevelHover];
const pagePaymentMethodsDataEntries = Object.entries(piggybankDbData.paymentMethods ?? {});
const preferredAddresses = pagePaymentMethodsDataEntries.filter(([, paymentMethodData]: any) => paymentMethodData.isPreferred);
const otherAddresses = pagePaymentMethodsDataEntries.filter(([, paymentMethodData]: any) => !paymentMethodData.isPreferred);
const WrapGroup: FunctionComponent = ({ children }) => (
<Wrap
justify="center"
>
{children}
</Wrap>
);
type PaymentMethodButtonsFromEntriesProps = {
entries: PaymentMethodDbObjEntry[]
}
const PaymentMethodButtonsFromEntries: FunctionComponent<PaymentMethodButtonsFromEntriesProps> = ({ entries }) => (
<WrapGroup>
{entries
.sort(sortArrayByEntriesKeyAlphabetical)
.map(([paymentMethodId, paymentMethodData]) => (
<WrapItem key={paymentMethodId}>
<PaymentMethodButton
key={paymentMethodId}
paymentMethod={paymentMethodId}
paymentMethodValue={paymentMethodData.address}
isPreferred={paymentMethodData.isPreferred}
accentColor={accentColor}
/>
</WrapItem>
))}
</WrapGroup>
);
const piggybankExists = !!owner_uid;
const initialSetupComplete = name && accentColor && verb && pagePaymentMethodsDataEntries.length > 0;
return (
<>
<NextSeo
title={`${name ?? piggybankName}'s Coindrop (coindrop.to/${piggybankName})`}
description={`Send money to ${name} with no fees`}
/>
<Container
maxW={theme.breakpoints.lg}
mx="auto"
>
{user?.id
&& user.id === owner_uid
&& (
<>
<DataRefetcher />
<ManagePiggybankBar
editButtonOptions={
initialSetupComplete
? ({
text: 'Configure',
color: undefined,
icon: <SettingsIcon />,
}) : ({
text: 'Set up',
color: 'green',
icon: <SettingsIcon />,
})
}
initialSetupComplete={initialSetupComplete}
/>
</>
)}
{initialSetupComplete ? (
<Box
mb={6}
>
<Box
padding="10px"
my={2}
mx={3}
>
<Center>
<Avatar />
</Center>
<Heading textAlign="center">
Choose a payment method to
{` ${verb} `}
{website ? (
<Link href={website} target="_blank" rel="noreferrer">
<Heading
as="span"
color={accentColorInitial}
textDecoration="underline"
css={css`
&:hover {
color: ${accentColorHover};
}
`}
>
{name}
</Heading>
</Link>
) : (
<Heading
as="span"
color={accentColorInitial}
>
{name}
</Heading>
)}
:
</Heading>
</Box>
<PaymentMethodButtonsFromEntries
entries={preferredAddresses}
/>
<PaymentMethodButtonsFromEntries
entries={otherAddresses}
/>
<PoweredByCoindropLink />
</Box>
) : (
<Heading mt={4} textAlign="center">
{piggybankExists ? 'This Coindrop has not been set up yet.' : 'This Coindrop does not exist'}
{/* TODO: Include action buttons to log in or landing page */}
</Heading>
)}
</Container>
</>
);
}
Example #21
Source File: index.tsx From ledokku with MIT License | 4 votes |
App = () => {
const history = useHistory();
const toast = useToast();
const { id: appId } = useParams<{ id: string }>();
const [isUnlinkModalOpen, setIsUnlinkModalOpen] = useState(false);
const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);
const [arrayOfLinkLogs, setArrayOfLinkLogs] = useState<RealTimeLog[]>([]);
const [arrayOfUnlinkLogs, setArrayOfUnlinkLogs] = useState<RealTimeLog[]>([]);
const [databaseAboutToUnlink, setdatabaseAboutToUnlink] = useState<string>();
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [processStatus, setProcessStatus] = useState<
'running' | 'notStarted' | 'finished'
>('notStarted');
const [unlinkLoading, setUnlinkLoading] = useState(false);
const [linkLoading, setLinkLoading] = useState(false);
const [selectedDb, setSelectedDb] = useState({
value: { name: '', id: '', type: '' },
label: 'Please select database',
});
const [
linkDatabaseMutation,
{
data: databaseLinkData,
loading: databaseLinkLoading,
error: databaseLinkError,
},
] = useLinkDatabaseMutation();
const [unlinkDatabaseMutation] = useUnlinkDatabaseMutation();
useUnlinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.unlinkDatabaseLogs;
if (logsExist) {
setArrayOfUnlinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
useLinkDatabaseLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.linkDatabaseLogs;
if (logsExist) {
setArrayOfLinkLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (
logsExist.type === 'end:success' ||
logsExist.type === 'end:failure'
) {
setProcessStatus('finished');
}
}
},
});
const {
data: databaseData,
loading: databaseDataLoading,
} = useDatabaseQuery();
const { data, loading, refetch /* error */ } = useAppByIdQuery({
variables: {
appId,
},
fetchPolicy: 'cache-and-network',
ssr: false,
skip: !appId,
});
if (!data || !databaseData) {
return null;
}
// // TODO display error
if (loading || databaseDataLoading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { databases } = databaseData;
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
const linkedDatabases = app.databases;
const linkedIds = linkedDatabases?.map((db) => db.id);
const notLinkedDatabases = databases.filter((db) => {
return linkedIds?.indexOf(db.id) === -1;
});
// Hacky way to add create new database to link db select
notLinkedDatabases.length > 0 &&
notLinkedDatabases.push({ name: 'Create new database' } as any);
const dbOptions = notLinkedDatabases.map((db) => {
return {
value: { name: db.name, id: db.id, type: db.type },
label: <DatabaseLabel type={db.type} name={db.name} />,
};
});
const handleUnlink = async (databaseId: string, appId: string) => {
try {
await unlinkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setIsTerminalVisible(true);
setUnlinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
const handleConnect = async (databaseId: string, appId: string) => {
try {
await linkDatabaseMutation({
variables: {
input: {
databaseId,
appId,
},
},
});
setSelectedDb({
value: { name: '', id: '', type: '' },
label: 'Please select database',
});
setIsTerminalVisible(true);
setLinkLoading(true);
} catch (e) {
toast.error(e.message);
}
};
return (
<div>
<HeaderContainer>
<Header />
<AppHeaderInfo app={app} />
<AppHeaderTabNav app={app} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<div className="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-2 gap-4 mt-10">
<div>
<Heading as="h2" size="md" py={5}>
App info
</Heading>
<div className="bg-gray-100 shadow overflow-hidden rounded-lg border-b border-gray-200">
<Table mt="4" mb="4" variant="simple">
<Tbody mt="10">
<Tr py="4">
<Td className="font-semibold" py="3" px="4">
App name
</Td>
<Td py="3" px="4">
{app.name}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="7" px="4">
id
</Td>
<Td w="1/3" py="3" px="4">
{app.id}
</Td>
</Tr>
<Tr>
<Td className="font-semibold" py="3" px="4">
Created at
</Td>
<Td py="3" px="4">
{app.createdAt}
</Td>
</Tr>
</Tbody>
</Table>
</div>
</div>
<div className="w-full">
<Heading as="h2" size="md" py={5}>
Databases
</Heading>
{databases.length === 0 ? (
<>
<div className="mt-4 mb-4">
<h2 className="text-gray-400">
Currently you haven't created any databases, to do so
proceed with the database creation flow
</h2>
</div>
<RouterLink
to={{
pathname: '/create-database/',
state: app.name,
}}
>
<Button width="large" color={'grey'}>
Create a database
</Button>
</RouterLink>
</>
) : (
<>
{notLinkedDatabases.length !== 0 ? (
<div>
<Listbox
as="div"
value={selectedDb}
//@ts-ignore
onChange={
selectedDb.value.name !== 'Create new database'
? setSelectedDb
: history.push({
pathname: '/create-database',
state: app.name,
})
}
>
{({ open }) => (
<div className="relative w-80">
<Listbox.Button className="cursor-default relative w-full rounded-md border border-gray-300 bg-white pl-3 pr-10 py-2 text-left focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition ease-in-out duration-150 sm:text-sm sm:leading-5">
<span className="block truncate">
{selectedDb.label}
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
className="h-5 w-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</Listbox.Button>
{open && (
<Transition
show={open}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
className="absolute mt-1 w-full rounded-md bg-white shadow-lg z-10"
>
<Listbox.Options
static
className="max-h-60 rounded-md py-1 text-base leading-6 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm sm:leading-5"
>
{dbOptions.map(
(db) =>
db.value.id !== selectedDb.value.id && (
<Listbox.Option
key={dbOptions.indexOf(db)}
value={db as any}
>
{({ active }) => (
<div
className={cx(
'cursor-default select-none relative py-2 px-4',
{
'bg-gray-200': active,
'bg-white text-black': !active,
}
)}
>
{db.label}
</div>
)}
</Listbox.Option>
)
)}
</Listbox.Options>
</Transition>
)}
</div>
)}
</Listbox>
{databaseLinkError && (
<p className="text-red-500 text-sm font-semibold">
{databaseLinkError.graphQLErrors[0].message}
</p>
)}
<Button
color="grey"
width="large"
className="mt-2"
isLoading={
databaseLinkLoading &&
!databaseLinkData &&
!databaseLinkError
}
disabled={!selectedDb.value.id || linkLoading}
onClick={() => {
setIsLinkModalOpen(true);
}}
>
Link database
</Button>
{isLinkModalOpen && (
<Modal>
<ModalTitle>Link database</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Linking <b>{selectedDb.value.name}</b> with{' '}
<b>{app.name}</b>!
</p>
<p className="text-gray-500 mb-2">
Linking process usually takes a couple of
minutes. Breathe in, breathe out, logs are about
to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfLinkLogs.map((log) => (
<p
key={arrayOfLinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to link{' '}
<b>{selectedDb.value.name}</b> to{' '}
<b>{app.name}</b>?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleConnect(selectedDb.value.id, appId);
}}
ctaText={'Link'}
otherButtonText={'Cancel'}
isCtaLoading={isTerminalVisible ? false : linkLoading}
isCtaDisabled={isTerminalVisible}
isOtherButtonDisabled={processStatus === 'running'}
closeModal={() => {
setIsLinkModalOpen(false);
refetch({ appId });
setLinkLoading(false);
setIsTerminalVisible(false);
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
) : (
<>
<p className="mt-3 mb-3 text-cool-gray-400">
All your databases are already linked to this app! If you
want to create more databases proceed with create database
flow.
</p>
<div className="ml-80">
<Link to="/create-database">
<Button
color={'grey'}
variant="outline"
className="text-sm mr-3"
>
Create database
</Button>
</Link>
</div>
</>
)}
{!loading && app && app.databases && (
<>
<h2 className="mb-1 mt-3 font-semibold">
{app.databases.length > 0 && 'Linked databases'}
</h2>
{app.databases.map((database) => (
<div
key={app.databases?.indexOf(database)}
className="flex flex-row justify-start"
>
<Link
to={`/database/${database.id}`}
className="py-2 block"
>
<div className="w-64 flex items-center py-3 px-2 shadow hover:shadow-md transition-shadow duration-100 ease-in-out rounded bg-white">
{database.type === 'POSTGRESQL' ? (
<>
<PostgreSQLIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'MONGODB' ? (
<>
<MongoIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'REDIS' ? (
<>
<RedisIcon size={16} className="mr-1" />
</>
) : undefined}
{database.type === 'MYSQL' ? (
<>
<MySQLIcon size={16} className="mr-1" />
</>
) : undefined}
{database.name}
</div>
</Link>
<Button
width="normal"
className="mt-4 ml-2 h-10"
color="red"
onClick={() => {
setIsUnlinkModalOpen(true);
setdatabaseAboutToUnlink(database.name);
}}
>
Unlink
</Button>
{isUnlinkModalOpen && (
<Modal>
<ModalTitle>Unlink database</ModalTitle>
<ModalDescription>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Unlinking <b>{app.name}</b>
from <b>{databaseAboutToUnlink}</b>!
</p>
<p className="text-gray-500 mb-2">
Unlinking process usually takes a couple of
minutes. Breathe in, breathe out, logs are
about to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfUnlinkLogs.map((log) => (
<p
key={arrayOfUnlinkLogs.indexOf(log)}
className="text-s leading-5"
>
{log.message}
</p>
))}
</Terminal>
</>
) : (
<p>
Are you sure, you want to unlink{' '}
<b>{app.name} </b>
from <b>{databaseAboutToUnlink}</b> ?
</p>
)}
</ModalDescription>
<ModalButton
ctaFn={() => {
setProcessStatus('running');
handleUnlink(database.id, appId);
}}
ctaText={'Unlink'}
otherButtonText={'Cancel'}
isOtherButtonDisabled={
processStatus === 'running'
}
isCtaLoading={
isTerminalVisible ? false : unlinkLoading
}
isCtaDisabled={isTerminalVisible === true}
closeModal={() => {
setIsUnlinkModalOpen(false);
refetch({ appId });
setUnlinkLoading(false);
setIsTerminalVisible(false);
setdatabaseAboutToUnlink('');
setProcessStatus('notStarted');
}}
/>
</Modal>
)}
</div>
))}
</>
)}
</>
)}
</div>
</div>
</Container>
</div>
);
}
Example #22
Source File: LandingPage.tsx From coindrop with GNU General Public License v3.0 | 4 votes |
LandingPage: FC<Props> = ({
headingTextPrimaryPreUnderline,
headingTextPrimaryUnderline,
headingTextPrimaryPostUnderline,
headingTextSecondary,
headingTextTertiary,
smartphoneMockupImagePublicPath,
showSubscriptionPlatforms,
ShareOptions,
shareOptionsHeading,
advertiseOpenSource,
getStartedText,
smartphoneMockupImageWidth,
smartphoneMockupImageHeight,
createCoindropInputPlaceholder,
logoSubtitle,
}) => {
const {
isOpen: isAuthOpen,
onOpen: onAuthOpen,
onClose: onAuthClose,
} = useDisclosure();
const router = useRouter();
const { user } = useUser();
useEffect(() => {
if (user) {
const pendingLoginCreatePiggybankPath = cookies.get('pendingLoginCreatePiggybankPath');
if (pendingLoginCreatePiggybankPath) {
router.push('/create');
} else {
router.push('/dashboard');
}
}
}, [user]);
useEffect(() => {
if (router.query.auth) {
onAuthOpen();
} else {
onAuthClose();
}
}, [router.query]);
return (
<>
<AuthModal
isOpen={isAuthOpen}
/>
<HeaderFooterContainer>
<Navbar
logoSubtitle={logoSubtitle}
/>
</HeaderFooterContainer>
<Container
maxW="100%"
mx="auto"
px={4}
mb={6}
>
<Container
my="3rem"
maxW="98em" // there is no theme.breakpoints.2xl
>
<HeadingTextPrimary
textPreUnderline={headingTextPrimaryPreUnderline}
textUnderline={headingTextPrimaryUnderline}
textPostUnderline={headingTextPrimaryPostUnderline}
/>
<Text fontSize="lg" textAlign="center" mt={3}>
{headingTextSecondary}
</Text>
<Text fontSize="lg" textAlign="center" mt={2}>
<b>{headingTextTertiary}</b>
</Text>
<Center mt={8}>
<Image
src={smartphoneMockupImagePublicPath}
alt="Smartphone mockup"
height={smartphoneMockupImageHeight}
width={smartphoneMockupImageWidth}
/>
</Center>
</Container>
<ContentContainer>
<ContentContainerHeading withThroughline>
➀ Pick a custom URL
</ContentContainerHeading>
<Box
mt={8}
>
<CreatePiggybankInput
createButtonColorScheme="orange"
onCancel={null}
instanceId="top"
buttonText="Check availability"
placeholder={createCoindropInputPlaceholder}
/>
</Box>
</ContentContainer>
<ContentContainer>
<ContentContainerHeading withThroughline>
➁ Add your payment methods
</ContentContainerHeading>
<Flex
direction={['column', 'row']}
wrap="wrap"
maxW="80%"
mx="auto"
>
<PaymentMethodContainer title="Digital wallets" paymentMethodCategory="digital-wallet" />
<PaymentMethodContainer title="Digital assets" paymentMethodCategory="digital-asset" />
{showSubscriptionPlatforms && (
<PaymentMethodContainer title="Subscription platforms" paymentMethodCategory="subscription-platform" />
)}
</Flex>
</ContentContainer>
<ContentContainer>
<ContentContainerHeading withThroughline>
➂ {shareOptionsHeading}
</ContentContainerHeading>
<ShareOptions />
</ContentContainer>
{advertiseOpenSource && (
<ContentContainer
boxProps={{
borderRadius: '16px',
position: 'relative',
}}
>
<ContentContainerHeading>
Open-Source
</ContentContainerHeading>
<Flex align="center" justify="center" mt={4}>
<GithubIcon
opacity={0.9}
boxSize="72px"
mr={4}
/>
<Text
fontSize="lg"
>
{'The source code for Coindrop is publicly available on '}
<Link isExternal href={githubUrl}>
Github
</Link>
</Text>
</Flex>
</ContentContainer>
)}
<ContentContainer>
<ContentContainerHeading>
Get started ?
</ContentContainerHeading>
<Text textAlign="center" fontSize="lg">
{getStartedText}
</Text>
<Box mt={2}>
<CreatePiggybankInput
createButtonColorScheme="orange"
onCancel={null}
instanceId="bottom"
buttonText="Create"
placeholder={createCoindropInputPlaceholder}
/>
</Box>
</ContentContainer>
</Container>
<HeaderFooterContainer>
<Footer />
</HeaderFooterContainer>
</>
);
}
Example #23
Source File: logs.tsx From ledokku with MIT License | 4 votes |
Logs = () => {
const { id: appId } = useParams<{ id: string }>();
const { data, loading /* error */ } = useAppByIdQuery({
variables: {
appId,
},
});
const {
data: appLogsData,
loading: appLogsLoading,
error: appLogsError,
} = useAppLogsQuery({
variables: {
appId,
},
// we fetch status every 2 min 30 sec
pollInterval: 15000,
});
const memoizedLogsHtml = useMemo(() => {
if (!appLogsData?.appLogs.logs) {
return null;
}
const data = appLogsData.appLogs.logs.map((log) => {
const ansiIUp = new AnsiUp();
const html = ansiIUp.ansi_to_html(log);
return html;
});
return data;
}, [appLogsData]);
if (!data) {
return null;
}
// // TODO display error
if (loading) {
// TODO nice loading
return <p>Loading...</p>;
}
const { app } = data;
if (!app) {
// TODO nice 404
return <p>App not found.</p>;
}
return (
<div>
<HeaderContainer>
<Header />
<AppHeaderInfo app={app} />
<AppHeaderTabNav app={app} />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
<Heading as="h2" size="md" py={5}>
Logs for {app.name} app:
</Heading>
{appLogsLoading ? (
<Text fontSize="sm" color="gray.400">
Loading...
</Text>
) : null}
{appLogsError ? (
<Alert
status="error"
variant="top-accent"
borderBottomRadius="base"
boxShadow="md"
>
<AlertDescription>{appLogsError.message}</AlertDescription>
</Alert>
) : null}
{!appLogsLoading && !appLogsError && !appLogsData ? (
<Alert
status="info"
variant="top-accent"
borderBottomRadius="base"
boxShadow="md"
>
<AlertDescription>
There are no logs for {app.name}.
<br />
App is not deployed or still deploying.
</AlertDescription>
</Alert>
) : null}
{memoizedLogsHtml ? (
<Terminal mb="8">
{memoizedLogsHtml.map((html, index) => (
<p key={index} dangerouslySetInnerHTML={{ __html: html }}></p>
))}
</Terminal>
) : null}
</Container>
</div>
);
}
Example #24
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 #25
Source File: create-app-github.tsx From ledokku with MIT License | 4 votes |
CreateAppGithub = () => {
const history = useHistory();
const toast = useToast();
const { user } = useAuth();
const { data: dataApps } = useAppsQuery();
const [isNewWindowClosed, setIsNewWindowClosed] = useState(false);
const [selectedRepo, setSelectedRepo] = useState<Repository>();
const [selectedBranch, setSelectedBranch] = useState('');
const [isProceedModalOpen, setIsProceedModalOpen] = useState(false);
const {
data: installationData,
loading: installationLoading,
} = useGithubInstallationIdQuery({ fetchPolicy: 'network-only' });
const [
getRepos,
{ data: reposData, loading: reposLoading },
] = useRepositoriesLazyQuery({ fetchPolicy: 'network-only' });
const [
getBranches,
{ data: branchesData, loading: branchesLoading },
] = useBranchesLazyQuery({ fetchPolicy: 'network-only' });
const [arrayOfCreateAppLogs, setArrayOfCreateAppLogs] = useState<
RealTimeLog[]
>([]);
const [isTerminalVisible, setIsTerminalVisible] = useState(false);
const [isToastShown, setIsToastShown] = useState(false);
const [createAppGithubMutation, { loading }] = useCreateAppGithubMutation();
const [
isAppCreationSuccess,
setIsAppCreationSuccess,
] = useState<AppCreationStatus>();
useAppCreateLogsSubscription({
onSubscriptionData: (data) => {
const logsExist = data.subscriptionData.data?.appCreateLogs;
if (logsExist) {
setArrayOfCreateAppLogs((currentLogs) => {
return [...currentLogs, logsExist];
});
if (logsExist.type === 'end:success') {
setIsAppCreationSuccess(AppCreationStatus.SUCCESS);
} else if (logsExist.type === 'end:failure') {
setIsAppCreationSuccess(AppCreationStatus.FAILURE);
}
}
},
});
const createAppGithubSchema = yup.object().shape({
name: yup
.string()
.required('App name is required')
.matches(/^[a-z0-9-]+$/)
.test(
'Name exists',
'App with this name already exists',
(val) => !dataApps?.apps.find((app) => app.name === val)
),
repo: yup.object({
fullName: yup.string().required(),
id: yup.string().required(),
name: yup.string().required(),
}),
installationId: yup.string().required(),
gitBranch: yup.string().optional(),
});
const formik = useFormik<{
name: string;
repo: {
fullName: string;
id: string;
name: string;
};
installationId: string;
gitBranch: string;
}>({
initialValues: {
name: '',
repo: {
fullName: '',
id: '',
name: '',
},
installationId: '',
gitBranch: '',
},
validateOnChange: true,
validationSchema: createAppGithubSchema,
onSubmit: async (values) => {
if (installationData) {
try {
await createAppGithubMutation({
variables: {
input: {
name: values.name,
gitRepoFullName: values.repo.fullName,
branchName: values.gitBranch,
gitRepoId: values.repo.id,
githubInstallationId: values.installationId,
},
},
});
setIsTerminalVisible(true);
} catch (error) {
error.message === 'Not Found'
? toast.error(`Repository : ${values.repo.fullName} not found`)
: toast.error(error.message);
}
}
},
});
const handleNext = () => {
setIsTerminalVisible(false);
const appId = arrayOfCreateAppLogs[arrayOfCreateAppLogs.length - 1].message;
history.push(`app/${appId}`, 'new');
trackGoal(trackingGoals.createAppGithub, 0);
};
const handleOpen = () => {
const newWindow = window.open(
`https://github.com/apps/${config.githubAppName}/installations/new`,
'Install App',
'resizable=1, scrollbars=1, fullscreen=0, height=1000, width=1020,top=' +
window.screen.width +
', left=' +
window.screen.width +
', toolbar=0, menubar=0, status=0'
);
const timer = setInterval(async () => {
if (newWindow && newWindow.closed) {
setIsNewWindowClosed(true);
clearInterval(timer);
}
}, 100);
};
useEffect(() => {
if (!installationLoading && installationData && isNewWindowClosed) {
getRepos({
variables: {
installationId: installationData.githubInstallationId.id,
},
});
setIsNewWindowClosed(false);
}
}, [
installationData,
installationLoading,
isNewWindowClosed,
setIsNewWindowClosed,
getRepos,
]);
useEffect(() => {
if (
!installationLoading &&
installationData &&
!reposLoading &&
reposData &&
selectedRepo
) {
getBranches({
variables: {
installationId: installationData.githubInstallationId.id,
repositoryName: selectedRepo.name,
},
});
}
}, [
installationData,
installationLoading,
reposData,
reposLoading,
getBranches,
selectedRepo?.name,
selectedRepo,
]);
const handleChangeRepo = (active: RepoOption) => {
setSelectedRepo(active.value);
setSelectedBranch('');
if (installationData) {
formik.setValues({
name: active.value.name,
installationId: installationData?.githubInstallationId.id,
repo: {
fullName: active.value.fullName,
name: active.value.name,
id: active.value.id,
},
gitBranch: '',
});
}
};
const handleChangeBranch = (active: BranchOption) => {
setSelectedBranch(active.value.name);
formik.setFieldValue('gitBranch', active.value.name);
};
const repoOptions: RepoOption[] = [];
if (reposData && !reposLoading) {
reposData?.repositories.map((r) =>
repoOptions.push({ value: r, label: r.fullName })
);
}
let branchOptions: BranchOption[] = [];
if (branchesData && !branchesLoading) {
branchesData.branches.map((b) =>
branchOptions.push({ value: b, label: b.name })
);
}
useEffect(() => {
if (installationData && !installationLoading) {
getRepos({
variables: {
installationId: installationData?.githubInstallationId.id,
},
});
}
}, [installationLoading, getRepos, installationData]);
useEffect(() => {
if (selectedRepo && installationData) {
getBranches({
variables: {
installationId: installationData?.githubInstallationId.id,
repositoryName: selectedRepo.name,
},
});
}
}, [selectedRepo, getBranches, installationData]);
// Effect for app creation
useEffect(() => {
isAppCreationSuccess === AppCreationStatus.FAILURE && !isToastShown
? toast.error('Failed to create an app') && setIsToastShown(true)
: isAppCreationSuccess === AppCreationStatus.SUCCESS &&
!isToastShown &&
toast.success('App created successfully') &&
setIsToastShown(true);
}, [isToastShown, isAppCreationSuccess, toast]);
return (
<>
<HeaderContainer>
<Header />
</HeaderContainer>
<Container maxW="5xl" mt={10}>
{isTerminalVisible ? (
<>
<p className="mb-2 ">
Creating <b>{formik.values.name}</b> app from{' '}
<b>{formik.values.repo.name}</b>
</p>
<p className="text-gray-500 mb-2">
Creating app usually takes a couple of minutes. Breathe in,
breathe out, logs are about to appear below:
</p>
<Terminal className={'w-6/6'}>
{arrayOfCreateAppLogs.map((log) => (
<p
key={arrayOfCreateAppLogs.indexOf(log)}
className={'text-s leading-5'}
>
{log.message?.replaceAll('[1G', '')}
</p>
))}
</Terminal>
{!!isAppCreationSuccess &&
isAppCreationSuccess === AppCreationStatus.SUCCESS ? (
<div className="mt-12 flex justify-end">
<Button
onClick={() => handleNext()}
color="grey"
iconEnd={<FiArrowRight size={20} />}
>
Next
</Button>
</div>
) : !!isAppCreationSuccess &&
isAppCreationSuccess === AppCreationStatus.FAILURE ? (
<div className="mt-12 flex justify-start">
<Button
onClick={() => {
setIsTerminalVisible(false);
formik.resetForm();
}}
color="grey"
iconEnd={<FiArrowLeft size={20} />}
>
Back
</Button>
</div>
) : null}
</>
) : (
<>
<Heading as="h2" size="md">
Create a new GitHub application
</Heading>
{installationData &&
!installationLoading &&
reposData &&
!reposLoading ? (
<>
<Text color="gray.400">
When you push to Git, your application will be redeployed
automatically.
</Text>
<Grid
templateColumns={{
sm: 'repeat(1, 1fr)',
md: 'repeat(3, 1fr)',
}}
>
<GridItem colSpan={2}>
<Flex alignItems="center" mt="12">
<Avatar
size="sm"
name={user?.userName}
src={user?.avatarUrl}
/>
<Text ml="2" fontWeight="bold">
{user?.userName}
</Text>
</Flex>
<form onSubmit={formik.handleSubmit}>
<Box mt="8">
<FormLabel>Repository</FormLabel>
<Select
placeholder="Select repository"
isSearchable={false}
onChange={handleChangeRepo}
options={repoOptions}
/>
</Box>
<Text mt="1" color="gray.400" fontSize="sm">
Can't see your repo in the list?{' '}
<Link
onClick={() => setIsProceedModalOpen(true)}
textDecoration="underline"
>
Configure the GitHub app.
</Link>
</Text>
<Box mt="8">
<FormLabel>Branch to deploy</FormLabel>
<Select
placeholder="Select branch"
isSearchable={false}
disabled={
!branchesData ||
branchesLoading ||
reposLoading ||
!reposData
}
onChange={handleChangeBranch}
options={branchOptions}
/>
</Box>
<Box mt="8" display="flex" justifyContent="flex-end">
<Button
type="submit"
color="grey"
disabled={!selectedBranch || !selectedRepo}
isLoading={loading}
>
Create
</Button>
</Box>
</form>
</GridItem>
</Grid>
</>
) : !reposLoading && !installationLoading && !reposData ? (
<>
<Alert mb="4" mt="4" w="65%" status="info">
<AlertIcon />
<Box flex="1">
<AlertTitle>Set up repository permissions</AlertTitle>
<AlertDescription display="block">
First you will need to set up permissions for repositories
that you would like to use with Ledokku. Once that's done,
it's time to choose repo and branch that you would like to
create app from and off we go.
</AlertDescription>
</Box>
</Alert>
<Button
color="grey"
onClick={() => setIsProceedModalOpen(true)}
>
Set up permissions
</Button>
</>
) : (
<Spinner />
)}
</>
)}
<Modal
isOpen={isProceedModalOpen}
onClose={() => setIsProceedModalOpen(false)}
isCentered
>
<ModalOverlay />
<ModalContent>
<ModalHeader>Github setup info</ModalHeader>
<ModalCloseButton />
<ModalBody>
New window is about to open. After you are done selecting github
repos, close the window and refresh page.
</ModalBody>
<ModalFooter>
<Button
color="grey"
variant="outline"
className="mr-3"
onClick={() => setIsProceedModalOpen(false)}
>
Cancel
</Button>
<Button
color="grey"
onClick={() => {
handleOpen();
setIsProceedModalOpen(false);
}}
>
Proceed
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Container>
</>
);
}
Example #26
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 #27
Source File: dashboard.tsx From ledokku with MIT License | 4 votes |
Dashboard = () => {
// const history = useHistory();
const { data /* loading, error */ } = useDashboardQuery({
fetchPolicy: 'cache-and-network',
});
// TODO show loading
// TODO handle error
// TODO if no apps or dbs show onboarding screen
return (
<div>
<HeaderContainer>
<Header />
<HomeHeaderTabNav />
</HeaderContainer>
<Container maxW="5xl" py={6}>
<Box display="flex" justifyContent="flex-end" pb={6}>
<Link to="/create-database">
<Button colorScheme="gray" variant="outline" fontSize="sm" mr={3}>
Create database
</Button>
</Link>
<Link to="/create-app">
<Button colorScheme="gray" fontSize="sm">
Create app
</Button>
</Link>
</Box>
<Grid
as="main"
templateColumns="repeat(12, 1fr)"
gap={{ base: 6, md: 20 }}
pt={4}
>
<GridItem colSpan={{ base: 12, md: 7 }}>
<Heading as="h2" size="md" py={5}>
Apps
</Heading>
{data?.apps.length === 0 ? (
<Text fontSize="sm" color="gray.400">
No apps deployed.
</Text>
) : null}
{data?.apps.map((app) => (
<Box
key={app.id}
py={3}
borderBottom={'1px'}
borderColor="gray.200"
>
<Box mb={1} color="gray.900" fontWeight="medium">
<Link to={`/app/${app.id}`}>{app.name}</Link>
</Box>
<Box
fontSize="sm"
color="gray.400"
display="flex"
justifyContent="space-between"
>
<Text display="flex" alignItems="center">
<Box mr={1} as="span">
{app.appMetaGithub ? (
<GithubIcon size={16} />
) : (
<Image
boxSize="16px"
objectFit="cover"
src="/dokku.png"
alt="dokkuLogo"
/>
)}
</Box>
{app.appMetaGithub
? `${app.appMetaGithub.repoOwner}/${app.appMetaGithub.repoName}`
: ''}
</Text>
<Text>
Created on {format(new Date(app.createdAt), 'MM/DD/YYYY')}
</Text>
</Box>
</Box>
))}
<Heading as="h2" size="md" py={5} mt={8}>
Databases
</Heading>
{data?.databases.length === 0 ? (
<Text fontSize="sm" color="gray.400">
No databases created.
</Text>
) : null}
{data?.databases.map((database) => {
const DbIcon = dbTypeToIcon(database.type);
return (
<Box
key={database.id}
py={3}
borderBottom={'1px'}
borderColor="gray.200"
>
<Box mb={1} color="gray.900" fontWeight="medium">
<Link to={`/database/${database.id}`}>{database.name}</Link>
</Box>
<Box
fontSize="sm"
color="gray.400"
display="flex"
justifyContent="space-between"
>
<Text display="flex" alignItems="center">
<Box mr={1} as="span">
<DbIcon size={16} />
</Box>
{dbTypeToReadableName(database.type)}
</Text>
<Text>
Created on{' '}
{format(new Date(database.createdAt), 'MM/DD/YYYY')}
</Text>
</Box>
</Box>
);
})}
</GridItem>
<GridItem colSpan={{ base: 12, md: 5 }}>
<Heading as="h2" size="md" py={5}>
Latest activity
</Heading>
<Text fontSize="sm" color="gray.400">
Coming soon
</Text>
</GridItem>
</Grid>
</Container>
</div>
);
}