Switch to Next.js

This commit is contained in:
Xevion
2023-02-16 04:23:29 -06:00
parent 59a34b93ca
commit 44a9c3a2c5
21 changed files with 2231 additions and 2485 deletions

14
.env.example Normal file
View File

@@ -0,0 +1,14 @@
# Since the ".env" file is gitignored, you can use the ".env.example" file to
# build a new ".env" file when you clone the repo. Keep this file up-to-date
# when you add new variables to `.env`.
# This file will be committed to version control, so make sure not to have any
# secrets in it. If you are cloning this repo, create a copy of this file named
# ".env" and populate it with your secrets.
# When adding additional environment variables, the schema in "/env/schema.mjs"
# should be updated accordingly.
# Example:
# SERVERVAR="foo"
# NEXT_PUBLIC_CLIENTVAR="bar"

23
.eslintrc.json Normal file
View File

@@ -0,0 +1,23 @@
{
"overrides": [
{
"extends": [
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"files": ["*.ts", "*.tsx"],
"parserOptions": {
"project": "tsconfig.json"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
"rules": {
"@typescript-eslint/consistent-type-imports": "warn",
"@typescript-eslint/ban-ts-comment": "warn"
}
}

48
.gitignore vendored
View File

@@ -1,24 +1,42 @@
.idea
.vscode
# build output
dist/
# generated types
.astro/
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules/
/node_modules
/.pnp
.pnp.js
# logs
# testing
/coverage
# database
/prisma/db.sqlite
/prisma/db.sqlite-journal
# next.js
/.next/
/out/
next-env.d.ts
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.pnpm-debug.log*
# environment variables
# local env files
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
.env
.env.production
.env*.local
# macOS-specific files
.DS_Store
# vercel
.vercel
# typescript
*.tsbuildinfo

View File

@@ -1,54 +1,57 @@
# Astro Starter Kit: Basics
# icons
```
npm create astro@latest -- --template basics
```
The `react-icons` demo page is great, providing a fast search and a decent view into
each of the various icon providers it includes.
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
But it could be better.
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
This project intends to
- Use Next.js for an optimized React static-site generator
- Utilize Vercel for builds & fast hosting
- Use hooks to regenerate & update React-Icons to the latest version constantly
- Use OpenAI's GPT-3 to suggest keywords
![basics](https://user-images.githubusercontent.com/4677417/186188965-73453154-fdec-4d6b-9c34-cb35c248ae5b.png)
## Builds
This project requires a complicated build flow in order to work perfectly.
- The latest React-Icons must be pulled at build time.
- The Cloudflare KV API & OpenAI APIs are contacted to acquire keyword suggestions for the various icons in the pack.
- All changes fetched from the APIs must be updated in Algolia.
## 🚀 Project Structure
## Filter by subset quickly
Inside of your Astro project, you'll see the following folders and files:
## Display Order
Currently, React Icons displays icons in a set ordered manner - each icon is filtered inside the set, and the sets render in the same order each time.
Not only does this seem inefficient and strange, but it doesn't offer any ability to order by keyword matching.
```
/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
## Icon List
The total icon list of all of these thousands of icons needs to be made available for searching at build time before we
begin a migration to build time export & Algolia.
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
## Element Flash & Animation
If possible, I'd like to animate the appearance, disappearance & shifting of the various Icons smoothly.
The major issue with React Icons currently is that searching creates a flash of content.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
## Most Popular Icons Display
Any static assets, like images, can be placed in the `public/` directory.
At build time, we can fetch the most popular used icons
## 🧞 Commands
## Icon Popularity Analytics
All commands are run from the root of the project, from a terminal:
Icon popularity can be measured by searches & interactions through the Algolia API.
- When an icon is hovered over for more than ~1.5 seconds.
- When an icon is clicked (to copy), a strong interaction is measured.
| Command | Action |
| :--------------------- | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:3000` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro --help` | Get help using the Astro CLI |
## Pages
## 👀 Want to learn more?
- `/` The index will show a list of all of the supported icon sets, the number of icons currently available, and an
icon or image display the logo of the given set. Hopefully, each of the sets has a logo of itself.
- `/[id]` Statically generated, each of the sets will have it's own page using just the identifier. They will be statically pulled from the icon manifests
and have another search bar, but it only searches just the given icon set. A button will be shown to move the search from the given
icon set to the global set.
- `/settings` Any settings I come up with will be on this page. This site is static and will
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
## Algolia Search
At build time, we'll generate a list of all the current icons and output it into a JSON file.
We'll then query

View File

@@ -1,4 +0,0 @@
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({});

24
next.config.mjs Normal file
View File

@@ -0,0 +1,24 @@
// @ts-check
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
* This is especially useful for Docker builds.
*/
!process.env.SKIP_ENV_VALIDATION && (await import("./src/env.mjs"));
/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
/**
* If you have the "experimental: { appDir: true }" setting enabled, then you
* must comment the below `i18n` config out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
export default config;

View File

@@ -1,16 +1,46 @@
{
"name": "",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^2.0.11",
"react-icons": "^4.7.1"
}
"name": "icons-nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@loadable/component": "^5.15.3",
"@react-icons/all-files": "^4.1.0",
"babel-plugin-codegen": "^4.1.5",
"babel-plugin-macros": "^3.1.0",
"fuse.js": "^6.6.2",
"next": "13.1.6",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.7.1",
"react-no-ssr": "^1.1.0",
"sass": "^1.58.1",
"usehooks-ts": "^2.9.1",
"zod": "^3.20.2"
},
"devDependencies": {
"@types/loadable__component": "^5.13.4",
"@types/node": "^18.11.18",
"@types/prettier": "^2.7.2",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"autoprefixer": "^10.4.7",
"eslint": "^8.30.0",
"eslint-config-next": "13.1.6",
"postcss": "^8.4.14",
"prettier": "^2.8.1",
"prettier-plugin-tailwindcss": "^0.2.1",
"tailwindcss": "^3.2.0",
"typescript": "^4.9.4"
},
"ct3aMetadata": {
"initVersion": "7.5.1"
}
}

6
postcss.config.cjs Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

4
prettier.config.cjs Normal file
View File

@@ -0,0 +1,4 @@
/** @type {import("prettier").Config} */
module.exports = {
plugins: [require.resolve("prettier-plugin-tailwindcss")],
};

BIN
public/favicon.ico Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,13 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
<path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
<path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
<defs>
<linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#000"/>
<stop offset="1" stop-color="#000" stop-opacity="0"/>
</linearGradient>
</defs>
<style>
@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}
</style>
</svg>

Before

Width:  |  Height:  |  Size: 873 B

View File

@@ -1,63 +0,0 @@
---
export interface Props {
title: string;
body: string;
href: string;
}
const { href, title, body } = Astro.props;
---
<li class="link-card">
<a href={href}>
<h2>
{title}
<span>&rarr;</span>
</h2>
<p>
{body}
</p>
</a>
</li>
<style>
.link-card {
list-style: none;
display: flex;
padding: 0.25rem;
background-color: white;
background-image: none;
background-size: 400%;
border-radius: 0.6rem;
background-position: 100%;
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
}
.link-card > a {
width: 100%;
text-decoration: none;
line-height: 1.4;
padding: 1rem 1.3rem;
border-radius: 0.35rem;
color: #111;
background-color: white;
opacity: 0.8;
}
h2 {
margin: 0;
font-size: 1.25rem;
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
p {
margin-top: 0.5rem;
margin-bottom: 0;
color: #444;
}
.link-card:is(:hover, :focus-within) {
background-position: 0;
background-image: var(--accent-gradient);
}
.link-card:is(:hover, :focus-within) h2 {
color: rgb(var(--accent));
}
</style>

1
src/env.d.ts vendored
View File

@@ -1 +0,0 @@
/// <reference types="astro/client" />

73
src/env.mjs Normal file
View File

@@ -0,0 +1,73 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { z } from "zod";
/**
* Specify your server-side environment variables schema here.
* This way you can ensure the app isn't built with invalid env vars.
*/
const server = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
});
/**
* Specify your client-side environment variables schema here.
* This way you can ensure the app isn't built with invalid env vars.
* To expose them to the client, prefix them with `NEXT_PUBLIC_`.
*/
const client = z.object({
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
});
/**
* You can't destruct `process.env` as a regular object in the Next.js
* edge runtimes (e.g. middlewares) or client-side so we need to destruct manually.
* @type {Record<keyof z.infer<typeof server> | keyof z.infer<typeof client>, string | undefined>}
*/
const processEnv = {
NODE_ENV: process.env.NODE_ENV,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
};
// Don't touch the part below
// --------------------------
const merged = server.merge(client);
/** @type z.infer<merged>
* @ts-ignore - can't type this properly in jsdoc */
let env = process.env;
if (!!process.env.SKIP_ENV_VALIDATION == false) {
const isServer = typeof window === "undefined";
const parsed = isServer
? merged.safeParse(processEnv) // on server we can validate all env vars
: client.safeParse(processEnv); // on client we can only validate the ones that are exposed
if (parsed.success === false) {
console.error(
"❌ Invalid environment variables:",
parsed.error.flatten().fieldErrors,
);
throw new Error("Invalid environment variables");
}
/** @type z.infer<merged>
* @ts-ignore - can't type this properly in jsdoc */
env = new Proxy(parsed.data, {
get(target, prop) {
if (typeof prop !== "string") return undefined;
// Throw a descriptive error if a server-side env var is accessed on the client
// Otherwise it would just be returning `undefined` and be annoying to debug
if (!isServer && !prop.startsWith("NEXT_PUBLIC_"))
throw new Error(
process.env.NODE_ENV === "production"
? "❌ Attempted to access a server-side environment variable on the client"
: `❌ Attempted to access server-side environment variable '${prop}' on the client`,
);
/* @ts-ignore - can't type this properly in jsdoc */
return target[prop];
},
});
}
export { env };

View File

@@ -1,35 +0,0 @@
---
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
<style is:global>
:root {
--accent: 124, 58, 237;
--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
}
html {
font-family: system-ui, sans-serif;
background-color: #F6F6F6;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
</style>

9
src/pages/_app.tsx Normal file
View File

@@ -0,0 +1,9 @@
import { type AppType } from "next/dist/shared/lib/utils";
import "../styles/globals.css";
const MyApp: AppType = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
export default MyApp;

View File

@@ -1,81 +0,0 @@
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
---
<Layout title="Welcome to Astro.">
<main>
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<p class="instructions">
To get started, open the directory <code>src/pages</code> in your project.<br />
<strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
</p>
<ul role="list" class="link-card-grid">
<Card
href="https://docs.astro.build/"
title="Documentation"
body="Learn how Astro works and explore the official API docs."
/>
<Card
href="https://astro.build/integrations/"
title="Integrations"
body="Supercharge your project with new frameworks and libraries."
/>
<Card
href="https://astro.build/themes/"
title="Themes"
body="Explore a galaxy of community-built starter themes."
/>
<Card
href="https://astro.build/chat/"
title="Community"
body="Come say hi to our amazing Discord community. ❤️"
/>
</ul>
</main>
</Layout>
<style>
main {
margin: auto;
padding: 1.5rem;
max-width: 60ch;
}
h1 {
font-size: 3rem;
font-weight: 800;
margin: 0;
}
.text-gradient {
background-image: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-size: 400%;
background-position: 0%;
}
.instructions {
line-height: 1.6;
margin: 1rem 0;
border: 1px solid rgba(var(--accent), 25%);
background-color: white;
padding: 1rem;
border-radius: 0.4rem;
}
.instructions code {
font-size: 0.875em;
font-weight: bold;
background: rgba(var(--accent), 12%);
color: rgb(var(--accent));
border-radius: 4px;
padding: 0.3em 0.45em;
}
.instructions strong {
color: rgb(var(--accent));
}
.link-card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
gap: 1rem;
padding: 0;
}
</style>

18
src/styles/globals.css Normal file
View File

@@ -0,0 +1,18 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--accent: 124, 58, 237;
--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
}
html {
font-family: system-ui, sans-serif;
background-color: #F6F6F6;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}

8
tailwind.config.cjs Normal file
View File

@@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -1,3 +1,29 @@
{
"extends": "astro/tsconfigs/strict"
}
"compilerOptions": {
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"checkJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"noUncheckedIndexedAccess": true,
"baseUrl": ".",
"paths": {
"@components/*": ["./src/components/*"],
"@pages/*": ["./src/pages/*"],
"@styles/*": ["./src/styles/*"],
"@utils/*": ["./src/utils/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs"],
"exclude": ["node_modules"]
}

4125
yarn.lock
View File

File diff suppressed because it is too large Load Diff