Compare commits

...
Author SHA1 Message Date
Wahyu Kurniawan 30357672ef 🎨 style: set default font weight to normal for heading component 2024-02-28 11:04:45 +07:00
Wahyu Kurniawan 2457d5a095 ♻️ refactor: remove .env 2024-02-28 08:50:18 +07:00
Wahyu Kurniawan 234803e313 🎨 style: re-styling project list page 2024-02-28 08:50:18 +07:00
Wahyu Kurniawan 1fbaf6fdf0 ️ feat: add polymorphic prop type for heading component 2024-02-28 08:50:18 +07:00
Wahyu Kurniawan 66277d6c3b ♻️ refactor: move sidebar inside shared components 2024-02-28 08:50:18 +07:00
Wahyu Kurniawan 3215a19141 ️ feat: create heading component 2024-02-28 08:50:18 +07:00
Wahyu Kurniawan 282001c317 [T-4903: chore] Add inter display font (#127)
* 🔧 chore: add `InterDisplay` font families

* 🎨 style: add font `InterDisplay` to tailwind

* 🔧 chore: update `yarn.lock`

* ♻️ refactor: change `InterDisplay` to `inter Display` and `inter-display` to `display
2024-02-28 08:47:43 +07:00
Eric Lewis 2f62d086de Merge pull request #131 from snowball-tools/ericlewis/deploy-2
chore(deployment): 1.1.3
2024-02-27 12:55:54 -05:00
Eric Lewis 4c544e8d15 chore: readme 2024-02-27 12:30:35 -05:00
Eric Lewis a02ee13f9d chore: deploy readme 2024-02-27 12:29:27 -05:00
Eric Lewis e32a51a771 chore(deployment): 1.1.3 2024-02-27 12:25:20 -05:00
Eric Lewis 513ca69d01 Merge pull request #130 from snowball-tools/ericlewis/pretty-login
feat: pretty login
2024-02-27 12:08:40 -05:00
Eric Lewis e34b8d6a2e Merge pull request #129 from snowball-tools/ericlewis/deploy
chore: create new deployment
2024-02-27 12:07:43 -05:00
Eric Lewis f4d5b77784 fix deploy 2024-02-27 11:56:22 -05:00
Eric Lewis 399b80ce3b chore: create new deployment 2024-02-27 11:30:39 -05:00
Eric Lewis fdaec2da94 feat: pretty login 2024-02-27 11:13:14 -05:00
Vivian Phung 13fc92bf0e Merge pull request #128 from snowball-tools/ericlewis/prettify-select 2024-02-27 10:44:59 -05:00
Eric Lewis 8a8ee1d6ae fix centering 2024-02-27 10:40:54 -05:00
Vivian Phung 5680961964 Merge pull request #122 from snowball-tools/repo 2024-02-27 09:18:20 -05:00
Vivian Phung aa0ca8dd21 Merge pull request #121 from snowball-tools/search-area-plus 2024-02-27 09:18:03 -05:00
Wahyu Kurniawan 8280f4c7f7 [T-4902: feat] Update project card (#126)
* ️ feat: create wavy border component

* ️ feat: create project card component

* ️ feat: add new size in avatar

* 🎨 style: add default border radius when the shape is default on the button

* ️ feat: create some icons for project card component

* 🔧 chore: install and setup jetbrains mono font family

* ️ feat: create `getInitials` util function

* 🎨 style: add jetbrains mono font to the tailwind config

* ️ feat: add warning error icon

* ♻️ refactor: change `jetbrains-mono` to `mono`
2024-02-27 21:16:38 +07:00
nabarun ab72bbb03f Update template repo links (#124) 2024-02-27 14:16:36 +05:30
Vivian Phung 195471b888 Merge branch 'main' into repo 2024-02-27 00:07:22 -05:00
Vivian Phung 8ce531274d center items in nav bar of git repos 2024-02-27 00:00:52 -05:00
Vivian Phung 6c38094093 github icon in search repo 2024-02-26 23:56:20 -05:00
Vivian Phung 95285d30dd private repo + repo 2024-02-26 23:50:42 -05:00
Vivian Phung 61c8846400 org slug 2024-02-26 23:24:19 -05:00
Eric Lewis d73c3c7daf fix: select issue 2024-02-26 22:57:05 -05:00
60 changed files with 751 additions and 160 deletions
+15 -2
View File
@@ -4,9 +4,18 @@
```bash
yarn
```
```bash
brew install jq # if you do not have jq installed already
```
Example of how to make the necessary deploy edits [here](https://github.com/snowball-tools/snowballtools-base/pull/131/files).
- Replace variables in the following files
- [records/application-deployment-request.yml](records/application-deployment-request.yml)
- update the name & application version numbers
- `<CURRENT_DATE_TIME>`: Replace with current time which can be generated by command `date -u`
```yml
# Example
@@ -42,9 +51,10 @@
repository_ref: <COMMIT_HASH>
```
- [deploy-frontend.sh](deploy-frontend.sh)
Also be sure to update the app version
```bash
...
RCD_APP_VERSION="0.1.0"
RCD_APP_VERSION="<NEW_VERSION>"
REPO_REF="<COMMIT_HASH>"
...
```
@@ -71,6 +81,9 @@
## Troubleshoot
- Check deployment status [here](https://console.laconic.com/deployer).
- Check records [here](https://console.laconic.com/#/registry).
- If deployment fails due to low bond balance
- Check balances
```bash
@@ -83,4 +96,4 @@
- Command to refill bond
```bash
yarn laconic cns bond refill --id 8fcf44b2f326b4b63ac57547777f1c78b7d494e5966e508f09001af53cb440ac --type aphoton --quantity 10000000
```
```
+2 -2
View File
@@ -4,8 +4,8 @@
RECORD_FILE=records/application-record.yml
CONFIG_FILE=config.yml
RCD_APP_VERSION="0.1.0"
REPO_REF="353fd0f6219a955be186b5914e93baa9058b4473"
RCD_APP_VERSION="0.1.3"
REPO_REF="513ca69d01bee857cf207a0605483205b384e218"
# Publish ApplicationRecord
RECORD_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
@@ -1,21 +1,21 @@
record:
type: ApplicationDeploymentRequest
version: '1.0.0'
name: snowballtools-base-frontend@0.1.0
application: crn://snowballtools/applications/snowballtools-base-frontend@0.1.0
name: snowballtools-base-frontend@0.1.3
application: crn://snowballtools/applications/snowballtools-base-frontend@0.1.3
dns: dashboard
config:
env:
LACONIC_HOSTED_CONFIG_app_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
# If GitHub client ID is changed, same ID and corresponding secret has to be set in backend config
LACONIC_HOSTED_CONFIG_app_github_clientid: 1ed99146e0d07aa62d44
LACONIC_HOSTED_CONFIG_app_github_templaterepo: deep-stack/test-progressive-web-app
LACONIC_HOSTED_CONFIG_app_github_clientid: b7c63b235ca1dd5639ab
LACONIC_HOSTED_CONFIG_app_github_templaterepo: snowball-tools-platform/test-progressive-web-app
# New config env after changes for image upload PWA
LACONIC_HOSTED_CONFIG_app_github_pwa_templaterepo: deep-stack/test-progressive-web-app
LACONIC_HOSTED_CONFIG_app_github_image_upload_templaterepo: deep-stack/image-upload-pwa-example
LACONIC_HOSTED_CONFIG_app_github_pwa_templaterepo: snowball-tools-platform/test-progressive-web-app
LACONIC_HOSTED_CONFIG_app_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
LACONIC_HOSTED_CONFIG_app_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
meta:
# Set CURRENT_DATE_TIME; Use command date -u
note: Added by Snowball @ <CURRENT_DATE_TIME>
note: Added by Snowball @ Tue Feb 27 17:24:06 UTC 2024
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
repository_ref: 353fd0f6219a955be186b5914e93baa9058b4473
repository_ref: 513ca69d01bee857cf207a0605483205b384e218
@@ -1,10 +1,10 @@
record:
type: ApplicationRecord
version: 0.0.5
repository_ref: 353fd0f6219a955be186b5914e93baa9058b4473
version: 0.0.11
repository_ref: 513ca69d01bee857cf207a0605483205b384e218
repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
app_type: webapp
# name is set to repo name
name: snowballtools-base-frontend
# app_version is set from package.json
app_version: 0.1.0
app_version: 0.1.3
-7
View File
@@ -1,7 +0,0 @@
REACT_APP_SERVER_URL = 'http://localhost:8000'
REACT_APP_GITHUB_CLIENT_ID =
REACT_APP_GITHUB_PWA_TEMPLATE_REPO =
REACT_APP_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO =
REACT_APP_WALLET_CONNECT_ID =
+3 -2
View File
@@ -1,11 +1,11 @@
{
"name": "frontend",
"version": "0.1.0",
"version": "0.1.3",
"private": true,
"dependencies": {
"@fontsource-variable/jetbrains-mono": "^5.0.19",
"@fontsource/inter": "^5.0.16",
"@material-tailwind/react": "^2.1.7",
"@tanstack/react-query": "^5.22.2",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-popover": "^1.0.7",
@@ -14,6 +14,7 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-query": "^5.22.2",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+10
View File
@@ -0,0 +1,10 @@
<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>

After

Width:  |  Height:  |  Size: 4.8 KiB

@@ -1,71 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Project } from 'gql-client';
import {
Menu,
MenuHandler,
MenuList,
MenuItem,
Typography,
Avatar,
} from '@material-tailwind/react';
import { relativeTimeMs } from '../../utils/time';
interface ProjectCardProps {
project: Project;
}
const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
return (
<div className="bg-white border border-gray-200 rounded-lg shadow">
<div className="flex gap-2 p-2 items-center">
<Avatar
variant="rounded"
src={project.icon || '/gray.png'}
placeholder={''}
/>
<div className="grow">
<Link to={`projects/${project.id}`}>
<Typography placeholder={''}>{project.name}</Typography>
<Typography color="gray" variant="small" placeholder={''}>
{project.deployments[0]?.domain?.name ??
'No Production Deployment'}
</Typography>
</Link>
</div>
<Menu placement="bottom-end">
<MenuHandler>
<button>...</button>
</MenuHandler>
<MenuList placeholder={''}>
<MenuItem placeholder={''}>^ Project settings</MenuItem>
<MenuItem className="text-red-500" placeholder={''}>
^ Delete project
</MenuItem>
</MenuList>
</Menu>
</div>
<div className="border-t-2 border-solid p-4 bg-gray-50">
{project.deployments.length > 0 ? (
<>
<Typography variant="small" color="gray" placeholder={''}>
^ {project.deployments[0].commitMessage}
</Typography>
<Typography variant="small" color="gray" placeholder={''}>
{relativeTimeMs(project.deployments[0].createdAt)} on ^&nbsp;
{project.deployments[0].branch}
</Typography>
</>
) : (
<Typography variant="small" color="gray" placeholder={''}>
No Production deployment
</Typography>
)}
</div>
</div>
);
};
export default ProjectCard;
@@ -0,0 +1,71 @@
import { VariantProps, tv } from 'tailwind-variants';
export const projectCardTheme = tv({
slots: {
wrapper: [
'bg-surface-card',
'shadow-card',
'rounded-2xl',
'flex',
'flex-col',
],
upperContent: ['px-4', 'py-4', 'flex', 'items-start', 'gap-3', 'relative'],
content: ['flex', 'flex-col', 'gap-1', 'flex-1'],
title: [
'text-sm',
'font-medium',
'text-elements-high-em',
'tracking-[-0.006em]',
],
description: ['text-xs', 'text-elements-low-em'],
icons: ['flex', 'items-center', 'gap-1'],
lowerContent: [
'bg-surface-card-hovered',
'px-4',
'py-4',
'flex',
'flex-col',
'gap-2',
'rounded-b-2xl',
],
latestDeployment: ['flex', 'items-center', 'gap-2'],
deploymentStatusContainer: [
'h-3',
'w-3',
'flex',
'items-center',
'justify-center',
],
deploymentStatus: ['w-1', 'h-1', 'rounded-full'],
deploymentName: ['text-xs', 'text-elements-low-em'],
deploymentText: [
'text-xs',
'text-elements-low-em',
'font-mono',
'flex',
'items-center',
'gap-2',
],
},
variants: {
status: {
success: {
deploymentStatus: ['bg-emerald-500'],
},
'in-progress': {
deploymentStatus: ['bg-orange-400'],
},
failure: {
deploymentStatus: ['bg-rose-500'],
},
pending: {
deploymentStatus: ['bg-gray-500'],
},
},
},
defaultVariants: {
status: 'pending',
},
});
export type ProjectCardTheme = VariantProps<typeof projectCardTheme>;
@@ -0,0 +1,124 @@
import React, { ComponentPropsWithoutRef, MouseEvent } from 'react';
import { ProjectCardTheme, projectCardTheme } from './ProjectCard.theme';
import { Project } from 'gql-client';
import { Button } from 'components/shared/Button';
import { WavyBorder } from 'components/shared/WavyBorder';
import {
BranchIcon,
ClockIcon,
GitHubLogo,
HorizontalDotIcon,
WarningDiamondIcon,
} from 'components/shared/CustomIcon';
import { relativeTimeMs } from 'utils/time';
import { Link } from 'react-router-dom';
import { Avatar } from 'components/shared/Avatar';
import { getInitials } from 'utils/geInitials';
import {
Menu,
MenuHandler,
MenuItem,
MenuList,
} from '@material-tailwind/react';
export interface ProjectCardProps
extends ComponentPropsWithoutRef<'div'>,
ProjectCardTheme {
project: Project;
}
export const ProjectCard = ({
className,
project,
status = 'failure',
...props
}: ProjectCardProps) => {
const theme = projectCardTheme();
const hasDeployment = project.deployments.length > 0;
// TODO: Update this to use the actual status from the API
const hasError = status === 'failure';
const handleOptionsClick = (
e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>,
) => {
e.stopPropagation();
};
return (
<div {...props} className={theme.wrapper({ className })}>
{/* Upper content */}
<div className={theme.upperContent()}>
{/* Icon container */}
<Avatar
size={48}
imageSrc={project.icon}
initials={getInitials(project.name)}
/>
{/* </div> */}
{/* Title and website */}
<Link to={`projects/${project.id}`} className={theme.content()}>
<p className={theme.title()}>{project.name}</p>
<p className={theme.description()}>
{project.deployments[0]?.domain?.name ?? 'No domain'}
</p>
</Link>
{/* Icons */}
<div className={theme.icons()}>
{hasError && <WarningDiamondIcon className="text-elements-danger" />}
<Menu placement="bottom-end">
<MenuHandler>
<Button
shape="default"
size="xs"
variant="ghost"
iconOnly
onClick={handleOptionsClick}
>
<HorizontalDotIcon />
</Button>
</MenuHandler>
<MenuList placeholder={''}>
<MenuItem placeholder={''}>Project settings</MenuItem>
<MenuItem className="text-red-500" placeholder={''}>
Delete project
</MenuItem>
</MenuList>
</Menu>
</div>
</div>
{/* Wave */}
<WavyBorder />
{/* Lower content */}
<div className={theme.lowerContent()}>
{/* Latest deployment */}
<div className={theme.latestDeployment()}>
{/* Dot icon */}
<div className={theme.deploymentStatusContainer()}>
<div className={theme.deploymentStatus({ status })} />
</div>
<p className={theme.deploymentText()}>
{hasDeployment
? project.deployments[0]?.commitMessage
: 'No production deployment'}
</p>
</div>
{/* Deployment and branch name */}
<div className={theme.deploymentText()}>
{hasDeployment ? (
<>
<GitHubLogo />
<span>{relativeTimeMs(project.deployments[0].createdAt)} on</span>
<BranchIcon />
<span>{project.deployments[0].branch}</span>
</>
) : (
<>
<ClockIcon />
<span>Created {relativeTimeMs(project.createdAt)}</span>
</>
)}
</div>
</div>
</div>
);
};
@@ -0,0 +1 @@
export * from './ProjectCard';
@@ -7,6 +7,7 @@ import { Chip, IconButton, Spinner } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { GitRepositoryDetails } from '../../../types';
import { useGQLClient } from '../../../context/GQLClientContext';
import { GithubIcon, LockIcon } from 'components/shared/CustomIcon';
interface ProjectRepoCardProps {
repository: GitRepositoryDetails;
@@ -47,16 +48,18 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 p-2 cursor-pointer"
onClick={createProject}
>
<div>^</div>
<div className="w-10 h-10 bg-white rounded-md justify-center items-center gap-1.5 inline-flex">
<GithubIcon />
</div>
<div className="grow">
<div>
<span className="text-black">{repository.full_name}</span>
{repository.visibility === 'private' && (
<Chip
className="normal-case inline ml-6 font-normal"
className="normal-case inline ml-6 font-normal text-xs text-xs bg-orange-50 border border-orange-200 text-orange-600 items-center gap-1 inline-flex"
size="sm"
value="Private"
icon={'^'}
icon={<LockIcon />}
/>
)}
</div>
@@ -9,6 +9,7 @@ import SearchBar from '../../SearchBar';
import ProjectRepoCard from './ProjectRepoCard';
import { GitOrgDetails, GitRepositoryDetails } from '../../../types';
import AsyncSelect from '../../shared/AsyncSelect';
import { GithubIcon } from 'components/shared/CustomIcon';
const DEFAULT_SEARCHED_REPO = '';
const REPOS_PER_PAGE = 5;
@@ -108,7 +109,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
return (
<div className="p-4">
<div className="flex gap-2 mb-2">
<div className="flex gap-2 mb-2 items-center">
<div className="basis-1/3">
<AsyncSelect
value={selectedAccount}
@@ -116,12 +117,14 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
>
{accounts.map((account) => (
<Option key={account.id} value={account.login}>
^ {account.login}
<div className="flex items-center gap-2 justify-start">
<GithubIcon /> {account.login}
</div>
</Option>
))}
</AsyncSelect>
</div>
<div className="basis-2/3">
<div className="basis-2/3 flex-grow flex items-center">
<SearchBar
value={searchedRepo}
onChange={(event) => setSearchedRepo(event.target.value)}
@@ -58,6 +58,9 @@ export const avatarTheme = tv(
44: {
base: ['rounded-xl', 'h-[44px]', 'w-[44px]', 'text-sm'],
},
48: {
base: ['rounded-xl', 'h-[48px]', 'w-[48px]', 'text-sm'],
},
},
},
defaultVariants: {
@@ -26,7 +26,7 @@ export const buttonTheme = tv(
true: 'w-full',
},
shape: {
default: '',
default: 'rounded-lg',
rounded: 'rounded-full',
},
iconOnly: {
@@ -0,0 +1,19 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const BranchIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
{...props}
>
<path
d="M3.5 1C2.67157 1 2 1.67157 2 2.5C2 3.24325 2.54057 3.86024 3.25 3.97926V8.02074C2.54057 8.13976 2 8.75675 2 9.5C2 10.3284 2.67157 11 3.5 11C4.32843 11 5 10.3284 5 9.5C5 8.75675 4.45943 8.13976 3.75 8.02074V7C3.75 6.58579 4.08579 6.25 4.5 6.25H7.5C8.19036 6.25 8.75 5.69036 8.75 5V3.97926C9.45943 3.86024 10 3.24325 10 2.5C10 1.67157 9.32843 1 8.5 1C7.67157 1 7 1.67157 7 2.5C7 3.24325 7.54057 3.86024 8.25 3.97926V5C8.25 5.41421 7.91421 5.75 7.5 5.75H4.5C4.2186 5.75 3.95892 5.84299 3.75 5.99991V3.97926C4.45943 3.86024 5 3.24325 5 2.5C5 1.67157 4.32843 1 3.5 1Z"
fill="currentColor"
/>
</CustomIcon>
);
};
@@ -0,0 +1,19 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const ClockIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
{...props}
>
<path
d="M6 1.125C5.03582 1.125 4.09329 1.41091 3.2916 1.94659C2.48991 2.48226 1.86507 3.24363 1.49609 4.13442C1.12711 5.02521 1.03057 6.00541 1.21867 6.95107C1.40678 7.89672 1.87108 8.76536 2.55286 9.44715C3.23464 10.1289 4.10328 10.5932 5.04894 10.7813C5.99459 10.9694 6.97479 10.8729 7.86558 10.5039C8.75637 10.1349 9.51775 9.51009 10.0534 8.7084C10.5891 7.90671 10.875 6.96418 10.875 6C10.8736 4.70749 10.3596 3.46831 9.44564 2.55436C8.5317 1.64042 7.29251 1.12636 6 1.125ZM8.625 6.375H6C5.90055 6.375 5.80516 6.33549 5.73484 6.26517C5.66451 6.19484 5.625 6.09946 5.625 6V3.375C5.625 3.27554 5.66451 3.18016 5.73484 3.10984C5.80516 3.03951 5.90055 3 6 3C6.09946 3 6.19484 3.03951 6.26517 3.10984C6.33549 3.18016 6.375 3.27554 6.375 3.375V5.625H8.625C8.72446 5.625 8.81984 5.66451 8.89017 5.73484C8.96049 5.80516 9 5.90054 9 6C9 6.09946 8.96049 6.19484 8.89017 6.26517C8.81984 6.33549 8.72446 6.375 8.625 6.375Z"
fill="currentColor"
/>
</CustomIcon>
);
};
@@ -0,0 +1,19 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const GitHubLogo = (props: CustomIconProps) => {
return (
<CustomIcon
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
{...props}
>
<path
d="M10.125 4.87501V5.25001C10.1242 5.88451 9.89387 6.4973 9.47652 6.97522C9.05917 7.45314 8.48299 7.76392 7.85437 7.85016C8.11096 8.1785 8.25024 8.5833 8.25 9.00001V10.875C8.25 10.9745 8.21049 11.0698 8.14017 11.1402C8.06984 11.2105 7.97446 11.25 7.875 11.25H4.875C4.77554 11.25 4.68016 11.2105 4.60984 11.1402C4.53951 11.0698 4.5 10.9745 4.5 10.875V10.125H3.375C2.87772 10.125 2.40081 9.92746 2.04917 9.57583C1.69754 9.2242 1.5 8.74729 1.5 8.25001C1.5 7.95164 1.38147 7.66549 1.1705 7.45451C0.959517 7.24353 0.673369 7.12501 0.375 7.12501C0.275544 7.12501 0.180161 7.0855 0.109835 7.01517C0.0395088 6.94484 0 6.84946 0 6.75001C0 6.65055 0.0395088 6.55517 0.109835 6.48484C0.180161 6.41451 0.275544 6.37501 0.375 6.37501C0.621229 6.37501 0.865046 6.4235 1.09253 6.51773C1.32002 6.61196 1.52672 6.75007 1.70083 6.92418C1.87494 7.09829 2.01305 7.30499 2.10727 7.53247C2.2015 7.75996 2.25 8.00378 2.25 8.25001C2.25 8.54837 2.36853 8.83452 2.5795 9.0455C2.79048 9.25648 3.07663 9.37501 3.375 9.37501H4.5V9.00001C4.49976 8.5833 4.63904 8.1785 4.89563 7.85016C4.26701 7.76392 3.69083 7.45314 3.27348 6.97522C2.85613 6.4973 2.62579 5.88451 2.625 5.25001V4.87501C2.62967 4.40896 2.75378 3.9519 2.98547 3.54751C2.87085 3.17775 2.83408 2.78826 2.87748 2.40359C2.92089 2.01892 3.04352 1.64742 3.23766 1.31251C3.27058 1.25549 3.31793 1.20814 3.37495 1.17523C3.43198 1.14231 3.49666 1.12499 3.5625 1.12501C3.99929 1.12409 4.43023 1.22535 4.82091 1.42069C5.21159 1.61602 5.55116 1.90003 5.8125 2.25001H6.9375C7.19884 1.90003 7.53841 1.61602 7.92909 1.42069C8.31977 1.22535 8.75071 1.12409 9.1875 1.12501C9.25334 1.12499 9.31802 1.14231 9.37505 1.17523C9.43207 1.20814 9.47942 1.25549 9.51234 1.31251C9.70651 1.64741 9.82912 2.01894 9.87245 2.40362C9.91577 2.78831 9.87887 3.1778 9.76406 3.54751C9.99619 3.95175 10.1205 4.40888 10.125 4.87501Z"
fill="currentColor"
/>
</CustomIcon>
);
};
@@ -0,0 +1,21 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const GithubIcon: React.FC<CustomIconProps> = (props) => {
return (
<CustomIcon
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.9702 0.206024C4.45694 0.206024 0 4.69582 0 10.2503C0 14.6903 2.85571 18.4487 6.81735 19.7789C7.31265 19.8789 7.49408 19.5628 7.49408 19.2968C7.49408 19.064 7.47776 18.2658 7.47776 17.4342C4.70429 18.033 4.12674 16.2368 4.12674 16.2368C3.68102 15.0728 3.02061 14.7736 3.02061 14.7736C2.11286 14.1583 3.08673 14.1583 3.08673 14.1583C4.09367 14.2248 4.62204 15.1893 4.62204 15.1893C5.51327 16.7191 6.94939 16.2868 7.52714 16.0207C7.60959 15.3721 7.87388 14.9232 8.15449 14.6738C5.94245 14.4409 3.6151 13.5762 3.6151 9.71807C3.6151 8.62051 4.01102 7.72256 4.63837 7.02419C4.53939 6.7748 4.19265 5.74358 4.73755 4.36337C4.73755 4.36337 5.57939 4.09725 7.47755 5.39439C8.29022 5.17453 9.12832 5.06268 9.9702 5.06174C10.812 5.06174 11.6702 5.17827 12.4627 5.39439C14.361 4.09725 15.2029 4.36337 15.2029 4.36337C15.7478 5.74358 15.4008 6.7748 15.3018 7.02419C15.9457 7.72256 16.3253 8.62051 16.3253 9.71807C16.3253 13.5762 13.998 14.4242 11.7694 14.6738C12.1327 14.9897 12.4461 15.5883 12.4461 16.5362C12.4461 17.8832 12.4298 18.9642 12.4298 19.2966C12.4298 19.5628 12.6114 19.8789 13.1065 19.7791C17.0682 18.4485 19.9239 14.6903 19.9239 10.2503C19.9402 4.69582 15.4669 0.206024 9.9702 0.206024Z"
fill="#0B1D2E"
/>
</CustomIcon>
);
};
@@ -0,0 +1,19 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const HorizontalDotIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
{...props}
>
<path
d="M10.9375 10C10.9375 10.1854 10.8825 10.3667 10.7795 10.5208C10.6765 10.675 10.5301 10.7952 10.3588 10.8661C10.1875 10.9371 9.99896 10.9557 9.8171 10.9195C9.63525 10.8833 9.4682 10.794 9.33709 10.6629C9.20598 10.5318 9.11669 10.3648 9.08051 10.1829C9.04434 10.001 9.06291 9.81254 9.13386 9.64123C9.20482 9.46993 9.32498 9.32351 9.47915 9.2205C9.63332 9.11748 9.81458 9.0625 10 9.0625C10.2486 9.0625 10.4871 9.16127 10.6629 9.33709C10.8387 9.5129 10.9375 9.75136 10.9375 10ZM15.3125 9.0625C15.1271 9.0625 14.9458 9.11748 14.7917 9.2205C14.6375 9.32351 14.5173 9.46993 14.4464 9.64123C14.3754 9.81254 14.3568 10.001 14.393 10.1829C14.4292 10.3648 14.5185 10.5318 14.6496 10.6629C14.7807 10.794 14.9477 10.8833 15.1296 10.9195C15.3115 10.9557 15.5 10.9371 15.6713 10.8661C15.8426 10.7952 15.989 10.675 16.092 10.5208C16.195 10.3667 16.25 10.1854 16.25 10C16.25 9.75136 16.1512 9.5129 15.9754 9.33709C15.7996 9.16127 15.5611 9.0625 15.3125 9.0625ZM4.6875 9.0625C4.50208 9.0625 4.32082 9.11748 4.16665 9.2205C4.01248 9.32351 3.89232 9.46993 3.82136 9.64123C3.75041 9.81254 3.73184 10.001 3.76801 10.1829C3.80419 10.3648 3.89348 10.5318 4.02459 10.6629C4.1557 10.794 4.32275 10.8833 4.5046 10.9195C4.68646 10.9557 4.87496 10.9371 5.04627 10.8661C5.21757 10.7952 5.36399 10.675 5.467 10.5208C5.57002 10.3667 5.625 10.1854 5.625 10C5.625 9.75136 5.52623 9.5129 5.35041 9.33709C5.1746 9.16127 4.93614 9.0625 4.6875 9.0625Z"
fill="currentColor"
/>
</CustomIcon>
);
};
@@ -0,0 +1,21 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const LockIcon: React.FC<CustomIconProps> = (props) => {
return (
<CustomIcon
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.99984 1.5C6.15889 1.5 4.6665 2.99238 4.6665 4.83333V6H4.49984C3.48732 6 2.6665 6.82081 2.6665 7.83333V12.8333C2.6665 13.8459 3.48732 14.6667 4.49984 14.6667H11.4998C12.5124 14.6667 13.3332 13.8459 13.3332 12.8333V7.83333C13.3332 6.82081 12.5124 6 11.4998 6H11.3332V4.83333C11.3332 2.99238 9.84079 1.5 7.99984 1.5ZM10.3332 6V4.83333C10.3332 3.54467 9.2885 2.5 7.99984 2.5C6.71117 2.5 5.6665 3.54467 5.6665 4.83333V6H10.3332ZM7.99984 8.83333C8.27598 8.83333 8.49984 9.05719 8.49984 9.33333V11.3333C8.49984 11.6095 8.27598 11.8333 7.99984 11.8333C7.72369 11.8333 7.49984 11.6095 7.49984 11.3333V9.33333C7.49984 9.05719 7.72369 8.83333 7.99984 8.83333Z"
fill="#EA580C"
/>
</CustomIcon>
);
};
@@ -0,0 +1,19 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const WarningDiamondIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
{...props}
>
<path
d="M18.3851 9.11879L10.8812 1.6141C10.647 1.38129 10.3302 1.25061 9.99999 1.25061C9.66976 1.25061 9.35294 1.38129 9.11874 1.6141L1.61874 9.11879C1.38593 9.35299 1.25525 9.66981 1.25525 10C1.25525 10.3303 1.38593 10.6471 1.61874 10.8813L9.12265 18.386C9.35685 18.6188 9.67367 18.7495 10.0039 18.7495C10.3341 18.7495 10.6509 18.6188 10.8851 18.386L18.3891 10.8813C18.6219 10.6471 18.7525 10.3303 18.7525 10C18.7525 9.66981 18.6219 9.35299 18.3891 9.11879H18.3851ZM9.37499 6.25004C9.37499 6.08428 9.44084 5.92531 9.55805 5.8081C9.67526 5.69089 9.83423 5.62504 9.99999 5.62504C10.1658 5.62504 10.3247 5.69089 10.4419 5.8081C10.5591 5.92531 10.625 6.08428 10.625 6.25004V10.625C10.625 10.7908 10.5591 10.9498 10.4419 11.067C10.3247 11.1842 10.1658 11.25 9.99999 11.25C9.83423 11.25 9.67526 11.1842 9.55805 11.067C9.44084 10.9498 9.37499 10.7908 9.37499 10.625V6.25004ZM9.99999 14.375C9.81457 14.375 9.63332 14.3201 9.47914 14.217C9.32497 14.114 9.20481 13.9676 9.13385 13.7963C9.0629 13.625 9.04433 13.4365 9.0805 13.2546C9.11668 13.0728 9.20597 12.9057 9.33708 12.7746C9.46819 12.6435 9.63524 12.5542 9.81709 12.5181C9.99895 12.4819 10.1875 12.5004 10.3588 12.5714C10.5301 12.6424 10.6765 12.7625 10.7795 12.9167C10.8825 13.0709 10.9375 13.2521 10.9375 13.4375C10.9375 13.6862 10.8387 13.9246 10.6629 14.1005C10.4871 14.2763 10.2486 14.375 9.99999 14.375Z"
fill="currentColor"
/>
</CustomIcon>
);
};
@@ -22,6 +22,13 @@ export * from './EllipseIcon';
export * from './EllipsesIcon';
export * from './SnowballIcon';
export * from './NotificationBellIcon';
export * from './GithubIcon';
export * from './LockIcon';
export * from './PencilIcon';
export * from './CheckRadioIcon';
export * from './ChevronDownIcon';
export * from './BranchIcon';
export * from './GitHubLogo';
export * from './ClockIcon';
export * from './HorizontalDotIcon';
export * from './WarningDiamondIcon';
@@ -0,0 +1,7 @@
import { tv, type VariantProps } from 'tailwind-variants';
export const headingTheme = tv({
base: ['text-elements-high-em', 'font-display', 'font-normal'],
});
export type HeadingVariants = VariantProps<typeof headingTheme>;
@@ -0,0 +1,30 @@
import React, { type PropsWithChildren } from 'react';
import { headingTheme, type HeadingVariants } from './Heading.theme';
import { PolymorphicProps } from 'types/common';
export type HeadingElementType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export type HeadingProps<Element extends HeadingElementType> =
PropsWithChildren<PolymorphicProps<Element, HeadingVariants>>;
export const Heading = <Element extends HeadingElementType>({
children,
as,
className,
...props
}: HeadingProps<Element>) => {
// Component is the element that will be rendered
const Component = as ?? 'h1';
return (
<Component
{...props}
className={headingTheme({
className,
})}
>
{children}
</Component>
);
};
@@ -0,0 +1 @@
export * from './Heading';
@@ -5,8 +5,8 @@ import { Organization } from 'gql-client';
import { Option } from '@material-tailwind/react';
import { useDisconnect } from 'wagmi';
import { useGQLClient } from '../context/GQLClientContext';
import AsyncSelect from './shared/AsyncSelect';
import { useGQLClient } from 'context/GQLClientContext';
import AsyncSelect from 'components/shared/AsyncSelect';
import {
ChevronGrabberHorizontal,
FolderIcon,
@@ -14,10 +14,11 @@ import {
LifeBuoyIcon,
QuestionMarkRoundIcon,
SettingsSlidersIcon,
} from './shared/CustomIcon';
} from 'components/shared/CustomIcon';
import { Tabs } from 'components/shared/Tabs';
import { Heading } from 'components/shared/Heading';
const Sidebar = () => {
export const Sidebar = () => {
const { orgSlug } = useParams();
const navigate = useNavigate();
const client = useGQLClient();
@@ -42,20 +43,20 @@ const Sidebar = () => {
}, [disconnect, navigate]);
return (
<div className="flex flex-col h-full p-4 pt-10">
<div className="grow">
<Link to={`/${orgSlug}`}>
<div className="flex items-center space-x-3 mb-10 ml-2">
<img
src="/logo.svg"
alt="Snowball Logo"
className="h-8 w-8 rounded-lg"
/>
<span className="text-2xl font-bold text-snowball-900">
Snowball
</span>
</div>
</Link>
<div 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">
<img
src="/logo.svg"
alt="Snowball Logo"
className="h-10 w-10 rounded-lg"
/>
<Heading className="text-[24px] font-semibold">Snowball</Heading>
</div>
</Link>
{/* Switch organization */}
<div className="flex flex-1 flex-col gap-4">
<AsyncSelect
containerProps={{ className: 'h-14 border-none' }}
labelProps={{ className: 'before:border-none after:border-none' }}
@@ -82,7 +83,7 @@ const Sidebar = () => {
)}
arrow={<ChevronGrabberHorizontal className="h-4 w-4 text-gray-500" />}
>
{/* TODO: Show label organization and manage in option */}
{/* // TODO: Show label organization and manage in option */}
{organizations.map((org) => (
<Option key={org.id} value={org.slug}>
<div className="flex items-center space-x-3">
@@ -99,13 +100,17 @@ const Sidebar = () => {
</Option>
))}
</AsyncSelect>
<Tabs defaultValue="Projects" orientation="vertical" className="mt-10">
<Tabs defaultValue="Projects" orientation="vertical">
<Tabs.List>
{[
{ title: 'Projects', icon: <FolderIcon /> },
{ title: 'Settings', icon: <SettingsSlidersIcon /> },
].map(({ title, icon }, index) => (
<NavLink to={`/${orgSlug}/${title}`} key={index}>
{ title: 'Projects', url: `/${orgSlug}/`, icon: <FolderIcon /> },
{
title: 'Settings',
url: `/${orgSlug}/settings`,
icon: <SettingsSlidersIcon />,
},
].map(({ title, icon, url }, index) => (
<NavLink to={url} key={index}>
<Tabs.Trigger icon={icon} value={title}>
{title}
</Tabs.Trigger>
@@ -114,9 +119,10 @@ const Sidebar = () => {
</Tabs.List>
</Tabs>
</div>
<div className="grow flex flex-col justify-end mb-8">
{/* Bottom navigation */}
<div className="flex flex-col justify-end">
<Tabs defaultValue="Projects" orientation="vertical">
{/* TODO: use proper link buttons */}
{/* // TODO: use proper link buttons */}
<Tabs.List>
<Tabs.Trigger icon={<GlobeIcon />} value="">
<a className="cursor-pointer" onClick={handleLogOut}>
@@ -135,5 +141,3 @@ const Sidebar = () => {
</div>
);
};
export default Sidebar;
@@ -0,0 +1 @@
export * from './Sidebar';
@@ -23,7 +23,6 @@ export const tabsTheme = tv({
// Vertical
'data-[orientation=vertical]:px-3',
'data-[orientation=vertical]:py-3',
'data-[orientation=vertical]:min-w-[240px]',
'data-[orientation=vertical]:w-full',
'data-[orientation=vertical]:focus-ring',
'data-[orientation=vertical]:rounded-xl',
@@ -0,0 +1,16 @@
import React, { ComponentPropsWithoutRef } from 'react';
import { cn } from 'utils/classnames';
export interface WavyBorderProps extends ComponentPropsWithoutRef<'div'> {}
export const WavyBorder = ({
className,
children,
...props
}: WavyBorderProps) => {
return (
<div {...props} className={cn('wave', className)}>
{children}
</div>
);
};
@@ -0,0 +1 @@
export * from './WavyBorder';
+155
View File
@@ -2,8 +2,163 @@
@tailwind components;
@tailwind utilities;
@layer base {
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 100;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Thin.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 100;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-ThinItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 200;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-ExtraLight.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 200;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-ExtraLightItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Light.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 300;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-LightItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Regular.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Italic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Medium.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 500;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-MediumItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-SemiBold.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 600;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-SemiBoldItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Bold.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-BoldItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-ExtraBold.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 800;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-ExtraBoldItalic.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: normal;
font-weight: 900;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-Black.woff2')
format('woff2');
}
@font-face {
font-family: 'Inter Display';
font-style: italic;
font-weight: 900;
font-display: swap;
src: url('../public/fonts/InterDisplay/InterDisplay-BlackItalic.woff2')
format('woff2');
}
}
@layer utilities {
.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
View File
@@ -7,6 +7,7 @@ import { ThemeProvider } from '@material-tailwind/react';
import './index.css';
import '@fontsource/inter';
import '@fontsource-variable/jetbrains-mono';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { GQLClientProvider } from './context/GQLClientContext';
@@ -25,6 +25,12 @@ const ProjectSearch = () => {
fetchUser();
}, []);
const fetchOrgSlug = useCallback(async () => {
const { organizations } = await client.getOrganizations();
// TODO: Get the selected organization. This is temp
return organizations[0].slug;
}, []);
return (
<div>
<div className="sticky top-0 bg-white z-30">
@@ -38,7 +44,15 @@ const ProjectSearch = () => {
}}
/>
</div>
<Button variant={'secondary'} iconOnly>
<Button
variant={'secondary'}
iconOnly
onClick={() => {
fetchOrgSlug().then((organizationSlug) => {
navigate(`/${organizationSlug}/projects/create`);
});
}}
>
<PlusIcon />
</Button>
<Button variant={'ghost'} iconOnly>
+8 -3
View File
@@ -1,10 +1,15 @@
import React from 'react';
import './Snow.css';
const Login = () => {
return (
<div className="grid grid-cols-5 h-screen bg-light-blue-50 py-10">
<div className="col-span-2"></div>
<div className="col-span-1">
<div className="flex items-center justify-center h-screen bg-snowball-900 snow">
<div className="flex flex-col items-center justify-center">
<img
src="/logo.svg"
alt="snowball logo"
className="w-32 h-32 rounded-full mb-4"
/>
<w3m-button />
</div>
</div>
+2 -2
View File
@@ -1,8 +1,8 @@
import React from 'react';
import { Outlet } from 'react-router-dom';
import Sidebar from '../components/Sidebar';
import { OctokitProvider } from '../context/OctokitContext';
import { OctokitProvider } from 'context/OctokitContext';
import { Sidebar } from 'components/shared/Sidebar';
const OrgSlug = () => {
return (
+25
View File
@@ -0,0 +1,25 @@
.snow {
width: 100%;
height: 100vh;
border: 1px solid rgba(255, 255, 255, 0.1);
background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 50 50' style='enable-background:new 0 0 50 50%3B' xml:space='preserve'%3E%3Cstyle type='text/css'%3E.st1%7Bopacity:0.3%3Bfill:%23FFFFFF%3B%7D.st3%7Bopacity:0.1%3Bfill:%23FFFFFF%3B%7D%3C/style%3E%3Ccircle class='st1' cx='5' cy='8' r='1'/%3E%3Ccircle class='st1' cx='38' cy='3' r='1'/%3E%3Ccircle class='st1' cx='12' cy='4' r='1'/%3E%3Ccircle class='st1' cx='16' cy='16' r='1'/%3E%3Ccircle class='st1' cx='47' cy='46' r='1'/%3E%3Ccircle class='st1' cx='32' cy='10' r='1'/%3E%3Ccircle class='st1' cx='3' cy='46' r='1'/%3E%3Ccircle class='st1' cx='45' cy='13' r='1'/%3E%3Ccircle class='st1' cx='10' cy='28' r='1'/%3E%3Ccircle class='st1' cx='22' cy='35' r='1'/%3E%3Ccircle class='st1' cx='3' cy='21' r='1'/%3E%3Ccircle class='st1' cx='26' cy='20' r='1'/%3E%3Ccircle class='st1' cx='30' cy='45' r='1'/%3E%3Ccircle class='st1' cx='15' cy='45' r='1'/%3E%3Ccircle class='st1' cx='34' cy='36' r='1'/%3E%3Ccircle class='st1' cx='41' cy='32' r='1'/%3E%3C/svg%3E");
background-position: 0px 0px;
animation: animatedBackground 230s linear infinite;
}
.snow div {
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 50 50' style='enable-background:new 0 0 50 50%3B' xml:space='preserve'%3E%3Cstyle type='text/css'%3E.st1%7Bopacity:0.7%3Bfill:%23FFFFFF%3B%7D.st3%7Bopacity:0.1%3Bfill:%23FFFFFF%3B%7D%3C/style%3E%3Ccircle class='st3' cx='4' cy='14' r='1'/%3E%3Ccircle class='st3' cx='43' cy='3' r='1'/%3E%3Ccircle class='st3' cx='31' cy='30' r='2'/%3E%3Ccircle class='st3' cx='19' cy='23' r='1'/%3E%3Ccircle class='st3' cx='37' cy='22' r='1'/%3E%3Ccircle class='st3' cx='43' cy='16' r='1'/%3E%3Ccircle class='st3' cx='8' cy='45' r='1'/%3E%3Ccircle class='st3' cx='29' cy='39' r='1'/%3E%3Ccircle class='st3' cx='13' cy='37' r='1'/%3E%3Ccircle class='st3' cx='47' cy='32' r='1'/%3E%3Ccircle class='st3' cx='15' cy='4' r='2'/%3E%3Ccircle class='st3' cx='9' cy='27' r='1'/%3E%3Ccircle class='st3' cx='30' cy='9' r='1'/%3E%3Ccircle class='st3' cx='25' cy='15' r='1'/%3E%3Ccircle class='st3' cx='21' cy='45' r='2'/%3E%3Ccircle class='st3' cx='42' cy='45' r='1'/%3E%3C/svg%3E");
background-position: 0px 0px;
animation: animatedBackground 260s linear infinite;
}
@keyframes animatedBackground {
0% {
background-position: 0 0;
}
100% {
background-position: 0px 11600px;
}
}
+20 -22
View File
@@ -3,11 +3,11 @@ import { Link, useParams } from 'react-router-dom';
import { Project } from 'gql-client';
import { Button } from 'components/shared/Button';
import { Typography, Chip } from '@material-tailwind/react';
import ProjectCard from '../../components/projects/ProjectCard';
import { useGQLClient } from '../../context/GQLClientContext';
import { PlusIcon } from 'components/shared/CustomIcon';
import { ProjectCard } from 'components/projects/ProjectCard';
import { Heading } from 'components/shared/Heading';
import { Badge } from 'components/shared/Badge';
import { useGQLClient } from 'context/GQLClientContext';
const Projects = () => {
const client = useGQLClient();
@@ -26,33 +26,31 @@ const Projects = () => {
}, [orgSlug]);
return (
<div>
<div className="flex p-5">
<section className="px-6 py-6 flex flex-col gap-6">
{/* Header */}
<div className="flex items-center">
<div className="grow">
<div className="flex gap-2 items-center">
<Typography variant="h4" placeholder={''}>
<div className="flex gap-4 items-center">
<Heading as="h2" className="text-[24px]">
Projects
</Typography>
<Chip
className="bg-gray-300 rounded-full static"
value={projects.length}
size="sm"
/>
</Heading>
<Badge className="bg-base-bg-alternate text-elements-mid-em h-7 w-7">
{projects.length}
</Badge>
</div>
</div>
<div>
<Link to="projects/create">
<Button leftIcon={<PlusIcon />}>Create project</Button>
</Link>
</div>
<Link to="projects/create">
<Button leftIcon={<PlusIcon />}>Create project</Button>
</Link>
</div>
<div className="grid grid-cols-3 gap-5 p-5">
{projects.length !== 0 &&
{/* List of projects */}
<div className="grid grid-cols-3 gap-4">
{projects.length > 0 &&
projects.map((project, key) => {
return <ProjectCard project={project} key={key} />;
})}
</div>
</div>
</section>
);
};
+18
View File
@@ -1,3 +1,9 @@
import {
type ElementType,
type ComponentPropsWithoutRef,
forwardRef,
} from 'react';
/**
* Construct a type by excluding common keys from one type to another.
* @template T - The type from which to omit properties.
@@ -7,3 +13,15 @@
* @returns A new type that includes all properties from T except those that are common with U.
*/
export type OmitCommon<T, U> = Pick<T, Exclude<keyof T, keyof U>>;
export type PolymorphicProps<Element extends ElementType, Props> = Props &
Omit<ComponentPropsWithoutRef<Element>, 'as'> & {
as?: Element;
};
// taken from : https://github.com/total-typescript/react-typescript-tutorial/blob/main/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx
type FixedForwardRef = <T, P = object>(
render: (props: P, ref: React.Ref<T>) => React.ReactNode,
) => (props: P & React.RefAttributes<T>) => JSX.Element;
export const fixedForwardRef = forwardRef as FixedForwardRef;
+13
View File
@@ -0,0 +1,13 @@
/**
* Get initials from a full name.
*
* @param {string} name - The full name string from which to get the initials.
* @returns {string} A string of initials.
*/
export function getInitials(name: string): string {
return name
.split(' ')
.filter((n) => n)
.map((n) => n[0].toUpperCase())
.join('');
}
+3
View File
@@ -14,6 +14,8 @@ export default withMT({
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
display: ['Inter Display', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
fontSize: {
'2xs': '0.625rem',
@@ -155,6 +157,7 @@ export default withMT({
'0px 3px 20px rgba(8, 47, 86, 0.1), 0px 0px 4px rgba(8, 47, 86, 0.14)',
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)',
},
spacing: {
2.5: '0.625rem',
+6 -1
View File
@@ -2160,6 +2160,11 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
"@fontsource-variable/jetbrains-mono@^5.0.19":
version "5.0.19"
resolved "https://registry.yarnpkg.com/@fontsource-variable/jetbrains-mono/-/jetbrains-mono-5.0.19.tgz#e718de646e83b7caaeee484d2e18e1e3680ba8e1"
integrity sha512-7PTG1Kp3B/FgoNVPT8da4humj5JxQYxTtO08ZPS2IfanS37Yb/WShbgScnG/iupuFwiRnHVkIuC/2czxItxmyg==
"@fontsource/inter@^5.0.16":
version "5.0.16"
resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.16.tgz#b858508cdb56dcbbf3166903122851e2fbd16b50"
@@ -8756,7 +8761,7 @@ dotenv@~16.3.1:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f"
integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==
downshift@^8.2.3:
downshift@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-8.3.2.tgz#35cccfdadfe183a9e6bceb1dca68a6a592bb5602"
integrity sha512-kO5mnwMbWB1OIPgIO4wxK0HtSJbaPzx3XTOcnN36I6i08iVc4C2Fftye3UZYVN+W03b13o1kEmN2118G5vcgeQ==