Skip to content

Commit

Permalink
chore(web): use shadcn ui for the web app (#106)
Browse files Browse the repository at this point in the history
* style(frontend): setup shadcdn

* style(frontend): pass external as dependency of the snippet

* feat: design the header

* feat: design the directory

* chore: use shadcn everywhere

* chore: imports restructure

* test: update tests

* chore: release frontend

* fix: lint
  • Loading branch information
tericcabrel authored Sep 29, 2024
1 parent c263cf8 commit 25631bd
Show file tree
Hide file tree
Showing 154 changed files with 2,819 additions and 2,206 deletions.
6 changes: 6 additions & 0 deletions .changeset/tricky-mugs-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@snipcode/front': minor
'@snipcode/web': minor
---

Use shadcn ui for web design page
8 changes: 8 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@
"index", // <- index imports
"unknown" // <- unknown
],
"pathGroups": [
{
"pattern": "@snipcode/**",
"group": "external",
"position": "after"
}
],
"pathGroupsExcludedImportTypes": ["builtin"],
"newlines-between": "always",
"alphabetize": {
"order": "asc",
Expand Down
1 change: 1 addition & 0 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Logger, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { ServeStaticModule } from '@nestjs/serve-static';

import { DomainModule } from '@snipcode/domain';

import { EnvironmentVariables, validate } from './configs/environment';
Expand Down
1 change: 1 addition & 0 deletions apps/backend/src/configs/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException, createParamDecorator } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

import { SessionService } from '@snipcode/domain';
import { errors } from '@snipcode/utils';

Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/configs/exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import {
PrismaClientUnknownRequestError,
PrismaClientValidationError,
} from '@prisma/client/runtime/library';
import { isAppError } from '@snipcode/utils';
import { Response } from 'express';
import { GraphQLError } from 'graphql';

import { isAppError } from '@snipcode/utils';

import { INTERNAL_SERVER_ERROR } from '../utils/constants';

type PrismaError =
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/features/app/app.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService, RoleService, UserService } from '@snipcode/domain';
import { mock } from 'jest-mock-extended';

import { PrismaService, RoleService, UserService } from '@snipcode/domain';

import { AppService } from './app.service';

const prismaServiceMock = mock<PrismaService>();
Expand Down
1 change: 1 addition & 0 deletions apps/backend/src/features/app/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import { RoleService, UserService } from '@snipcode/domain';

import { EnvironmentVariables } from '../../configs/environment';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import request from 'supertest';

import { SessionService } from '@snipcode/domain';
import { isValidUUIDV4 } from '@snipcode/utils';
import request from 'supertest';

import { TestHelper } from '../../../utils/tests/helpers';
import { TestServer, startTestServer } from '../../../utils/tests/server';
Expand Down
1 change: 1 addition & 0 deletions apps/backend/src/features/auth/graphql/auth.resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { UseGuards } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Args, Context, Mutation, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';

import {
CreateSessionInput,
CreateUserInput,
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/features/auth/rest/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Controller, Get, Logger, Query, Res } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Response } from 'express';

import {
CreateSessionInput,
CreateUserRootFolderInput,
Expand All @@ -9,7 +11,6 @@ import {
UserService,
} from '@snipcode/domain';
import { addDayToDate, errors } from '@snipcode/utils';
import { Response } from 'express';

import { EnvironmentVariables } from '../../../configs/environment';
import { AUTH_SUCCESS_URL } from '../../../utils/constants';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as url from 'node:url';

import { SessionService } from '@snipcode/domain';
import { HttpResponse, http } from 'msw';
import { setupServer } from 'msw/node';
import request from 'supertest';

import { SessionService } from '@snipcode/domain';

import { TestHelper } from '../../../utils/tests/helpers';
import { TestServer, startTestServer } from '../../../utils/tests/server';
import { GitHubUserResponse } from '../types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { User } from '@snipcode/domain';
import { HttpResponse, http } from 'msw';
import { setupServer } from 'msw/node';

import { User } from '@snipcode/domain';

import { GithubService } from './github.service';
import { GitHubUserResponse } from '../types';

Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/features/auth/services/github.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';

import { CreateUserInput, UpdateUserInput, User } from '@snipcode/domain';
import { AppError } from '@snipcode/utils';
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';

import { EnvironmentVariables } from '../../../configs/environment';
import { GitHubUserResponse } from '../types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';

import {
CreateFolderInput,
Folder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';

import {
CreateSnippetInput,
DeleteSnippetInput,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Controller, Get, Param } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import { SnippetService } from '@snipcode/domain';
import { OEmbedResult, generateOembedMetadata } from '@snipcode/embed';

Expand Down
1 change: 1 addition & 0 deletions apps/backend/src/features/users/graphql/user.resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ConfigService } from '@nestjs/config';
import { Args, Mutation, Resolver } from '@nestjs/graphql';

import { NewsletterService } from '@snipcode/domain';

import { EnvironmentVariables } from '../../../configs/environment';
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/utils/graphql/date-scalar.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { CustomScalar, Scalar } from '@nestjs/graphql';
import { errors } from '@snipcode/utils';
import { Kind, ValueNode } from 'graphql';
import { GraphQLError } from 'graphql';

import { errors } from '@snipcode/utils';

import { DATE_REGEX } from '../constants';

@Scalar('Date')
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/utils/tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { INestApplication } from '@nestjs/common';
import { randEmail, randFullName, randPassword, randWord } from '@ngneat/falso';
import request from 'supertest';

import { PrismaService, RoleName } from '@snipcode/domain';
import { generateJwtToken } from '@snipcode/utils';
import request from 'supertest';

type CreateUserInputArgs = {
email: string;
Expand Down
7 changes: 5 additions & 2 deletions apps/web/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
'sentry.edge.config.js',
'.eslintrc.js',
'vitest.config.ts',
'tailwind.config.ts',
],
parserOptions: {
ecmaVersion: 2023,
Expand All @@ -27,9 +28,11 @@ module.exports = {
rules: {
camelcase: 'off',
'import/prefer-default-export': 'off',
'react/jsx-filename-extension': 'off',
'react/jsx-props-no-spreading': 'off',
'react/no-unused-prop-types': 'off',
'react/boolean-prop-naming': 'error',
'react/jsx-no-leaked-render': 'error',
'react/no-unused-prop-types': 'error',
'react/destructuring-assignment': 'error',
'react/require-default-props': 'off',
'import/extensions': 'off',
quotes: 'off',
Expand Down
17 changes: 17 additions & 0 deletions apps/web/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/styles/tailwind.css",
"baseColor": "slate",
"cssVariables": false,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
6 changes: 5 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@
"dependencies": {
"@apollo/client": "3.10.6",
"@apollo/experimental-nextjs-app-support": "0.11.2",
"@headlessui/react": "2.1.0",
"@hookform/resolvers": "3.6.0",
"@radix-ui/react-slot": "1.1.0",
"@sentry/nextjs": "8.11.0",
"@snipcode/front": "workspace:*",
"@snipcode/utils": "workspace:*",
"class-variance-authority": "0.7.0",
"classnames": "2.5.1",
"clsx": "2.1.1",
"graphql": "16.9.0",
"next": "14.2.4",
"next-seo": "6.5.0",
"react": "18.3.1",
"react-cookie": "7.1.4",
"react-dom": "18.3.1",
"react-hook-form": "7.52.0",
"tailwind-merge": "2.4.0",
"tailwindcss-animate": "1.0.7",
"yup": "1.4.0"
},
"devDependencies": {
Expand Down
29 changes: 10 additions & 19 deletions apps/web/src/app/(protected)/app/browse/container.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import { Button } from '@snipcode/front/forms/button';
import { useState } from 'react';

import { Button } from '@snipcode/front/components/ui/button';
import { SelectInput } from '@snipcode/front/forms/select-input';
import { ChevronDoubleLeftIcon, ChevronDoubleRightIcon, SearchIcon } from '@snipcode/front/icons';
import { ChevronsLeftIcon, ChevronsRightIcon, SearchIcon } from '@snipcode/front/icons';
import { usePublicSnippets } from '@snipcode/front/services';
import { SelectOption } from '@snipcode/front/typings/components';
import { PublicSnippetItem, PublicSnippetResult } from '@snipcode/front/typings/queries';
import { useState } from 'react';
import { SelectOption } from '@snipcode/front/types/components';
import { PublicSnippetItem, PublicSnippetResult } from '@snipcode/front/types/queries';

import { PublicSnippet } from '@/components/snippets/public-snippet';
import { usePaginationToken } from '@/hooks/use-pagination-token';
Expand Down Expand Up @@ -124,23 +125,13 @@ export const BrowseContainer = ({ data }: Props) => {
))}
</div>
<div className="w-full flex justify-center mt-10 space-x-4">
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoBack}
onClick={onPreviousItemClick}
>
<ChevronDoubleLeftIcon className="w-6 h-4" />
<Button className="w-32" disabled={!canGoBack} onClick={onPreviousItemClick}>
<ChevronsLeftIcon />
Previous
</Button>
<Button
className="bg-gray-200 w-auto items-center"
color="white-gray"
disabled={!canGoForward}
onClick={onNextItemClick}
>
<Button className="w-32" disabled={!canGoForward} onClick={onNextItemClick}>
Next
<ChevronDoubleRightIcon className="w-6 h-4" />
<ChevronsRightIcon />
</Button>
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/app/(protected)/app/browse/lib/fetch-snippets.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { cookies } from 'next/headers';

import { findPublicSnippetsQuery } from '@snipcode/front/graphql';
import { PublicSnippetsQuery } from '@snipcode/front/graphql/generated';
import { SNIPPET_ITEM_PER_PAGE } from '@snipcode/front/lib/constants';
import { formatPublicSnippetsResult } from '@snipcode/front/services';
import { SNIPPET_ITEM_PER_PAGE } from '@snipcode/front/utils/constants';
import { cookies } from 'next/headers';

import { getApolloClient } from '@/lib/apollo/server';
import { AUTH_COOKIE_NAME } from '@/lib/constants';
Expand Down
10 changes: 7 additions & 3 deletions apps/web/src/app/(protected)/app/folders/[id]/container.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';

import { useParams } from 'next/navigation';

import { Directory } from '@snipcode/front/components/directory';
import { useFindFolder } from '@snipcode/front/services';
import { useParams } from 'next/navigation';

import { useFolderDirectory } from '@/hooks/use-folder-directory';
import { EMBEDDABLE_HOST_URL, SHAREABLE_HOST_URL } from '@/lib/constants';

export const ViewFolderContainer = () => {
const queryParams = useParams<{ id: string }>();
Expand All @@ -18,16 +20,18 @@ export const ViewFolderContainer = () => {

return (
<div className="py-10">
{isFolderFound && (
{isFolderFound ? (
<Directory
embeddableHostUrl={EMBEDDABLE_HOST_URL}
folderId={folderId}
rootFolderId={rootFolderId}
shareableHostUrl={SHAREABLE_HOST_URL}
title={data?.name ?? '-----'}
onBreadcrumbPathClick={handleBreadcrumbClick}
onNavigateToFolder={navigateToFolder}
onSnippetClick={openSnippet}
/>
)}
) : null}
</div>
);
};
3 changes: 3 additions & 0 deletions apps/web/src/app/(protected)/app/home/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Directory } from '@snipcode/front/components/directory';
import { useAuthenticatedUser } from '@snipcode/front/services';

import { useFolderDirectory } from '@/hooks/use-folder-directory';
import { EMBEDDABLE_HOST_URL, SHAREABLE_HOST_URL } from '@/lib/constants';

export const HomeContainer = () => {
const { data: user } = useAuthenticatedUser();
Expand All @@ -12,8 +13,10 @@ export const HomeContainer = () => {
return (
<div className="py-10">
<Directory
embeddableHostUrl={EMBEDDABLE_HOST_URL}
folderId={rootFolderId}
rootFolderId={rootFolderId}
shareableHostUrl={SHAREABLE_HOST_URL}
title={`Welcome, ${user?.name}`}
onBreadcrumbPathClick={handleBreadcrumbClick}
onNavigateToFolder={navigateToFolder}
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/app/(protected)/app/snippets/[id]/container.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use client';

import { useParams } from 'next/navigation';

import { BreadCrumb } from '@snipcode/front/components/directory/breadcrumb';
import { ViewSnippet } from '@snipcode/front/components/directory/snippets/form/view-snippet';
import { useFindSnippet } from '@snipcode/front/services';
import { useParams } from 'next/navigation';

import { useFolderDirectory } from '@/hooks/use-folder-directory';

Expand All @@ -19,7 +20,7 @@ export const ViewSnippetContainer = () => {

return (
<div className="py-10">
{isSnippetFound && (
{isSnippetFound ? (
<div className="max-w-7xl py-8 mx-auto sm:px-6 lg:px-8">
<BreadCrumb
current={data.snippet.id}
Expand All @@ -31,7 +32,7 @@ export const ViewSnippetContainer = () => {
<ViewSnippet snippet={data.snippet} />
</div>
</div>
)}
) : null}
</div>
);
};
Loading

0 comments on commit 25631bd

Please sign in to comment.