Compare commits

..
Author SHA1 Message Date
Sushan Yadav c57bf61b37 chore: use Heading component 2024-02-28 13:29:04 +05:45
Sushan Yadav 6b948d47e8 Merge branch 'main' into sushan/T-4916-project-overview-activity-section 2024-02-28 13:26:44 +05:45
Sushan Yadav ae1e3455e4 comment fixes 2024-02-28 13:15:57 +05:45
Sushan Yadav 951fd9a3f3 chore: limit commit message to 4 line 2024-02-28 12:24:14 +05:45
Sushan Yadav 97fea83582 feat: add sepeator calc in comment 2024-02-28 11:56:22 +05:45
Sushan Yadav 47cd8079e4 feat: reskin w/ new design system 2024-02-28 11:50:38 +05:45
Wahyu Kurniawan 62734308fc [T-4907: style] Re-styling home page & sidebar component (#132)
* ️ feat: create heading component

* ♻️ refactor: move sidebar inside shared components

* ️ feat: add polymorphic prop type for heading component

* 🎨 style: re-styling project list page

* ♻️ refactor: remove `.env`

* 🎨 style: set default font weight to normal for heading component
2024-02-28 12:50:30 +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
46 changed files with 500 additions and 141 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 =
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "0.1.0",
"version": "0.1.3",
"private": true,
"dependencies": {
"@fontsource-variable/jetbrains-mono": "^5.0.19",
@@ -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)}
@@ -1,45 +1,85 @@
import React from 'react';
import { Typography, IconButton, Avatar } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { Link } from 'react-router-dom';
import { GitCommitWithBranch } from '../../../types';
import { Avatar } from 'components/shared/Avatar';
import { Button } from 'components/shared/Button';
import {
ArrowRightCircleFilledIcon,
BranchIcon,
} from 'components/shared/CustomIcon';
import { formatDistance } from 'date-fns';
import { getInitials } from 'utils/geInitials';
interface ActivityCardProps {
activity: GitCommitWithBranch;
}
const ActivityCard = ({ activity }: ActivityCardProps) => {
const formattedDate = formatDistance(
new Date(activity.commit.author!.date!),
new Date(),
{
addSuffix: true,
},
);
return (
<div className="group flex gap-2 hover:bg-gray-200 rounded mt-1">
<div className="w-8">
<Avatar
src={activity.author?.avatar_url}
variant="rounded"
size="sm"
placeholder={''}
<>
<Link
to={activity.html_url}
target="_blank"
className="p-3 gap-2 focus-within:ring-2 focus-within:ring-controls-primary/40 focus:outline-none rounded-xl transition-colors hover:bg-base-bg-alternate flex group"
>
<div>
<Avatar
type="orange"
size={36}
initials={getInitials(activity.commit.author?.name ?? '')}
imageSrc={activity.author?.avatar_url}
/>
</div>
<div className="flex-1">
<span className="text-elements-high-em text-sm font-medium tracking-tight">
{activity.commit.author?.name}
</span>
<span className="text-elements-low-em text-xs flex items-center gap-2">
<span title={formattedDate} className="whitespace-nowrap">
{formattedDate}
</span>
{/* Dot */}
<span className="w-0.5 h-0.5 rounded-full bg-border-interactive-hovered"></span>
<span className="flex justify-center items-center gap-1.5">
<div>
<BranchIcon />
</div>
<span
title={activity.branch.name}
// pseudo to increase hover area
className="before:absolute relative before:h-5 before:-top-4 before:inset-x-0"
>
<span className="line-clamp-1">{activity.branch.name}</span>
</span>
</span>
</span>
<p
title={activity.commit.message}
className="text-sm line-clamp-4 tracking-tight text-elements-mid-em mt-2"
>
{activity.commit.message}
</p>
</div>
<Button
aria-label="Go to commit"
variant="unstyled"
tabIndex={-1}
className="p-0 text-elements-low-em group-focus-within:opacity-100 group-hover:opacity-100 opacity-0 transition-all"
leftIcon={<ArrowRightCircleFilledIcon className="w-5 h-5" />}
/>
</div>
<div className="grow">
<Typography placeholder={''}>{activity.commit.author?.name}</Typography>
<Typography variant="small" color="gray" placeholder={''}>
{relativeTimeISO(activity.commit.author!.date!)} ^{' '}
{activity.branch.name}
</Typography>
<Typography variant="small" color="gray" placeholder={''}>
{activity.commit.message}
</Typography>
</div>
<div className="mr-2 self-center hidden group-hover:block">
<IconButton
size="sm"
className="rounded-full bg-gray-600"
placeholder={''}
>
{'>'}
</IconButton>
</div>
</div>
</Link>
{/* Separator calc => 100% - 36px (avatar) - 12px (padding-left) - 8px (gap)
*/}
<div className="pt-2 mb-2 ml-auto h-1 w-[calc(100%-36px-12px-8px)] border-b border-border-separator last:border-b-transparent"></div>
</>
);
};
@@ -0,0 +1,21 @@
import React from 'react';
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const ArrowRightCircleFilledIcon = (props: CustomIconProps) => {
return (
<CustomIcon
{...props}
fill="none"
height="32"
viewBox="0 0 32 32"
width="32"
>
<path
clipRule="evenodd"
d="M29.3334 16C29.3334 8.63619 23.3638 2.66666 16 2.66666C8.63622 2.66666 2.66669 8.63619 2.66669 16C2.66669 23.3638 8.63622 29.3333 16 29.3333C23.3638 29.3333 29.3334 23.3638 29.3334 16ZM18.1144 17.3333L16.3905 19.0572C15.8698 19.5779 15.8698 20.4221 16.3905 20.9428C16.9112 21.4635 17.7555 21.4635 18.2762 20.9428L21.3334 17.8856C22.3748 16.8442 22.3748 15.1558 21.3334 14.1144L18.2762 11.0572C17.7555 10.5365 16.9112 10.5365 16.3905 11.0572C15.8698 11.5779 15.8698 12.4221 16.3905 12.9428L18.1144 14.6667H10.6667C9.93031 14.6667 9.33335 15.2636 9.33335 16C9.33335 16.7364 9.93031 17.3333 10.6667 17.3333H18.1144Z"
fill="currentColor"
fillRule="evenodd"
/>
</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,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>
);
};
@@ -22,6 +22,8 @@ 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';
@@ -30,3 +32,4 @@ export * from './GitHubLogo';
export * from './ClockIcon';
export * from './HorizontalDotIcon';
export * from './WarningDiamondIcon';
export * from './ArrowRightCircleFilledIcon';
@@ -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',
+147
View File
@@ -2,6 +2,153 @@
@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;
@@ -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;
}
}
+19 -21
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 { 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>
);
};
@@ -1,15 +1,9 @@
import React, { useEffect, useState } from 'react';
import { Domain, DomainStatus } from 'gql-client';
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
import { useNavigate, useOutletContext } from 'react-router-dom';
import { RequestError } from 'octokit';
import {
Typography,
Button,
Chip,
Avatar,
Tooltip,
} from '@material-tailwind/react';
import { Typography, Chip, Avatar, Tooltip } from '@material-tailwind/react';
import ActivityCard from '../../../../components/projects/project/ActivityCard';
import { relativeTimeMs } from '../../../../utils/time';
@@ -17,6 +11,8 @@ import { useOctokit } from '../../../../context/OctokitContext';
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { formatAddress } from '../../../../utils/format';
import { Button } from 'components/shared/Button';
import { Heading } from 'components/shared/Heading';
const COMMITS_PER_PAGE = 4;
@@ -107,9 +103,9 @@ const OverviewTabPanel = () => {
}, [project]);
return (
<div className="grid grid-cols-5">
<div className="col-span-3 p-2">
<div className="flex items-center gap-2 p-2 ">
<div className="grid grid-cols-5 gap-[72px] mt-7">
<div className="col-span-3">
<div className="flex items-center gap-2">
<Avatar
src={project.icon || '/gray.png'}
variant="rounded"
@@ -143,12 +139,11 @@ const OverviewTabPanel = () => {
/>
<Button
className="normal-case rounded-full"
color="blue"
variant="primary"
size="sm"
onClick={() => {
navigate('settings/domains');
}}
placeholder={''}
>
Setup
</Button>
@@ -179,21 +174,17 @@ const OverviewTabPanel = () => {
<div>No current deployment found</div>
)}
</div>
<div className="col-span-2 p-2">
<div className="flex justify-between">
<Typography variant="h6" placeholder={''}>
Activity
</Typography>
<button className="text-xs bg-gray-300 rounded-full p-2">
<div className="col-span-2 mr-1">
<div className="flex items-center justify-between">
<Heading className="text-lg leading-6 font-medium">Activity</Heading>
<Button variant="tertiary" size="sm">
See all
</button>
</Button>
</div>
<div className="p-2">
<div className="mt-5">
{activities.map((activity, index) => {
return (
<Link to={activity.html_url} target="_blank" key={index}>
<ActivityCard activity={activity} />
</Link>
<ActivityCard activity={activity} key={`activity-${index}`} />
);
})}
</div>
+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;
+1
View File
@@ -14,6 +14,7 @@ export default withMT({
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
display: ['Inter Display', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
fontSize: {