mirror of
https://github.com/snowball-tools/snowballtools-base.git
synced 2024-11-17 16:29:19 +00:00
Merge branch 'main' into andrehadianto/T-4904-home-org-switcher
This commit is contained in:
commit
aa5507f309
@ -1,10 +0,0 @@
|
||||
<svg width="333" height="5" viewBox="0 0 333 5" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 4L6.39555 1.30714C8.38078 0.47125 10.6192 0.47125 12.6045 1.30714L15.8955 2.69286C17.8808 3.52875 20.1192 3.52875 22.1045 2.69286L25.3955 1.30714C27.3808 0.47125 29.6192 0.47125 31.6045 1.30714L34.8955 2.69286C36.8808 3.52875 39.1192 3.52875 41.1045 2.69286L44.3955 1.30714C46.3808 0.47125 48.6192 0.47125 50.6045 1.30714L53.8955 2.69286C55.8808 3.52875 58.1192 3.52875 60.1045 2.69286L63.3955 1.30714C65.3808 0.47125 67.6192 0.47125 69.6045 1.30714L72.8955 2.69286C74.8808 3.52875 77.1192 3.52875 79.1045 2.69286L82.3955 1.30714C84.3808 0.47125 86.6192 0.47125 88.6045 1.30714L91.8955 2.69286C93.8808 3.52875 96.1192 3.52875 98.1045 2.69286L101.396 1.30714C103.381 0.47125 105.619 0.47125 107.604 1.30714L110.896 2.69286C112.881 3.52875 115.119 3.52875 117.104 2.69286L120.396 1.30714C122.381 0.47125 124.619 0.47125 126.604 1.30714L129.896 2.69286C131.881 3.52875 134.119 3.52875 136.104 2.69286L139.396 1.30714C141.381 0.47125 143.619 0.47125 145.604 1.30714L148.896 2.69286C150.881 3.52875 153.119 3.52875 155.104 2.69286L158.396 1.30714C160.381 0.47125 162.619 0.47125 164.604 1.30714L167.896 2.69286C169.881 3.52875 172.119 3.52875 174.104 2.69286L177.396 1.30714C179.381 0.47125 181.619 0.47125 183.604 1.30714L186.896 2.69286C188.881 3.52875 191.119 3.52875 193.104 2.69286L196.396 1.30714C198.381 0.47125 200.619 0.47125 202.604 1.30714L205.896 2.69286C207.881 3.52875 210.119 3.52875 212.104 2.69286L215.396 1.30714C217.381 0.47125 219.619 0.47125 221.604 1.30714L224.896 2.69286C226.881 3.52875 229.119 3.52875 231.104 2.69286L234.396 1.30714C236.381 0.47125 238.619 0.47125 240.604 1.30714L243.896 2.69286C245.881 3.52875 248.119 3.52875 250.104 2.69286L253.396 1.30714C255.381 0.47125 257.619 0.47125 259.604 1.30714L262.896 2.69286C264.881 3.52875 267.119 3.52875 269.104 2.69286L272.396 1.30714C274.381 0.47125 276.619 0.47125 278.604 1.30714L281.896 2.69286C283.881 3.52875 286.119 3.52875 288.104 2.69286L291.396 1.30714C293.381 0.47125 295.619 0.47125 297.604 1.30714L300.896 2.69286C302.881 3.52875 305.119 3.52875 307.104 2.69286L310.396 1.30714C312.381 0.47125 314.619 0.47125 316.604 1.30714L319.973 2.72566C321.913 3.54216 324.095 3.56183 326.049 2.78039L330.029 1.18845C331.936 0.425535 334.064 0.425535 335.971 1.18845L343 4" stroke="#DBEBF9"/>
|
||||
<path d="M6.39555 1.30714L0 4H342.5L336.027 1.27434C334.087 0.457837 331.905 0.438174 329.951 1.21961L326.049 2.78039C324.095 3.56183 321.913 3.54216 319.973 2.72566L316.604 1.30714C314.619 0.47125 312.381 0.47125 310.396 1.30714L307.104 2.69286C305.119 3.52875 302.881 3.52875 300.896 2.69286L297.604 1.30714C295.619 0.47125 293.381 0.47125 291.396 1.30714L288.104 2.69286C286.119 3.52875 283.881 3.52875 281.896 2.69286L278.604 1.30714C276.619 0.47125 274.381 0.47125 272.396 1.30714L269.104 2.69286C267.119 3.52875 264.881 3.52875 262.896 2.69286L259.604 1.30714C257.619 0.47125 255.381 0.47125 253.396 1.30714L250.104 2.69286C248.119 3.52875 245.881 3.52875 243.896 2.69286L240.604 1.30714C238.619 0.47125 236.381 0.47125 234.396 1.30714L231.104 2.69286C229.119 3.52875 226.881 3.52875 224.896 2.69286L221.604 1.30714C219.619 0.47125 217.381 0.47125 215.396 1.30714L212.104 2.69286C210.119 3.52875 207.881 3.52875 205.896 2.69286L202.604 1.30714C200.619 0.47125 198.381 0.47125 196.396 1.30714L193.104 2.69286C191.119 3.52875 188.881 3.52875 186.896 2.69286L183.604 1.30714C181.619 0.47125 179.381 0.47125 177.396 1.30714L174.104 2.69286C172.119 3.52875 169.881 3.52875 167.896 2.69286L164.604 1.30714C162.619 0.47125 160.381 0.47125 158.396 1.30714L155.104 2.69286C153.119 3.52875 150.881 3.52875 148.896 2.69286L145.604 1.30714C143.619 0.47125 141.381 0.47125 139.396 1.30714L136.104 2.69286C134.119 3.52875 131.881 3.52875 129.896 2.69286L126.604 1.30714C124.619 0.47125 122.381 0.47125 120.396 1.30714L117.104 2.69286C115.119 3.52875 112.881 3.52875 110.896 2.69286L107.604 1.30714C105.619 0.47125 103.381 0.47125 101.396 1.30714L98.1045 2.69286C96.1192 3.52875 93.8808 3.52875 91.8955 2.69286L88.6045 1.30714C86.6192 0.47125 84.3808 0.47125 82.3955 1.30714L79.1045 2.69286C77.1192 3.52875 74.8808 3.52875 72.8955 2.69286L69.6045 1.30714C67.6192 0.47125 65.3808 0.47125 63.3955 1.30714L60.1045 2.69286C58.1192 3.52875 55.8808 3.52875 53.8955 2.69286L50.6045 1.30714C48.6192 0.47125 46.3808 0.47125 44.3955 1.30714L41.1045 2.69286C39.1192 3.52875 36.8808 3.52875 34.8955 2.69286L31.6045 1.30714C29.6192 0.47125 27.3808 0.47125 25.3955 1.30714L22.1045 2.69286C20.1192 3.52875 17.8808 3.52875 15.8955 2.69286L12.6045 1.30714C10.6192 0.47125 8.38078 0.47125 6.39555 1.30714Z" fill="url(#paint0_linear_1729_11298)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1729_11298" x1="171.25" y1="0" x2="171.25" y2="4" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E6F4FF"/>
|
||||
<stop offset="1" stop-color="#F9FCFF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.8 KiB |
4
packages/frontend/public/wavy-border-fill.svg
Normal file
4
packages/frontend/public/wavy-border-fill.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="19" height="4" viewBox="0 0 19 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M-12.6045 1.27694L-19 3.9698H37.5L34.8955 2.66266L31.6045 1.27694C29.6192 0.441052 27.3808 0.441052 25.3955 1.27694L22.1045 2.66266C20.1192 3.49855 17.8808 3.49855 15.8955 2.66266L12.6045 1.27694C10.6192 0.441052 8.38078 0.441052 6.39555 1.27694L3.10446 2.66266C1.11922 3.49855 -1.11922 3.49855 -3.10445 2.66266L-6.39554 1.27694C-8.38078 0.441052 -10.6192 0.441052 -12.6045 1.27694Z" fill="currentColor"/>
|
||||
<path d="M25.7836 1.58773L22.4925 2.97346C20.3832 3.86159 18.0049 3.86159 15.8955 2.97346L12.6045 1.58774C10.7433 0.804089 8.64476 0.804088 6.7836 1.58773L3.49251 2.97346C1.3832 3.86159 -0.99514 3.86159 -3.10445 2.97346L-6.39554 1.58774C-8.2567 0.804089 -10.3552 0.804088 -12.2164 1.58773L-18.6119 4.2806L-19 3.35896L-12.6045 0.666099C-10.4951 -0.222033 -8.1168 -0.222033 -6.00749 0.6661L-2.7164 2.05182C-0.855238 2.83547 1.2433 2.83547 3.10446 2.05182L6.39555 0.666099C8.50486 -0.222033 10.8832 -0.222033 12.9925 0.6661L16.2836 2.05182C18.1448 2.83547 20.2433 2.83547 22.1045 2.05182L25.3955 0.666099L25.7836 1.58773Z" fill="currentColor"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
15
packages/frontend/public/wavy-border-line-and-fill.svg
Normal file
15
packages/frontend/public/wavy-border-line-and-fill.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<svg width="19" height="4" viewBox="0 0 19 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1177_19315)">
|
||||
<path d="M-12.6045 1.27694L-19 3.9698H37.5L34.8955 2.66266L31.6045 1.27694C29.6192 0.441052 27.3808 0.441052 25.3955 1.27694L22.1045 2.66266C20.1192 3.49855 17.8808 3.49855 15.8955 2.66266L12.6045 1.27694C10.6192 0.441052 8.38078 0.441052 6.39555 1.27694L3.10446 2.66266C1.11922 3.49855 -1.11922 3.49855 -3.10445 2.66266L-6.39554 1.27694C-8.38078 0.441052 -10.6192 0.441052 -12.6045 1.27694Z" fill="url(#paint0_linear_1177_19315)"/>
|
||||
<path d="M25.7836 1.58773L22.4925 2.97346C20.3832 3.86159 18.0049 3.86159 15.8955 2.97346L12.6045 1.58774C10.7433 0.804089 8.64476 0.804088 6.7836 1.58773L3.49251 2.97346C1.3832 3.86159 -0.99514 3.86159 -3.10445 2.97346L-6.39554 1.58774C-8.2567 0.804089 -10.3552 0.804088 -12.2164 1.58773L-18.6119 4.2806L-19 3.35896L-12.6045 0.666099C-10.4951 -0.222033 -8.1168 -0.222033 -6.00749 0.6661L-2.7164 2.05182C-0.855238 2.83547 1.2433 2.83547 3.10446 2.05182L6.39555 0.666099C8.50486 -0.222033 10.8832 -0.222033 12.9925 0.6661L16.2836 2.05182C18.1448 2.83547 20.2433 2.83547 22.1045 2.05182L25.3955 0.666099L25.7836 1.58773Z" fill="#DBEBF9"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1177_19315" x1="9.25" y1="0.650024" x2="9.25" y2="3.9698" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#EBF6FF"/>
|
||||
<stop offset="1" stop-color="#F7FCFF" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_1177_19315">
|
||||
<rect width="19" height="4" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
10
packages/frontend/public/wavy-border-line.svg
Normal file
10
packages/frontend/public/wavy-border-line.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="19" height="4" viewBox="0 0 19 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1175_19292)">
|
||||
<path d="M-9.5 0L-3.10445 2.69286C-1.11922 3.52875 1.11922 3.52875 3.10446 2.69286L6.39555 1.30714C8.38078 0.47125 10.6192 0.47125 12.6045 1.30714L15.8955 2.69286C17.8808 3.52875 20.1192 3.52875 22.1045 2.69286L28.5 0" stroke="#082F56" stroke-opacity="0.1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1175_19292">
|
||||
<rect width="19" height="4" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 507 B |
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
import OrgSlug from './pages/OrgSlug';
|
||||
import Projects from './pages/org-slug';
|
||||
import Settings from './pages/org-slug/Settings';
|
||||
import {
|
||||
@ -11,11 +10,12 @@ import {
|
||||
import ProjectSearchLayout from './layouts/ProjectSearch';
|
||||
import Index from './pages';
|
||||
import Login from './pages/Login';
|
||||
import { DashboardLayout } from 'pages/org-slug/layout';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: ':orgSlug',
|
||||
element: <OrgSlug />,
|
||||
element: <DashboardLayout />,
|
||||
children: [
|
||||
{
|
||||
element: <ProjectSearchLayout />,
|
||||
|
@ -2,31 +2,36 @@ export default [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Progressive Web App (PWA)',
|
||||
icon: '^',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${process.env.REACT_APP_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Image Upload PWA',
|
||||
icon: '^',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${process.env.REACT_APP_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Kotlin',
|
||||
icon: '^',
|
||||
icon: 'kotlin',
|
||||
repoFullName: '',
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'React Native',
|
||||
icon: '^',
|
||||
icon: 'react-native',
|
||||
repoFullName: '',
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Swift',
|
||||
icon: '^',
|
||||
icon: 'swift',
|
||||
repoFullName: '',
|
||||
isComingSoon: true,
|
||||
},
|
||||
];
|
||||
|
@ -8,6 +8,7 @@ export const projectCardTheme = tv({
|
||||
'rounded-2xl',
|
||||
'flex',
|
||||
'flex-col',
|
||||
'group',
|
||||
],
|
||||
upperContent: ['px-4', 'py-4', 'flex', 'items-start', 'gap-3', 'relative'],
|
||||
content: ['flex', 'flex-col', 'gap-1', 'flex-1'],
|
||||
@ -20,13 +21,15 @@ export const projectCardTheme = tv({
|
||||
description: ['text-xs', 'text-elements-low-em'],
|
||||
icons: ['flex', 'items-center', 'gap-1'],
|
||||
lowerContent: [
|
||||
'bg-surface-card-hovered',
|
||||
'transition-colors',
|
||||
'duration-150',
|
||||
'px-4',
|
||||
'py-4',
|
||||
'flex',
|
||||
'flex-col',
|
||||
'gap-2',
|
||||
'rounded-b-2xl',
|
||||
'group-hover:bg-surface-card-hovered',
|
||||
],
|
||||
latestDeployment: ['flex', 'items-center', 'gap-2'],
|
||||
deploymentStatusContainer: [
|
||||
@ -46,6 +49,12 @@ export const projectCardTheme = tv({
|
||||
'items-center',
|
||||
'gap-2',
|
||||
],
|
||||
wavyBorder: [
|
||||
'bg-surface-card',
|
||||
'transition-colors',
|
||||
'duration-150',
|
||||
'group-hover:bg-surface-card-hovered',
|
||||
],
|
||||
},
|
||||
variants: {
|
||||
status: {
|
||||
|
@ -1,4 +1,8 @@
|
||||
import React, { ComponentPropsWithoutRef, MouseEvent } from 'react';
|
||||
import React, {
|
||||
ComponentPropsWithoutRef,
|
||||
MouseEvent,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import { ProjectCardTheme, projectCardTheme } from './ProjectCard.theme';
|
||||
import { Project } from 'gql-client';
|
||||
import { Button } from 'components/shared/Button';
|
||||
@ -11,7 +15,7 @@ import {
|
||||
WarningDiamondIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { relativeTimeMs } from 'utils/time';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Avatar } from 'components/shared/Avatar';
|
||||
import { getInitials } from 'utils/geInitials';
|
||||
import {
|
||||
@ -27,6 +31,8 @@ export interface ProjectCardProps
|
||||
project: Project;
|
||||
}
|
||||
|
||||
// TODO: Update the whole component to use `Link` from `react-router-dom` and remove the `useNavigate` hook,
|
||||
// currently it's not possible to use `Link` because the dot menu is not a direct child of the `Link` component
|
||||
export const ProjectCard = ({
|
||||
className,
|
||||
project,
|
||||
@ -38,14 +44,24 @@ export const ProjectCard = ({
|
||||
// TODO: Update this to use the actual status from the API
|
||||
const hasError = status === 'failure';
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleOptionsClick = (
|
||||
e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>,
|
||||
) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
navigate(`projects/${project.id}`);
|
||||
}, [project.id, navigate]);
|
||||
|
||||
return (
|
||||
<div {...props} className={theme.wrapper({ className })}>
|
||||
<div
|
||||
{...props}
|
||||
className={theme.wrapper({ className })}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{/* Upper content */}
|
||||
<div className={theme.upperContent()}>
|
||||
{/* Icon container */}
|
||||
@ -54,14 +70,13 @@ export const ProjectCard = ({
|
||||
imageSrc={project.icon}
|
||||
initials={getInitials(project.name)}
|
||||
/>
|
||||
{/* </div> */}
|
||||
{/* Title and website */}
|
||||
<Link to={`projects/${project.id}`} className={theme.content()}>
|
||||
<div className={theme.content()}>
|
||||
<p className={theme.title()}>{project.name}</p>
|
||||
<p className={theme.description()}>
|
||||
{project.deployments[0]?.domain?.name ?? 'No domain'}
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
{/* Icons */}
|
||||
<div className={theme.icons()}>
|
||||
{hasError && <WarningDiamondIcon className="text-elements-danger" />}
|
||||
@ -87,7 +102,7 @@ export const ProjectCard = ({
|
||||
</div>
|
||||
</div>
|
||||
{/* Wave */}
|
||||
<WavyBorder />
|
||||
<WavyBorder variant="stroke-and-fill" className={theme.wavyBorder()} />
|
||||
{/* Lower content */}
|
||||
<div className={theme.lowerContent()}>
|
||||
{/* Latest deployment */}
|
||||
|
@ -1,53 +0,0 @@
|
||||
import React from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
import { IconButton, Typography } from '@material-tailwind/react';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface TemplateDetails {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
interface TemplateCardProps {
|
||||
template: TemplateDetails;
|
||||
isGitAuth: boolean;
|
||||
}
|
||||
|
||||
const CardDetails = ({ template }: { template: TemplateDetails }) => {
|
||||
return (
|
||||
<div className="h-14 group bg-gray-200 border-gray-200 rounded-lg shadow p-4 flex items-center justify-between">
|
||||
<Typography className="grow" placeholder={''}>
|
||||
{template.icon} {template.name}
|
||||
</Typography>
|
||||
<div>
|
||||
<IconButton
|
||||
size="sm"
|
||||
className="rounded-full hidden group-hover:block"
|
||||
placeholder={''}
|
||||
>
|
||||
{'>'}
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TemplateCard: React.FC<TemplateCardProps> = ({ template, isGitAuth }) => {
|
||||
return isGitAuth ? (
|
||||
<Link to={`template?templateId=${template.id}`}>
|
||||
<CardDetails template={template} />
|
||||
</Link>
|
||||
) : (
|
||||
<a
|
||||
onClick={() =>
|
||||
toast.error('Connect Git account to start with a template')
|
||||
}
|
||||
>
|
||||
<CardDetails template={template} />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateCard;
|
@ -0,0 +1,85 @@
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
ArrowRightCircleIcon,
|
||||
ClockOutlineIcon,
|
||||
TemplateIcon,
|
||||
TemplateIconType,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { Tag } from 'components/shared/Tag';
|
||||
import React, { ComponentPropsWithoutRef, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
import { cn } from 'utils/classnames';
|
||||
|
||||
export interface TemplateDetail {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
repoFullName?: string;
|
||||
isComingSoon?: boolean;
|
||||
}
|
||||
|
||||
export interface TemplateCardProps extends ComponentPropsWithoutRef<'div'> {
|
||||
template: TemplateDetail;
|
||||
isGitAuth: boolean;
|
||||
}
|
||||
|
||||
export const TemplateCard = ({ template, isGitAuth }: TemplateCardProps) => {
|
||||
const { toast, dismiss } = useToast();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (template?.isComingSoon) {
|
||||
return toast({
|
||||
id: 'coming-soon',
|
||||
title: 'This template is coming soon',
|
||||
variant: 'info',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
if (isGitAuth) {
|
||||
return navigate(`/template?templateId=${template.id}`);
|
||||
}
|
||||
return toast({
|
||||
id: 'connect-git-account',
|
||||
title: 'Connect Git account to start with a template',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}, [isGitAuth, navigate, template, toast]);
|
||||
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
'flex items-center gap-3 px-3 py-3 bg-base-bg-alternate hover:bg-base-bg-emphasized rounded-2xl group relative',
|
||||
{
|
||||
'cursor-default': template?.isComingSoon,
|
||||
},
|
||||
)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{/* Icon */}
|
||||
<div className="px-1 py-1 rounded-xl bg-base-bg border border-border-interactive/10 shadow-card-sm">
|
||||
<TemplateIcon type={template.icon as TemplateIconType} />
|
||||
</div>
|
||||
{/* Name */}
|
||||
<p className="flex-1 text-left text-sm tracking-tighter text-elements-high-em">
|
||||
{template.name}
|
||||
</p>
|
||||
{template?.isComingSoon ? (
|
||||
<Tag size="xs" type="neutral" leftIcon={<ClockOutlineIcon />}>
|
||||
Soon
|
||||
</Tag>
|
||||
) : (
|
||||
<Button
|
||||
variant="tertiary"
|
||||
size="sm"
|
||||
iconOnly
|
||||
className="group-hover:flex hidden absolute right-3"
|
||||
>
|
||||
<ArrowRightCircleIcon />
|
||||
</Button>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './TemplateCard';
|
@ -150,7 +150,7 @@ export const buttonTheme = tv(
|
||||
{
|
||||
size: 'md',
|
||||
iconOnly: true,
|
||||
class: ['py-3.25', 'px-3.25'],
|
||||
class: ['py-3', 'px-3'],
|
||||
},
|
||||
{
|
||||
size: 'sm',
|
||||
|
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from './CustomIcon';
|
||||
|
||||
export const ArrowRightCircleIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="17"
|
||||
height="16"
|
||||
viewBox="0 0 17 16"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M15.3333 8C15.3333 4.3181 12.3486 1.33333 8.66667 1.33333C4.98477 1.33333 2 4.3181 2 8C2 11.6819 4.98477 14.6667 8.66667 14.6667C12.3486 14.6667 15.3333 11.6819 15.3333 8ZM10.2929 8.5L8.97978 9.81311C8.78452 10.0084 8.78452 10.325 8.97978 10.5202C9.17504 10.7155 9.49162 10.7155 9.68689 10.5202L11.3821 8.82495C11.8378 8.36934 11.8378 7.63065 11.3821 7.17504L9.68689 5.47977C9.49162 5.28451 9.17504 5.28451 8.97978 5.47977C8.78452 5.67504 8.78452 5.99162 8.97978 6.18688L10.2929 7.5H5.83333C5.55719 7.5 5.33333 7.72385 5.33333 8C5.33333 8.27614 5.55719 8.5 5.83333 8.5H10.2929Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from './CustomIcon';
|
||||
|
||||
export const ClockOutlineIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.99984 5V8L9.99984 10M14.3332 8C14.3332 11.4978 11.4976 14.3333 7.99984 14.3333C4.50203 14.3333 1.6665 11.4978 1.6665 8C1.6665 4.5022 4.50203 1.66667 7.99984 1.66667C11.4976 1.66667 14.3332 4.5022 14.3332 8Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
@ -35,5 +35,10 @@ export * from './GitHubLogo';
|
||||
export * from './ClockIcon';
|
||||
export * from './HorizontalDotIcon';
|
||||
export * from './WarningDiamondIcon';
|
||||
export * from './ArrowRightCircleIcon';
|
||||
export * from './ClockOutlineIcon';
|
||||
export * from './ArrowRightCircleFilledIcon';
|
||||
export * from './SquigglyLine';
|
||||
|
||||
// Templates
|
||||
export * from './templates';
|
||||
|
@ -0,0 +1,130 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from '../CustomIcon';
|
||||
|
||||
export const KotlinIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="41"
|
||||
height="40"
|
||||
viewBox="0 0 41 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<g filter="url(#filter0_ii_417_1111)">
|
||||
<rect
|
||||
x="0.333496"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="8"
|
||||
fill="url(#paint0_linear_417_1111)"
|
||||
/>
|
||||
<rect
|
||||
x="0.74421"
|
||||
y="0.410714"
|
||||
width="39.1786"
|
||||
height="39.1786"
|
||||
rx="7.58929"
|
||||
stroke="#082F56"
|
||||
strokeOpacity="0.1"
|
||||
strokeWidth="0.821429"
|
||||
/>
|
||||
<g clipPath="url(#clip0_417_1111)">
|
||||
<path
|
||||
d="M30.1908 29.8591H10.4766V10.1448H30.1908L20.3337 20.0019L30.1908 29.8591Z"
|
||||
fill="url(#paint1_linear_417_1111)"
|
||||
/>
|
||||
<path
|
||||
d="M30.1908 29.8591H10.4766V10.1448H30.1908L20.3337 20.0019L30.1908 29.8591Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_ii_417_1111"
|
||||
x="0.333496"
|
||||
y="0"
|
||||
width="40"
|
||||
height="40"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="-2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_417_1111"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect1_innerShadow_417_1111"
|
||||
result="effect2_innerShadow_417_1111"
|
||||
/>
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="paint0_linear_417_1111"
|
||||
x1="40.3335"
|
||||
y1="-1.19209e-06"
|
||||
x2="0.333497"
|
||||
y2="40"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.00343514" stopColor="#E44857" />
|
||||
<stop offset="0.4689" stopColor="#C711E1" />
|
||||
<stop offset="1" stopColor="#7F52FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_417_1111"
|
||||
x1="30.1908"
|
||||
y1="10.1448"
|
||||
x2="10.4766"
|
||||
y2="29.8591"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.00343514" stopColor="#E44857" />
|
||||
<stop offset="0.4689" stopColor="#C711E1" />
|
||||
<stop offset="1" stopColor="#7F52FF" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_417_1111">
|
||||
<rect
|
||||
width="19.7143"
|
||||
height="19.7143"
|
||||
fill="white"
|
||||
transform="translate(10.4766 10.1429)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
@ -0,0 +1,88 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from '../CustomIcon';
|
||||
|
||||
export const PWAIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<g filter="url(#filter0_ii_417_1121)">
|
||||
<rect width="40" height="40" rx="8" fill="#12B785" />
|
||||
<rect
|
||||
x="0.410714"
|
||||
y="0.410714"
|
||||
width="39.1786"
|
||||
height="39.1786"
|
||||
rx="7.58929"
|
||||
stroke="#082F56"
|
||||
strokeOpacity="0.1"
|
||||
strokeWidth="0.821429"
|
||||
/>
|
||||
<path
|
||||
d="M24.5832 26.25H26.2498M12.9165 24.5833V14.5833C12.9165 13.6628 13.6627 12.9167 14.5832 12.9167H25.4165C26.337 12.9167 27.0832 13.6628 27.0832 14.5833V17.0833M12.9165 24.5833H11.6665V25.4167C11.6665 26.3371 12.4127 27.0833 13.3332 27.0833H22.0832M12.9165 24.5833H22.0832M27.0832 17.0833H23.7498C22.8294 17.0833 22.0832 17.8295 22.0832 18.75V26.25C22.0832 27.1705 22.8294 27.9167 23.7498 27.9167H27.0832C28.0036 27.9167 28.7498 27.1705 28.7498 26.25V18.75C28.7498 17.8295 28.0036 17.0833 27.0832 17.0833Z"
|
||||
stroke="white"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_ii_417_1121"
|
||||
x="0"
|
||||
y="0"
|
||||
width="40"
|
||||
height="40"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="-2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_417_1121"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect1_innerShadow_417_1121"
|
||||
result="effect2_innerShadow_417_1121"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
@ -0,0 +1,98 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from '../CustomIcon';
|
||||
|
||||
export const ReactNativeIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="40"
|
||||
height="40"
|
||||
viewBox="0 0 40 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<g filter="url(#filter0_ii_417_1095)">
|
||||
<rect width="40" height="40" rx="8" fill="#00C0F5" />
|
||||
<rect
|
||||
x="0.410714"
|
||||
y="0.410714"
|
||||
width="39.1786"
|
||||
height="39.1786"
|
||||
rx="7.58929"
|
||||
stroke="#082F56"
|
||||
strokeOpacity="0.1"
|
||||
strokeWidth="0.821429"
|
||||
/>
|
||||
<path
|
||||
d="M20.0004 21.7819C20.9849 21.7819 21.783 20.9838 21.783 19.9993C21.783 19.0148 20.9849 18.2167 20.0004 18.2167C19.0159 18.2167 18.2178 19.0148 18.2178 19.9993C18.2178 20.9838 19.0159 21.7819 20.0004 21.7819Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M19.9998 23.6515C25.2825 23.6515 29.565 22.0164 29.565 19.9993C29.565 17.9823 25.2825 16.3472 19.9998 16.3472C14.7171 16.3472 10.4346 17.9823 10.4346 19.9993C10.4346 22.0164 14.7171 23.6515 19.9998 23.6515Z"
|
||||
stroke="white"
|
||||
/>
|
||||
<path
|
||||
d="M16.8372 21.8246C19.4786 26.3996 23.0359 29.2908 24.7827 28.2822C26.5295 27.2737 25.8043 22.7474 23.163 18.1724C20.5216 13.5975 16.9643 10.7063 15.2175 11.7148C13.4707 12.7233 14.1959 17.2496 16.8372 21.8246Z"
|
||||
stroke="white"
|
||||
/>
|
||||
<path
|
||||
d="M16.837 18.173C14.1956 22.7479 13.4704 27.2742 15.2172 28.2828C16.964 29.2913 20.5213 26.4001 23.1627 21.8251C25.8041 17.2502 26.5292 12.7238 24.7824 11.7153C23.0356 10.7068 19.4783 13.598 16.837 18.173Z"
|
||||
stroke="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_ii_417_1095"
|
||||
x="0"
|
||||
y="0"
|
||||
width="40"
|
||||
height="40"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="-2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_417_1095"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect1_innerShadow_417_1095"
|
||||
result="effect2_innerShadow_417_1095"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,42 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { CustomIconProps } from '../CustomIcon';
|
||||
import { ReactNativeIcon } from './ReactNativeIcon';
|
||||
import { cloneIcon } from 'utils/cloneIcon';
|
||||
import { PWAIcon } from './PWAIcon';
|
||||
import { WebAppIcon } from './WebAppIcon';
|
||||
import { KotlinIcon } from './KotlinIcon';
|
||||
import { SwitfIcon } from './SwiftIcon';
|
||||
|
||||
const TEMPLATE_ICONS = [
|
||||
'react-native',
|
||||
'pwa',
|
||||
'web',
|
||||
'kotlin',
|
||||
'swift',
|
||||
] as const;
|
||||
export type TemplateIconType = (typeof TEMPLATE_ICONS)[number];
|
||||
|
||||
export interface TemplateIconProps extends CustomIconProps {
|
||||
type: TemplateIconType;
|
||||
}
|
||||
|
||||
export const TemplateIcon = ({ type, ...props }: TemplateIconProps) => {
|
||||
const renderIcon = useMemo(() => {
|
||||
switch (type) {
|
||||
case 'react-native':
|
||||
return <ReactNativeIcon />;
|
||||
case 'pwa':
|
||||
return <PWAIcon />;
|
||||
case 'web':
|
||||
return <WebAppIcon />;
|
||||
case 'kotlin':
|
||||
return <KotlinIcon />;
|
||||
case 'swift':
|
||||
return <SwitfIcon />;
|
||||
default:
|
||||
throw new Error(`Invalid template icon type: ${type}`);
|
||||
}
|
||||
}, [type]);
|
||||
|
||||
return cloneIcon(renderIcon, props) as JSX.Element;
|
||||
};
|
@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import { CustomIcon, CustomIconProps } from '../CustomIcon';
|
||||
|
||||
export const WebAppIcon = (props: CustomIconProps) => {
|
||||
return (
|
||||
<CustomIcon
|
||||
width="41"
|
||||
height="40"
|
||||
viewBox="0 0 41 40"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<g filter="url(#filter0_ii_417_1126)">
|
||||
<rect x="0.666504" width="40" height="40" rx="8" fill="#F63184" />
|
||||
<rect
|
||||
x="1.07722"
|
||||
y="0.410714"
|
||||
width="39.1786"
|
||||
height="39.1786"
|
||||
rx="7.58929"
|
||||
stroke="#082F56"
|
||||
strokeOpacity="0.1"
|
||||
strokeWidth="0.821429"
|
||||
/>
|
||||
<path
|
||||
d="M20.6667 27.9167C25.0389 27.9167 28.5833 24.3723 28.5833 20C28.5833 15.6278 25.0389 12.0833 20.6667 12.0833M20.6667 27.9167C16.2944 27.9167 12.75 24.3723 12.75 20C12.75 15.6278 16.2944 12.0833 20.6667 12.0833M20.6667 27.9167C18.8257 27.9167 17.3333 24.3723 17.3333 20C17.3333 15.6278 18.8257 12.0833 20.6667 12.0833M20.6667 27.9167C22.5076 27.9167 24 24.3723 24 20C24 15.6278 22.5076 12.0833 20.6667 12.0833M28.1667 20H13.1667"
|
||||
stroke="white"
|
||||
strokeLinecap="square"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_ii_417_1126"
|
||||
x="0.666504"
|
||||
y="0"
|
||||
width="40"
|
||||
height="40"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset dy="-2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_417_1126"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="2" />
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect1_innerShadow_417_1126"
|
||||
result="effect2_innerShadow_417_1126"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</CustomIcon>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './TemplateIcon';
|
@ -57,7 +57,7 @@ export const Sidebar = () => {
|
||||
}, [disconnect, navigate]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full px-6 py-8 gap-9">
|
||||
<nav className="flex flex-col h-full px-6 py-8 gap-9">
|
||||
{/* Logo */}
|
||||
<Link to={`/${orgSlug}`}>
|
||||
<div className="flex items-center gap-3 px-2">
|
||||
@ -113,6 +113,6 @@ export const Sidebar = () => {
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
@ -1,16 +1,44 @@
|
||||
import React, { ComponentPropsWithoutRef } from 'react';
|
||||
import React, { ComponentPropsWithoutRef, useMemo } from 'react';
|
||||
import { cn } from 'utils/classnames';
|
||||
|
||||
export interface WavyBorderProps extends ComponentPropsWithoutRef<'div'> {}
|
||||
type WaveBorderVariant = 'stroke' | 'stroke-and-fill';
|
||||
|
||||
export interface WavyBorderProps extends ComponentPropsWithoutRef<'div'> {
|
||||
variant?: WaveBorderVariant;
|
||||
}
|
||||
|
||||
export const WavyBorder = ({
|
||||
className,
|
||||
children,
|
||||
variant = 'stroke',
|
||||
...props
|
||||
}: WavyBorderProps) => {
|
||||
const imageSrc = useMemo(() => {
|
||||
switch (variant) {
|
||||
case 'stroke-and-fill':
|
||||
return '/wavy-border-line-and-fill.svg';
|
||||
case 'stroke':
|
||||
default:
|
||||
return '/wavy-border-line.svg';
|
||||
}
|
||||
}, [variant]);
|
||||
|
||||
return (
|
||||
<div {...props} className={cn('wave', className)}>
|
||||
{children}
|
||||
<div
|
||||
{...props}
|
||||
className={cn(className)}
|
||||
style={{
|
||||
// If adding background beneath the wave, we use mask
|
||||
mask: `url(/wavy-border-fill.svg) repeat-x top`,
|
||||
WebkitMask: `url(/wavy-border-fill.svg) repeat-x top`,
|
||||
}}
|
||||
>
|
||||
{/* Wave */}
|
||||
<div
|
||||
className="h-1 w-full bg-repeat-x bg-top"
|
||||
style={{
|
||||
backgroundImage: `url(${imageSrc})`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -153,12 +153,4 @@
|
||||
.focus-ring {
|
||||
@apply focus-visible:ring-[3px] focus-visible:ring-snowball-200 focus-visible:ring-offset-1 focus-visible:ring-offset-snowball-500 focus-visible:outline-none;
|
||||
}
|
||||
|
||||
.wave {
|
||||
background-image: url('../public/wave-border.svg');
|
||||
background-repeat: repeat-x;
|
||||
background-position: top;
|
||||
background-size: cover;
|
||||
@apply w-full h-1;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { OctokitProvider } from 'context/OctokitContext';
|
||||
import { Sidebar } from 'components/shared/Sidebar';
|
||||
|
||||
const OrgSlug = () => {
|
||||
return (
|
||||
<div className="grid grid-cols-5 h-screen bg-snowball-50">
|
||||
<>
|
||||
<div className="h-full">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div className="col-span-4 h-full p-3 overflow-y-hidden">
|
||||
<div className="bg-white rounded-3xl h-full overflow-y-auto shadow-sm">
|
||||
<OctokitProvider>
|
||||
<Outlet />
|
||||
</OctokitProvider>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrgSlug;
|
31
packages/frontend/src/pages/org-slug/layout.tsx
Normal file
31
packages/frontend/src/pages/org-slug/layout.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Sidebar } from 'components/shared/Sidebar';
|
||||
import { OctokitProvider } from 'context/OctokitContext';
|
||||
import React, { ComponentPropsWithoutRef } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { cn } from 'utils/classnames';
|
||||
|
||||
export interface DashboardLayoutProps
|
||||
extends ComponentPropsWithoutRef<'section'> {}
|
||||
|
||||
export const DashboardLayout = ({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: DashboardLayoutProps) => {
|
||||
return (
|
||||
<section
|
||||
{...props}
|
||||
className={cn('grid grid-cols-5 h-screen bg-snowball-50', className)}
|
||||
>
|
||||
<Sidebar />
|
||||
<div className="col-span-4 h-full px-3 py-3 overflow-y-hidden">
|
||||
<div className="rounded-3xl bg-base-bg h-full shadow-card overflow-y-auto relative">
|
||||
<OctokitProvider>
|
||||
<Outlet />
|
||||
</OctokitProvider>
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
};
|
@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Outlet, Link, useParams } from 'react-router-dom';
|
||||
|
||||
import { IconButton } from '@material-tailwind/react';
|
||||
|
||||
import HorizontalLine from '../../../components/HorizontalLine';
|
||||
|
||||
const CreateProject = () => {
|
||||
const { orgSlug } = useParams();
|
||||
return (
|
||||
<div className="h-full">
|
||||
<div className="flex p-4 items-center">
|
||||
<div className="grow">
|
||||
<h3 className="text-gray-750 text-2xl">Create new project</h3>
|
||||
</div>
|
||||
<div>
|
||||
<Link to={`/${orgSlug}`}>
|
||||
<IconButton
|
||||
className="rounded-full"
|
||||
variant="outlined"
|
||||
placeholder={''}
|
||||
>
|
||||
X
|
||||
</IconButton>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<HorizontalLine />
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateProject;
|
@ -1,29 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
import templates from '../../../../assets/templates';
|
||||
import TemplateCard from '../../../../components/projects/create/TemplateCard';
|
||||
import RepositoryList from '../../../../components/projects/create/RepositoryList';
|
||||
import ConnectAccount from '../../../../components/projects/create/ConnectAccount';
|
||||
import { useOctokit } from '../../../../context/OctokitContext';
|
||||
import templates from 'assets/templates';
|
||||
import RepositoryList from 'components/projects/create/RepositoryList';
|
||||
import ConnectAccount from 'components/projects/create/ConnectAccount';
|
||||
import { useOctokit } from 'context/OctokitContext';
|
||||
import { Heading } from 'components/shared/Heading';
|
||||
import { TemplateCard } from 'components/projects/create/TemplateCard';
|
||||
|
||||
const NewProject = () => {
|
||||
const { octokit, updateAuth, isAuth } = useOctokit();
|
||||
|
||||
return isAuth ? (
|
||||
<>
|
||||
<h5 className="mt-4 ml-4">Start with template</h5>
|
||||
<div className="grid grid-cols-3 p-4 gap-4">
|
||||
{templates.map((template) => {
|
||||
return (
|
||||
<TemplateCard
|
||||
isGitAuth={Boolean(octokit)}
|
||||
template={template}
|
||||
key={template.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<div className="space-y-3">
|
||||
<Heading as="h3" className="font-medium text-lg">
|
||||
Start with template
|
||||
</Heading>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3">
|
||||
{templates.map((template) => {
|
||||
return (
|
||||
<TemplateCard
|
||||
isGitAuth={Boolean(octokit)}
|
||||
template={template}
|
||||
key={template.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<h5 className="mt-4 ml-4">Import a repository</h5>
|
||||
<Heading as="h3" className="font-medium text-lg mt-10">
|
||||
Import a repository
|
||||
</Heading>
|
||||
<RepositoryList octokit={octokit} />
|
||||
</>
|
||||
) : (
|
||||
|
@ -0,0 +1,39 @@
|
||||
import React, { ComponentPropsWithoutRef } from 'react';
|
||||
import { Link, Outlet, useParams } from 'react-router-dom';
|
||||
|
||||
import { Heading } from 'components/shared/Heading';
|
||||
import { WavyBorder } from 'components/shared/WavyBorder';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { CrossIcon } from 'components/shared/CustomIcon';
|
||||
import { cn } from 'utils/classnames';
|
||||
|
||||
export interface CreateProjectLayoutProps
|
||||
extends ComponentPropsWithoutRef<'section'> {}
|
||||
|
||||
export const CreateProjectLayout = ({
|
||||
className,
|
||||
...props
|
||||
}: CreateProjectLayoutProps) => {
|
||||
const { orgSlug } = useParams();
|
||||
|
||||
return (
|
||||
<section {...props} className={cn('h-full flex flex-col', className)}>
|
||||
<div className="sticky top-0">
|
||||
<div className="flex px-6 py-4 bg-base-bg items-center gap-4">
|
||||
<Heading as="h2" className="flex-1 text-[24px] font-medium">
|
||||
Create new project
|
||||
</Heading>
|
||||
<Link to={`/${orgSlug}`}>
|
||||
<Button iconOnly variant="tertiary">
|
||||
<CrossIcon size={18} />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<WavyBorder />
|
||||
</div>
|
||||
<section className="px-6 h-full flex-1 py-6 overflow-y-auto">
|
||||
<Outlet />
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
};
|
@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
|
||||
import CreateProject from './Create';
|
||||
import Id from './Id';
|
||||
import AddDomain from './id/settings/domains/add';
|
||||
import { createProjectRoutes } from './create/routes';
|
||||
import { projectTabRoutes } from './id/routes';
|
||||
import { addDomainRoutes } from './id/settings/domains/add/routes';
|
||||
import { CreateProjectLayout } from './create/layout';
|
||||
|
||||
export const projectsRoutesWithoutSearch = [
|
||||
{
|
||||
path: 'create',
|
||||
element: <CreateProject />,
|
||||
element: <CreateProjectLayout />,
|
||||
children: createProjectRoutes,
|
||||
},
|
||||
{
|
||||
|
@ -158,6 +158,7 @@ export default withMT({
|
||||
field: '0px 1px 2px rgba(0, 0, 0, 0.04)',
|
||||
inset: 'inset 0px 1px 0px rgba(8, 47, 86, 0.06)',
|
||||
card: '0px 0px 0px 1px #E8F0F7, 0px 2px 4px rgba(8, 47, 86, 0.04)',
|
||||
'card-sm': '0px 1px 2px -1px rgba(4, 25, 47, 0.08)',
|
||||
},
|
||||
spacing: {
|
||||
2.5: '0.625rem',
|
||||
|
Loading…
Reference in New Issue
Block a user