diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..b4aa050 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,51 @@ +name: Deploy + +on: + push: + branches: + - main + +jobs: + build: + name: Build + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: Install dependencies + run: npm install + + - name: Build project + run: npm run build + + - name: Upload production-ready build files + uses: actions/upload-artifact@v3 + with: + name: production-files + path: ./dist + + deploy: + name: Deploy + needs: build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + steps: + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: production-files + path: ./dist + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./dist diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fd6913 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +package-lock.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..f01ff5d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +**/node_modules/** +**/*.d.ts diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..086e94d --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,18 @@ +{ + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "quoteProps": "as-needed", + "jsxSingleQuote": false, + "trailingComma": "none", + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "always", + "proseWrap": "never", + "endOfLine": "lf", + "importOrder": ["", "", "", "^[./]"], + "plugins": ["prettier-plugin-organize-imports", "@ianvs/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"], + "tailwindFunctions": ["twMerge"] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c2d0465 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hanzla Mateen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..08ba48d --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# website + +## References + + + + + + diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..daefb07 Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..b5e0d16 Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..3e7d5e1 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..5ff7d69 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + + + + Hello React Github Pages + + + +
+ + + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..685e480 --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "react-gh-pages-boilerplate", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "postbuild": "node scripts/generate-static-files.mjs", + "format-staged": "lint-staged", + "format": "prettier --write \"src/**/*.{ts,tsx}\"", + "lint": "prettier --check \"src/**/*.{ts,tsx}\"", + "clean-node-modules": "npx rimraf node_modules && npx rimraf package-lock.json" + }, + "pre-commit": [ + "format-staged" + ], + "lint-staged": { + "*.{ts,tsx}": [ + "prettier --write" + ], + "*.scss": [ + "stylelint --fix" + ] + }, + "resolutions": { + "@types/react": "18.2.0", + "react": "18.2.0" + }, + "dependencies": { + "@fontsource/poppins": "^5.0.14", + "animate.css": "^4.1.1", + "react": "18.2.0", + "react-animate-on-scroll": "^2.1.9", + "react-dom": "18.2.0", + "react-icons": "^5.2.1", + "react-router-dom": "^6.25.1", + "typescript": "5.4.5" + }, + "devDependencies": { + "@ianvs/prettier-plugin-sort-imports": "4.1.0", + "@originjs/vite-plugin-commonjs": "^1.0.3", + "@tailwindcss/typography": "^0.5.13", + "@types/node": "^20.14.11", + "@types/react": "18.2.0", + "@types/react-dom": "18.2.0", + "autoprefixer": "^10", + "daisyui": "^4", + "postcss": "^8", + "prettier": "3.0.2", + "prettier-plugin-organize-imports": "^3.2.3", + "prettier-plugin-tailwindcss": "^0.5.11", + "react-daisyui": "^5.0.0", + "tailwindcss": "^3.3.2", + "vite": "5.1.7" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..116848f --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: [require("tailwindcss"), require("autoprefixer")], +}; diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..a05eda6 --- /dev/null +++ b/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Sitemap: https://{YOUR_WEBSITE_DOMAIN_HERE}/sitemap.xml \ No newline at end of file diff --git a/scripts/generate-static-files.mjs b/scripts/generate-static-files.mjs new file mode 100644 index 0000000..e552d0b --- /dev/null +++ b/scripts/generate-static-files.mjs @@ -0,0 +1,38 @@ +import fs from 'fs' +import path from 'path' +import routes from '../src/constants/routes.json' assert { type: 'json' } + +const destinationFolder = 'dist' +const filesToCopy = ['sitemap.xml', 'robots.txt', 'CNAME'] + +// Copy files from the root of the project to the dist folder +for (const sourceFile of filesToCopy) { + const destinationFile = path.join(destinationFolder, sourceFile) + + fs.copyFile(sourceFile, destinationFile, (err) => { + if (err) { + console.error(`Error copying file ${sourceFile}`, err) + } else { + console.log(`File ${sourceFile} copied successfully`) + } + }) +} + +// Create a new HTML file for each route based on the index.html file +for (const route in routes) { + if (route === 'Home') { + continue + } + const routeName = routes[route] + const routeFileName = `${routeName.replace('/', '')}.html` + const routeHtml = path.join(destinationFolder, routeFileName) + const indexHtml = path.join(destinationFolder, 'index.html') + + fs.copyFile(indexHtml, routeHtml, (err) => { + if (err) { + console.error(`Error copying file ${routeFileName}`, err) + } else { + console.log(`File ${routeFileName} copied successfully`) + } + }) +} diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..682f808 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..1389b6f --- /dev/null +++ b/src/App.css @@ -0,0 +1,19 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + font-family: 'Poppins'; +} + +.prose { + max-width: none; +} + +.prose img { + margin: 0px; +} + +/* .navbar { + box-shadow: 0px 25px 23px 0px rgba(0, 0, 0, 0.1); +} */ diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..802ad87 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { createBrowserRouter, RouterProvider } from 'react-router-dom' +import './App.css' +import routes from './constants/routes.json' +import Home from './pages/Home' +import PrivacyPolicy from './pages/PrivacyPolicy' + +const App = () => { + /** + * Routes that should be completely a different page/route should go here + * https://reactrouter.com/en/main/start/tutorial#adding-a-router + */ + const router = createBrowserRouter([ + { + path: routes.Privacy, + element: + }, + { + path: routes.Home, + element: + } + ]) + + return ( +
+ +
+ ) +} + +export default App diff --git a/src/components/about-us.tsx b/src/components/about-us.tsx new file mode 100644 index 0000000..c05fbb7 --- /dev/null +++ b/src/components/about-us.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import routes from '../constants/routes.json' +import { usePathScrollToView } from '../hooks/usePathScrollToView' + +const AboutUs = () => { + const myRef = usePathScrollToView(routes.AboutUs) + + return ( +
+

About Us

+
+ ) +} + +export default AboutUs diff --git a/src/components/footer.tsx b/src/components/footer.tsx new file mode 100644 index 0000000..18cb0d9 --- /dev/null +++ b/src/components/footer.tsx @@ -0,0 +1,89 @@ +import React from 'react' +import ScrollAnimation from 'react-animate-on-scroll' +import { FaEnvelope, FaGithub, FaLinkedinIn, FaMeta, FaTwitter } from 'react-icons/fa6' +import logo from '../../assets/logo.png' +import packageJson from '../../package.json' +import routes from '../constants/routes.json' +import { useForceNavigate } from '../hooks/useForceNavigate' + +const Footer = () => { + const navigate = useForceNavigate() + const socialLinks = [ + { + link: 'https://github.com/hanzlamateen', + icon: + }, + { + link: 'https://www.linkedin.com/in/hanzlamateen/', + icon: + }, + { + link: 'https://www.twitter.com/hanzlamateen/', + icon: + }, + { + link: 'https://www.facebook.com/hanzlamateen/', + icon: + }, + { + link: 'mailto:hanzlamateen@live.com', + icon: + } + ] + + return ( + + ) +} + +export default Footer diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx new file mode 100644 index 0000000..4dd1025 --- /dev/null +++ b/src/components/navbar.tsx @@ -0,0 +1,79 @@ +import React from 'react' +import logo from '../../assets/logo.png' +import packageJson from '../../package.json' +import routes from '../constants/routes.json' +import { useForceNavigate } from '../hooks/useForceNavigate' + +const Navbar = () => { + const navigate = useForceNavigate() + + const navLinks = [ + { + title: 'Home', + route: '/' + }, + { + title: 'About Us', + route: routes.AboutUs + } + ] + + return ( + + ) +} + +export default Navbar diff --git a/src/components/services.tsx b/src/components/services.tsx new file mode 100644 index 0000000..b94550c --- /dev/null +++ b/src/components/services.tsx @@ -0,0 +1,104 @@ +import React from 'react' +import ScrollAnimation from 'react-animate-on-scroll' +import corporateLogo from '../../assets/corporate.svg' +import crossBorderLogo from '../../assets/cross-border.svg' +import digitalLogo from '../../assets/digital.svg' +import privateLogo from '../../assets/private.svg' +import routes from '../constants/routes.json' +import { usePathScrollToView } from '../hooks/usePathScrollToView' + +const Services = () => { + const myRef = usePathScrollToView(routes.AboutUs) + + const services = [ + { + title: 'Corporate Banking Services', + logo: corporateLogo, + details: [ + 'International & Local Bank Accounts', + 'Multi-currency IBAN Accounts (over 25 currencies)', + 'Dedicated and Pooled SWIFT & SEPA Accounts', + 'Over 30 Regulated Activities', + 'Fast & Reliable B2B, B2C and Acquiring Services' + ] + }, + { + title: 'Private Banking Services', + logo: privateLogo, + details: [ + 'Operating and Savings Accounts for HNWI Clients', + 'Depositary Accounts in the Best EU Jurisdictions', + 'Top-rated Private Banks' + ] + }, + { + title: 'Digital Banking', + logo: digitalLogo, + details: [ + 'Fast Account Opening with more than 15 Neo Banks across the Globe', + 'Built-in Cryptocurrency Wallet', + 'Fiat-Cryptocurrency on and off Ramp Services: BTC, ETH, USDT and more...' + ] + }, + { + title: 'Cross-Border Payments', + logo: crossBorderLogo, + details: [ + 'Multi-currency IBAN Accounts (over 25 currencies)', + 'Dedicated and Pooled Accounts', + 'SEPA and SWIFT Cross-border Transfers', + 'Send and Receive Payments in more than 150 Countries' + ] + } + ] + return ( +
+
+

Services

+ +
+ {services.map((service, index) => ( +
+
+
+
+ +
+
+
+
+

{service.title}

+ +
+ +
    + {service.details.map((detail, index) => ( +
  • + {detail} +
  • + ))} +
+
+
+ ))} +
+ +
+
+ ) +} + +export default Services diff --git a/src/constants/routes.json b/src/constants/routes.json new file mode 100644 index 0000000..01f739f --- /dev/null +++ b/src/constants/routes.json @@ -0,0 +1,6 @@ +{ + "Home": "*", + "404": "/404", + "AboutUs": "/about", + "Privacy": "/privacy" +} diff --git a/src/hooks/useForceNavigate.tsx b/src/hooks/useForceNavigate.tsx new file mode 100644 index 0000000..d17320e --- /dev/null +++ b/src/hooks/useForceNavigate.tsx @@ -0,0 +1,16 @@ +import { useLocation, useNavigate } from 'react-router-dom' + +export const useForceNavigate = () => { + const locationRouter = useLocation() + const navigateRouter = useNavigate() + + const navigate = (route: string) => { + if (locationRouter.pathname !== route) { + navigateRouter(route) + } else { + navigateRouter(0) // https://stackoverflow.com/a/71336494/2077741 + } + } + + return navigate +} diff --git a/src/hooks/usePathScrollToView.tsx b/src/hooks/usePathScrollToView.tsx new file mode 100644 index 0000000..0c280c6 --- /dev/null +++ b/src/hooks/usePathScrollToView.tsx @@ -0,0 +1,15 @@ +import { useEffect, useRef } from 'react' +import { useLocation } from 'react-router-dom' + +export const usePathScrollToView = (pathName: string) => { + const ref = useRef(null) + const location = useLocation() + + useEffect(() => { + if (location.pathname === pathName && ref.current) { + ref.current.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' }) + } + }, [location.pathname]) + + return ref +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..50c1e14 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,11 @@ +import '@fontsource/poppins' +import 'animate.css' +import React from 'react' +import { createRoot } from 'react-dom/client' +import App from './App' +import './index.css' + +const container = document.getElementById('root') +const root = createRoot(container!) + +root.render() diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..f79a483 --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import packageJson from '../../package.json' +import Footer from '../components/footer' +import Navbar from '../components/navbar' + +const Home = () => { + return ( +
+ +
+

{packageJson.name}

+
+
+
+ ) +} + +export default Home diff --git a/src/pages/PrivacyPolicy.tsx b/src/pages/PrivacyPolicy.tsx new file mode 100644 index 0000000..6d7292b --- /dev/null +++ b/src/pages/PrivacyPolicy.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import Footer from '../components/footer' +import Navbar from '../components/navbar' + +const PrivacyPolicy = () => { + return ( +
+ +
+

Privacy Policy

+
+
+ ) +} + +export default PrivacyPolicy diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..3af33e7 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,15 @@ +module.exports = { + daisyui: { + themes: [ + { + light: { + 'primary-content': 'white', + primary: 'white', + secondary: '#AB883F' + } + } + ] + }, + content: ['./src/**/*.{js,ts,jsx,tsx}'], + plugins: [require('@tailwindcss/typography'), require('daisyui')] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100755 index 0000000..29db687 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": [ + "ESNext", + "dom", + "dom.iterable", + "WebWorker" + ], + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "module": "ESNext", + "strict": false, + "strictNullChecks": true, + "strictBindCallApply": true, + "noImplicitAny": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "moduleResolution": "node", + "sourceMap": true, + "jsx": "react", + "isolatedModules": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "emitDecoratorMetadata": true, + "declaration": true, + "outDir": "./lib", + "types": [ + "vite/client" + ] + }, + "exclude": [ + "**/node_modules/**", + ], + "include": [ + "../../__global.d.ts", + "./**/*.ts", + "./**/*.tsx" + ] +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..6b9c95d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,8 @@ +import { viteCommonjs } from '@originjs/vite-plugin-commonjs' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [viteCommonjs()], + base: '/' +})