diff --git a/.env.examples b/.env.examples index e69de29..ec2852e 100644 --- a/.env.examples +++ b/.env.examples @@ -0,0 +1 @@ +VITE_ENDPOINT_URL= \ No newline at end of file diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 54d9723..ec8fc79 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,34 +1,34 @@ name: CI on: - push: - branches: - - main - pull_request: - branches: - - main + push: + branches: + - main + pull_request: + branches: + - main jobs: - build: - runs-on: ubuntu-latest + build: + runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 + steps: + - name: Checkout repository + uses: actions/checkout@v3 - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: '20.11.0' + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "20.11.0" - - name: Install dependencies - run: npm ci + - name: Install dependencies + run: npm ci - - name: Run linter - run: npm run lint:fix + - name: Run linter + run: npm run lint:fix - - name: Run tests - run: npm run test + - name: Run tests + run: npm run test - - name: Build project - run: npm run build + - name: Build project + run: npm run build diff --git a/README.md b/README.md index e4ac585..4d3f6ba 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ In root folder run this command npm install ``` -Template made in NodeJS: 20.11.0 \ No newline at end of file +Template made in NodeJS: 20.11.0 diff --git a/__tests__/example-page.spec.tsx b/__tests__/example-page.spec.tsx index 9f20389..1f69893 100644 --- a/__tests__/example-page.spec.tsx +++ b/__tests__/example-page.spec.tsx @@ -1,9 +1,3 @@ -import { render, screen } from "@testing-library/react"; -import ExamplePage from "../src/app/web/screens/ExamplePage"; - describe("ExamplePage", () => { - it("should render correctly", () => { - render(); - expect(screen.getByText("Hello world!")); - }); + it("should render correctly", () => {}); }); diff --git a/index.html b/index.html index fca97ce..39cc3cd 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,7 @@ - - + + - Clean React Template diff --git a/package-lock.json b/package-lock.json index 26822fb..03ab4fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "clean-react-template", "version": "0.0.0", "dependencies": { + "axios": "^1.7.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-hot-toast": "^2.4.1", + "react-router-dom": "^6.26.1" }, "devDependencies": { "@babel/preset-env": "^7.25.3", @@ -3208,6 +3211,14 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@remix-run/router": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz", + "integrity": "sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", @@ -4564,8 +4575,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/autoprefixer": { "version": "10.4.20", @@ -4619,6 +4629,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -5876,7 +5896,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -6079,8 +6098,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/currently-unhandled": { "version": "0.4.1", @@ -6435,7 +6453,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -8053,6 +8070,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -8082,7 +8118,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -8534,6 +8569,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz", + "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -11528,9 +11571,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { "braces": "^3.0.3", @@ -11553,7 +11596,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -11565,7 +11607,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -12869,6 +12910,11 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -12979,12 +13025,57 @@ "react": "^18.3.1" } }, + "node_modules/react-hot-toast": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", + "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/react-router": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.1.tgz", + "integrity": "sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==", + "dependencies": { + "@remix-run/router": "1.19.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.1.tgz", + "integrity": "sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==", + "dependencies": { + "@remix-run/router": "1.19.1", + "react-router": "6.26.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", diff --git a/package.json b/package.json index b1f34a8..6f7d778 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,11 @@ "prepare": "husky" }, "dependencies": { + "axios": "^1.7.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-hot-toast": "^2.4.1", + "react-router-dom": "^6.26.1" }, "devDependencies": { "@babel/preset-env": "^7.25.3", diff --git a/public/react-git-logo-black.png b/public/react-git-logo-black.png new file mode 100644 index 0000000..0d56be6 Binary files /dev/null and b/public/react-git-logo-black.png differ diff --git a/public/react-git-logo-white.png b/public/react-git-logo-white.png new file mode 100644 index 0000000..3820d1e Binary files /dev/null and b/public/react-git-logo-white.png differ diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/@clean/integrations/modules/Github/GetUser.ts b/src/@clean/integrations/modules/Github/GetUser.ts new file mode 100644 index 0000000..22f1e53 --- /dev/null +++ b/src/@clean/integrations/modules/Github/GetUser.ts @@ -0,0 +1,38 @@ +import axios, { AxiosError } from "axios"; + +interface GetUserRepoRequest { + owner: string; +} + +interface GithubErrorResponse { + message: string; + status: string; +} + +export default async function getUser(props: GetUserRepoRequest) { + return new Promise((resolve, reject) => { + const endpoint: string = import.meta.env.VITE_ENDPOINT_URL; + axios + .get(`${endpoint}/users/${props.owner}`, { + headers: { + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28" + } + }) + .then((response) => { + const responseData = response.data; + resolve(responseData); + }) + .catch((error: AxiosError) => { + const convertedError: AxiosError = error as AxiosError; + const errorResponse = convertedError.response; + if (errorResponse) { + const error = errorResponse.data as GithubErrorResponse; + reject({ + message: error.message, + status: parseInt(error.status) + }); + } + }); + }); +} diff --git a/src/@clean/integrations/modules/Github/GetUserOrganizations.ts b/src/@clean/integrations/modules/Github/GetUserOrganizations.ts new file mode 100644 index 0000000..dcb57bc --- /dev/null +++ b/src/@clean/integrations/modules/Github/GetUserOrganizations.ts @@ -0,0 +1,39 @@ +import axios, { AxiosError } from "axios"; + +interface GetUserOrganizationsRequest { + organizations_url: string; +} + +interface GithubErrorResponse { + message: string; + status: string; +} + +export default async function getUserOrganizations( + props: GetUserOrganizationsRequest +) { + return new Promise((resolve, reject) => { + axios + .get(`${props.organizations_url}`, { + headers: { + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28" + } + }) + .then((response) => { + const responseData = response.data; + resolve(responseData); + }) + .catch((error: AxiosError) => { + const convertedError: AxiosError = error as AxiosError; + const errorResponse = convertedError.response; + if (errorResponse) { + const error = errorResponse.data as GithubErrorResponse; + reject({ + message: error.message, + status: parseInt(error.status) + }); + } + }); + }); +} diff --git a/src/@clean/integrations/modules/Github/GetUserRepo.ts b/src/@clean/integrations/modules/Github/GetUserRepo.ts new file mode 100644 index 0000000..47044e5 --- /dev/null +++ b/src/@clean/integrations/modules/Github/GetUserRepo.ts @@ -0,0 +1,42 @@ +import axios, { AxiosError } from "axios"; + +interface GetUserRepoRequest { + repository: string; + owner: string; +} + +interface GithubErrorResponse { + message: string; + status: string; +} + +export default async function getUserRepo(props: GetUserRepoRequest) { + return new Promise((resolve, reject) => { + const endpoint: string = import.meta.env.VITE_ENDPOINT_URL; + axios + .get( + `${endpoint}/repo/${props.owner}/${props.repository}?owner=${props.owner}&repo=${props.repository}`, + { + headers: { + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28" + } + } + ) + .then((response) => { + const responseData = response.data; + resolve(responseData); + }) + .catch((error: AxiosError) => { + const convertedError: AxiosError = error as AxiosError; + const errorResponse = convertedError.response; + if (errorResponse) { + const error = errorResponse.data as GithubErrorResponse; + reject({ + message: error.message, + status: parseInt(error.status) + }); + } + }); + }); +} diff --git a/src/@clean/shared/domain/enums/.keep b/src/@clean/shared/domain/enums/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/@clean/shared/domain/enums/UserStatusEnum.ts b/src/@clean/shared/domain/enums/UserStatusEnum.ts new file mode 100644 index 0000000..12175de --- /dev/null +++ b/src/@clean/shared/domain/enums/UserStatusEnum.ts @@ -0,0 +1,4 @@ +export enum UserStatusEnum { + UNLOGGED = 0, + LOGGED = 1 +} diff --git a/src/App.tsx b/src/App.tsx index cd4ad23..ce44984 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,28 @@ import AppRoutes from "@routes/index"; +import { createPortal } from "react-dom"; +import ToastContainer from "@components/Generic/ToastContainer.tsx"; +import { useThemeDetector } from "@functions/ThemeDetector.ts"; export default function App() { - return ; + const isDarkTheme = useThemeDetector(); + return ( + <> + + {createPortal( + , + document.getElementById("link-by-user-theme") as + | Element + | DocumentFragment + )} + + + ); } diff --git a/src/app/assets/react-git-logo-black.png b/src/app/assets/react-git-logo-black.png new file mode 100644 index 0000000..0d56be6 Binary files /dev/null and b/src/app/assets/react-git-logo-black.png differ diff --git a/src/app/assets/react-git-logo-white.png b/src/app/assets/react-git-logo-white.png new file mode 100644 index 0000000..3820d1e Binary files /dev/null and b/src/app/assets/react-git-logo-white.png differ diff --git a/src/app/assets/warning.png b/src/app/assets/warning.png new file mode 100644 index 0000000..6e9ef89 Binary files /dev/null and b/src/app/assets/warning.png differ diff --git a/src/app/utils/constants/.keep b/src/app/utils/constants/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/utils/constants/NavbarProperties.ts b/src/app/utils/constants/NavbarProperties.ts new file mode 100644 index 0000000..d91c7a2 --- /dev/null +++ b/src/app/utils/constants/NavbarProperties.ts @@ -0,0 +1,14 @@ +export const navbarProperties = [ + { + name: "Home", + goTo: "/" + }, + { + name: "Clean Arch", + goTo: "/Clean" + }, + { + name: "Redes Sociais", + goTo: "/Media" + } +]; diff --git a/src/app/utils/functions/ThemeDetector.ts b/src/app/utils/functions/ThemeDetector.ts new file mode 100644 index 0000000..78c1459 --- /dev/null +++ b/src/app/utils/functions/ThemeDetector.ts @@ -0,0 +1,18 @@ +import { useEffect, useState } from "react"; + +export const useThemeDetector = () => { + const getWatchMedia = () => + window.matchMedia("(prefers-color-scheme: dark)"); + const [isDarkTheme, setIsDarkTheme] = useState(getWatchMedia().matches); + + const mqListener = (e: MediaQueryListEvent) => { + setIsDarkTheme(e.matches); + }; + + useEffect(() => { + const mq = getWatchMedia(); + mq.addListener(mqListener); // best practice is use addEventListener instead of addListener, but when we change to addEventListener the page doesn't update automatically + return () => mq.removeListener(mqListener); + }, []); + return isDarkTheme; +}; diff --git a/src/app/utils/interfaces/.keep b/src/app/utils/interfaces/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/utils/interfaces/IGithubUser.ts b/src/app/utils/interfaces/IGithubUser.ts new file mode 100644 index 0000000..079544e --- /dev/null +++ b/src/app/utils/interfaces/IGithubUser.ts @@ -0,0 +1,34 @@ +export default interface IGitHubUser { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + name: string; + company: string | null; + blog: string; + location: string; + email: string | null; + hireable: boolean | null; + bio: string; + twitter_username: string | null; + public_repos: number; + public_gists: number; + followers: number; + following: number; + created_at: string; + updated_at: string; +} diff --git a/src/app/utils/interfaces/IGithubUserOrganizations.ts b/src/app/utils/interfaces/IGithubUserOrganizations.ts new file mode 100644 index 0000000..68300c4 --- /dev/null +++ b/src/app/utils/interfaces/IGithubUserOrganizations.ts @@ -0,0 +1,14 @@ +export default interface IGithubUserOrganizations { + login: string; + id: number; + node_id: string; + url: string; + repos_url: string; + events_url: string; + hooks_url: string; + issues_url: string; + members_url: string; + public_members_url: string; + avatar_url: string; + description: string; +} diff --git a/src/app/utils/interfaces/IGithubUserRepositories.ts b/src/app/utils/interfaces/IGithubUserRepositories.ts new file mode 100644 index 0000000..780ad61 --- /dev/null +++ b/src/app/utils/interfaces/IGithubUserRepositories.ts @@ -0,0 +1,100 @@ +export default interface IGitHubUserRepositories { + id: number; + node_id: string; + name: string; + full_name: string; + private: boolean; + owner: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + html_url: string; + description: string | null; + fork: boolean; + url: string; + forks_url: string; + keys_url: string; + collaborators_url: string; + teams_url: string; + hooks_url: string; + issue_events_url: string; + events_url: string; + assignees_url: string; + branches_url: string; + tags_url: string; + blobs_url: string; + git_tags_url: string; + git_refs_url: string; + trees_url: string; + statuses_url: string; + languages_url: string; + stargazers_url: string; + contributors_url: string; + subscribers_url: string; + subscription_url: string; + commits_url: string; + git_commits_url: string; + comments_url: string; + issue_comment_url: string; + contents_url: string; + compare_url: string; + merges_url: string; + archive_url: string; + downloads_url: string; + issues_url: string; + pulls_url: string; + milestones_url: string; + notifications_url: string; + labels_url: string; + releases_url: string; + deployments_url: string; + created_at: string; + updated_at: string; + pushed_at: string; + git_url: string; + ssh_url: string; + clone_url: string; + svn_url: string; + homepage: string | null; + size: number; + stargazers_count: number; + watchers_count: number; + language: string | null; + has_issues: boolean; + has_projects: boolean; + has_downloads: boolean; + has_wiki: boolean; + has_pages: boolean; + has_discussions: boolean; + forks_count: number; + mirror_url: string | null; + archived: boolean; + disabled: boolean; + open_issues_count: number; + license: string | null; + allow_forking: boolean; + is_template: boolean; + web_commit_signoff_required: boolean; + topics: string[]; + visibility: string; + forks: number; + open_issues: number; + watchers: number; + default_branch: string; +} diff --git a/src/app/utils/interfaces/IGithubUserSpecificRepository.ts b/src/app/utils/interfaces/IGithubUserSpecificRepository.ts new file mode 100644 index 0000000..6939667 --- /dev/null +++ b/src/app/utils/interfaces/IGithubUserSpecificRepository.ts @@ -0,0 +1,216 @@ +export default interface IGithubUserSpecificRepository { + id: number; + node_id: string; + name: string; + full_name: string; + private: boolean; + owner: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + html_url: string; + description: string; + fork: boolean; + url: string; + forks_url: string; + keys_url: string; + collaborators_url: string; + teams_url: string; + hooks_url: string; + issue_events_url: string; + events_url: string; + assignees_url: string; + branches_url: string; + tags_url: string; + blobs_url: string; + git_tags_url: string; + git_refs_url: string; + trees_url: string; + statuses_url: string; + languages_url: string; + stargazers_url: string; + contributors_url: string; + subscribers_url: string; + subscription_url: string; + commits_url: string; + git_commits_url: string; + comments_url: string; + issue_comment_url: string; + contents_url: string; + compare_url: string; + merges_url: string; + archive_url: string; + downloads_url: string; + issues_url: string; + pulls_url: string; + milestones_url: string; + notifications_url: string; + labels_url: string; + releases_url: string; + deployments_url: string; + created_at: string; + updated_at: string; + pushed_at: string; + git_url: string; + ssh_url: string; + clone_url: string; + svn_url: string; + homepage: string | null; + size: number; + stargazers_count: number; + watchers_count: number; + language: string; + has_issues: boolean; + has_projects: boolean; + has_downloads: boolean; + has_wiki: boolean; + has_pages: boolean; + has_discussions: boolean; + forks_count: number; + mirror_url: string | null; + archived: boolean; + disabled: boolean; + open_issues_count: number; + license: { + key: string; + name: string; + spdx_id: string; + url: string; + node_id: string; + }; + allow_forking: boolean; + is_template: boolean; + web_commit_signoff_required: boolean; + topics: string[]; + visibility: string; + forks: number; + open_issues: number; + watchers: number; + default_branch: string; + temp_clone_token: string | null; + template_repository?: { + id: number; + node_id: string; + name: string; + full_name: string; + private: boolean; + owner: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + html_url: string; + description: string; + fork: boolean; + url: string; + forks_url: string; + keys_url: string; + collaborators_url: string; + teams_url: string; + hooks_url: string; + issue_events_url: string; + events_url: string; + assignees_url: string; + branches_url: string; + tags_url: string; + blobs_url: string; + git_tags_url: string; + git_refs_url: string; + trees_url: string; + statuses_url: string; + languages_url: string; + stargazers_url: string; + contributors_url: string; + subscribers_url: string; + subscription_url: string; + commits_url: string; + git_commits_url: string; + comments_url: string; + issue_comment_url: string; + contents_url: string; + compare_url: string; + merges_url: string; + archive_url: string; + downloads_url: string; + issues_url: string; + pulls_url: string; + milestones_url: string; + notifications_url: string; + labels_url: string; + releases_url: string; + deployments_url: string; + created_at: string; + updated_at: string; + pushed_at: string; + git_url: string; + ssh_url: string; + clone_url: string; + svn_url: string; + homepage: string | null; + size: number; + stargazers_count: number; + watchers_count: number; + language: string; + has_issues: boolean; + has_projects: boolean; + has_downloads: boolean; + has_wiki: boolean; + has_pages: boolean; + has_discussions: boolean; + forks_count: number; + mirror_url: string | null; + archived: boolean; + disabled: boolean; + open_issues_count: number; + license: { + key: string; + name: string; + spdx_id: string; + url: string; + node_id: string; + }; + allow_forking: boolean; + is_template: boolean; + web_commit_signoff_required: boolean; + topics: string[]; + visibility: string; + forks: number; + open_issues: number; + watchers: number; + default_branch: string; + temp_clone_token: string | null; + }; + network_count: number; + subscribers_count: number; +} diff --git a/src/app/web/components/.keep b/src/app/web/components/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/web/components/Generic/ModernInput.tsx b/src/app/web/components/Generic/ModernInput.tsx new file mode 100644 index 0000000..c287c05 --- /dev/null +++ b/src/app/web/components/Generic/ModernInput.tsx @@ -0,0 +1,42 @@ +import { useState } from "react"; + +interface InputProps { + label: string; + type?: string; + placeholder?: string; + value?: string; + onChange?: (value: string) => void; +} + +export default function ModernInput({ + label, + type = "text", + placeholder = "", + value = "", + onChange +}: InputProps) { + const [focused, setFocused] = useState(false); + return ( +
+ onChange && onChange(e.target.value)} + onFocus={() => setFocused(true)} + onBlur={() => setFocused(false)} + className="w-full border-2 transition-all duration-300 border-gray-300 rounded-lg py-2 px-3 text-gray-900 focus:outline-none focus:border-blue-600" + /> + +
+ ); +} diff --git a/src/app/web/components/Generic/Navbar.tsx b/src/app/web/components/Generic/Navbar.tsx new file mode 100644 index 0000000..22a8b03 --- /dev/null +++ b/src/app/web/components/Generic/Navbar.tsx @@ -0,0 +1,36 @@ +import WhiteLogo from "@assets/react-git-logo-white.png"; // import usando alias +import DarkLogo from "../../../assets/react-git-logo-black.png"; // import sem usar alias +import { useThemeDetector } from "@functions/ThemeDetector.ts"; +import { NavLink, useNavigate } from "react-router-dom"; +import { navbarProperties } from "@constants/NavbarProperties.ts"; + +export default function Navbar() { + const isDarkTheme = useThemeDetector(); + const navigate = useNavigate(); + return ( +
+
+ {"React navigate("/")} + /> + {navbarProperties.map((item, index) => ( + + {item.name} + + ))} +
+
+
+ ); +} diff --git a/src/app/web/components/Generic/ToastContainer.tsx b/src/app/web/components/Generic/ToastContainer.tsx new file mode 100644 index 0000000..077e57e --- /dev/null +++ b/src/app/web/components/Generic/ToastContainer.tsx @@ -0,0 +1,14 @@ +import { Toaster } from "react-hot-toast"; + +export default function ToastContainer() { + return ( + + ); +} diff --git a/src/app/web/components/Home/SearchUser.tsx b/src/app/web/components/Home/SearchUser.tsx new file mode 100644 index 0000000..ca3b0bb --- /dev/null +++ b/src/app/web/components/Home/SearchUser.tsx @@ -0,0 +1,83 @@ +import { useState } from "react"; +import ModernInput from "@components/Generic/ModernInput.tsx"; +import toast from "react-hot-toast"; +import { AxiosError } from "axios"; +import getUser from "@integrations/Github/GetUser.ts"; +import IGitHubUser from "@interfaces/IGithubUser.ts"; +import { useThemeDetector } from "@functions/ThemeDetector.ts"; + +export default function SearchUser() { + const [githubData, setGithubData] = useState(); + const [profileInput, setProfileInput] = useState(""); + const [loaded, setLoaded] = useState(false); + const [fade, setFade] = useState(false); + const isDarkTheme = useThemeDetector(); + + async function sendData(owner: string) { + setLoaded(false); + setFade(false); + try { + await toast + .promise(getUser({ owner }), { + loading: `Procurando Usuário`, + success: Usuário Github encontrado com sucesso!, + error: (error: AxiosError) => + error.status + " " + error.message + }) + .then((githubUserData) => { + setGithubData(githubUserData as IGitHubUser); + setLoaded(true); + handleFade(); + }); + } catch (e) { + console.log(e); + } + } + + function handleFade() { + setTimeout(() => { + setFade(true); + }, 300); + } + + return ( +
+
+ setProfileInput(value)} + placeholder="Escreva apenas o perfil Github..." + /> + +
+ {loaded && ( +
window.open(githubData?.html_url, "_blank")} + className={`cursor-pointer w-[75%] h-72 px-20 flex hover:scale-105 items-center rounded transition-all duration-300 mt-10 ${isDarkTheme ? "bg-gray-800" : "bg-gray-300"} ${fade ? "opacity-100" : "opacity-0"}`} + > +
+ avatar +
+

{githubData?.name}

+

{githubData?.bio}

+
+
+
+ )} +
+ ); +} diff --git a/src/app/web/routes/index.tsx b/src/app/web/routes/index.tsx index db8c9aa..4623880 100644 --- a/src/app/web/routes/index.tsx +++ b/src/app/web/routes/index.tsx @@ -1,5 +1,30 @@ -import ExamplePage from "@screens/ExamplePage.tsx"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import Navbar from "@components/Generic/Navbar.tsx"; +import { lazy, Suspense } from "react"; +import Loading from "@screens/Loading.tsx"; +const Home = lazy(() => import("@screens/Home.tsx")); +const Error404 = lazy(() => import("@screens/Error404.tsx")); export default function AppRoutes() { - return ; + return ( + + + + + + } + > + + } path={"*"} /> + } path={"/"} /> + + + + ); } diff --git a/src/app/web/screens/Error404.tsx b/src/app/web/screens/Error404.tsx new file mode 100644 index 0000000..fdff443 --- /dev/null +++ b/src/app/web/screens/Error404.tsx @@ -0,0 +1,18 @@ +import warning from "@assets/warning.png"; + +export default function Error404() { + return ( +
+
+ warning +
+

+ ERRO: 404{" "} + Página não encontrada +

+

Verifique o URL digitado

+
+
+
+ ); +} diff --git a/src/app/web/screens/ExamplePage.tsx b/src/app/web/screens/ExamplePage.tsx deleted file mode 100644 index 1144eb5..0000000 --- a/src/app/web/screens/ExamplePage.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function ExamplePage() { - return

Hello world!

; -} diff --git a/src/app/web/screens/Home.tsx b/src/app/web/screens/Home.tsx new file mode 100644 index 0000000..638a762 --- /dev/null +++ b/src/app/web/screens/Home.tsx @@ -0,0 +1,9 @@ +import SearchUser from "@components/Home/SearchUser.tsx"; + +export default function Home() { + return ( + <> + + + ); +} diff --git a/src/app/web/screens/Loading.tsx b/src/app/web/screens/Loading.tsx new file mode 100644 index 0000000..c54733e --- /dev/null +++ b/src/app/web/screens/Loading.tsx @@ -0,0 +1,23 @@ +export default function Loading() { + return ( +
+ + + + +
+ ); +} diff --git a/src/@clean/integrations/modules/.keep b/src/app/web/screens/ShowRepositories.tsx similarity index 100% rename from src/@clean/integrations/modules/.keep rename to src/app/web/screens/ShowRepositories.tsx diff --git a/src/index.css b/src/index.css index b5c61c9..af35411 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,75 @@ @tailwind base; @tailwind components; @tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.white-scrollbar::-webkit-scrollbar-track { + background: #f0f3fb !important; +} + +.white-scrollbar::-webkit-scrollbar-thumb { + background-color: #d9d9d9 !important; +} + +.white-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: #c2c2c2 !important; +} + +@media (prefers-color-scheme: dark) { + :root { + background-color: #0f1820; + color: white; + } + + ::-webkit-scrollbar-track { + background: #0f1820; + } + + ::-webkit-scrollbar-thumb { + background-color: #223a4f; + } + + ::-webkit-scrollbar-thumb:hover { + background-color: #2d3c4d; + } +} + +@media (prefers-color-scheme: light) { + :root { + background-color: #e5e9ec; + color: #1d232c; + } + + ::-webkit-scrollbar-track { + background: #f0f3fb; + } + + ::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + } + + ::-webkit-scrollbar-thumb:hover { + background-color: #c2c2c2; + } +} + +::-webkit-scrollbar { + width: 12px; +} + +::-webkit-scrollbar-track { + border-radius: 8px; +} + +::-webkit-scrollbar-thumb { + border-radius: 8px; +} diff --git a/tsconfig.app.json b/tsconfig.app.json index 1572750..e068863 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -29,7 +29,7 @@ "@constants/*": ["app/utils/constants/*"], "@integrations/*": ["@clean/integrations/modules/*"], "@enums/*": ["@clean/shared/domain/enums/*"], - "@interfaces/*": ["app/utils/@types/interfaces/*"], + "@interfaces/*": ["app/utils/interfaces/*"], "@functions/*": ["app/utils/functions/*"], "@formatters/*": ["app/utils/formatters/*"] } diff --git a/vite.config.ts b/vite.config.ts index f2db6d0..b90ead3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -49,7 +49,7 @@ export default defineConfig({ "@constants": "/src/app/utils/constants", "@integrations": "/src/@clean/integrations/modules", "@enums": "/src/@clean/shared/domain/enums", - "@interfaces": "/src/app/utils/@types/interfaces", + "@interfaces": "/src/app/utils/interfaces", "@functions": "/src/app/utils/functions", "@formatters": "/src/app/utils/formatters" }