Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
yoshikouki authored Aug 30, 2024
0 parents commit b0a906c
Showing 45 changed files with 2,844 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "github-actions"
# Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.)
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'daily'
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Continuous Integration

on:
pull_request:
push:
branches:
- main

jobs:
ci-web:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install bun
uses: oven-sh/setup-bun@v2

- name: Install dependencies
run: bun install

- name: Run Lint and Format
run: bun lint

- name: Run tests
run: bun test

- name: Run build
run: bun run build
28 changes: 28 additions & 0 deletions .github/workflows/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: 'Dependabot: Update bun.lockb'

on:
pull_request:
paths:
- "package.json"

permissions:
contents: write

jobs:
update-bun-lockb:
name: "Update bun.lockb"
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- uses: oven-sh/setup-bun@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
- run: |
bun install
git add bun.lockb
git config --global user.name 'dependabot[bot]'
git config --global user.email 'dependabot[bot]@users.noreply.github.com'
git commit --amend --no-edit
git push --force
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["biomejs.biome"]
}
15 changes: 15 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"workbench.editor.customLabels.patterns": {
"**/{index,page,actions,hooks,components,utils,types,functions}.{js,ts,jsx,tsx,mjs,mts}": "${dirname}/${filename}"
},
"cSpell.words": []
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# honon

Template for Next.js + Hono

## Getting Started

First, run the development server:

```bash
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
87 changes: 87 additions & 0 deletions bin/generate-logo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// biome-ignore lint/style/useNodejsImportProtocol: <explanation>
import { parseArgs } from "util";
import { renderLogoSVG } from "@/app/logo.svg/logo";
import sharp from "sharp";

const DEFAULT_CONFIG = {
DEFAULT_INPUT: "./public/logo.webp",
DEFAULT_OUTPUT: "./public/logo.webp",
DEFAULT_QUALITY: 80,
};

const parseArguments = () => {
const {
values: { input, output, quality, ...optionalArguments },
} = parseArgs({
args: Bun.argv,
options: {
input: {
type: "string",
short: "i",
default: DEFAULT_CONFIG.DEFAULT_INPUT,
},
output: {
type: "string",
short: "o",
default: DEFAULT_CONFIG.DEFAULT_OUTPUT,
},
quality: {
type: "string",
short: "q",
default: DEFAULT_CONFIG.DEFAULT_QUALITY.toString(),
},
debug: {
type: "boolean",
default: false,
},
},
strict: true,
allowPositionals: true,
});
if (!(input && output && quality)) {
throw new Error("No logo path provided.");
}
return {
input,
output,
quality: Number.parseInt(quality, 10),
...optionalArguments,
};
};

const confirmOverwrite = async (filePath: string): Promise<boolean> => {
console.log(`🆙 File already exists: ${filePath}`, 33); // Yellow
process.stdout.write("Are you sure you want to overwrite? (y/n): ");
for await (const line of console) {
if (line.toLowerCase().trim() === "y") {
return true;
}
return false;
}
return false;
};

const convertToWebP = async (string: string, quality: number) => {
const { data: buffer, info } = await sharp(Buffer.from(string))
.webp({ quality })
.toBuffer({ resolveWithObject: true });
return { buffer, info };
};

const main = async () => {
const { output: outputPath, quality } = parseArguments();

const svgString = await renderLogoSVG();
const file = Bun.file(outputPath, { type: "text/xml" });
if ((await file.exists()) && !(await confirmOverwrite(outputPath))) {
console.log("Logo file not written.");
return;
}

const { buffer, info } = await convertToWebP(svgString, quality);
Bun.write(file, buffer);
console.log(`✅ Logo file written to ${outputPath}.`);
console.log(info);
};

main();
39 changes: 39 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"indentStyle": "space",
"ignore": []
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"nursery": { "useSortedClasses": "warn" },
"correctness": {
"noUnusedImports": "warn",
"noUnusedVariables": "warn"
}
}
},
"css": {
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true
},
"parser": {
"cssModules": true
}
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
}
}
Binary file added bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[test]
17 changes: 17 additions & 0 deletions 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/app/globals.css",
"baseColor": "stone",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
9 changes: 9 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
reactCompiler: true,
ppr: true,
},
};

export default nextConfig;
41 changes: 41 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "honon",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "bun --bun x next dev --turbo",
"build": "bun --bun x next build",
"start": "bun --bun x next start",
"lint": "bunx @biomejs/biome check .",
"format": "bunx @biomejs/biome check --write .",
"format:unsafe": "bunx @biomejs/biome check --write --unsafe .",
"update:all": "bun update --latest"
},
"dependencies": {
"@radix-ui/react-slot": "^1.1.0",
"babel-plugin-react-compiler": "^0.0.0-experimental-e68eda9-20240829",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"hono": "^4.5.9",
"lucide-react": "^0.436.0",
"next": "^15.0.0-rc.0",
"next-auth": "^5.0.0-beta.20",
"next-themes": "^0.3.0",
"react": "^19.0.0-rc-a19a8ab4-20240829",
"react-dom": "^19.0.0-rc-a19a8ab4-20240829",
"satori": "^0.10.14",
"swr": "^2.2.5",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@biomejs/biome": "1.8.3",
"@types/bun": "^1.1.8",
"@types/node": "^22.5.1",
"@types/react": "npm:types-react@^19.0.0-alpha.3",
"@types/react-dom": "npm:types-react-dom@^19.0.0-alpha.3",
"postcss": "^8.4.41",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.4"
}
}
8 changes: 8 additions & 0 deletions postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};

export default config;
Binary file added public/fonts/Inter-Black.ttf
Binary file not shown.
Binary file added public/icon-192x192.webp
Binary file not shown.
Binary file added public/icon-512x512.webp
Binary file not shown.
Binary file added public/logo-no-padding.webp
Binary file not shown.
Binary file added public/logo.webp
Binary file not shown.
19 changes: 19 additions & 0 deletions src/app/api/[[...route]]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { app as server } from "@/server";
import { Hono } from "hono";
import { handle } from "hono/vercel";

const app = new Hono().basePath("/api");

app.route("/", server);

export const GET = handle(app);
export const POST = handle(app);
export const PUT = handle(app);
export const PATCH = handle(app);
export const DELETE = handle(app);
export const HEAD = handle(app);
export const OPTIONS = handle(app);

// Build error: Attempt to export a nullable value for "TextDecoderStream"
// ref: https://github.com/oven-sh/bun/issues/5648
// export const runtime = "edge";
22 changes: 22 additions & 0 deletions src/app/client-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use client";

import { client } from "@/server/client";
import useSWR from "swr";

export const ClientComponent = () => {
const request = client.time;
const { data, isLoading, error } = useSWR(
request.$url().pathname,
async () => {
const res = await request.$get();
return await res.json();
},
);

if (isLoading) return <div>Loading...</div>;
if (error) {
return <div className="text-2xl tabular-nums">Error</div>;
}

return <div className="text-2xl tabular-nums">C: {data?.message}</div>;
};
Binary file added src/app/favicon.ico
Binary file not shown.
20 changes: 20 additions & 0 deletions src/app/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Link from "next/link";
import { GitHubIcon } from "./github-icon";
import { XIcon } from "./x-icon";

export const Footer = () => {
return (
<footer className="mt-20 flex w-full flex-col items-center justify-center gap-4 p-4">
<div className="flex items-center gap-4 p-4">
<Link href="https://github.com/yoshikouki/honon">
<GitHubIcon className="size-6" />
</Link>
<Link href="https://x.com/yoshikouki_">
<XIcon className="size-4 stroke-primary" />
</Link>
</div>
{/* copyright */}
<div className="text-primary/50 text-sm">Copyright © 2024 yoshikouki</div>
</footer>
);
};
22 changes: 22 additions & 0 deletions src/app/github-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { cn } from "@/lib/utils";

export const GitHubIcon = ({
className,
...props
}: React.SVGProps<SVGSVGElement>) => (
// biome-ignore lint/a11y/noSvgWithoutTitle: <explanation>
<svg
width="98"
height="96"
viewBox="0 0 98 96"
xmlns="http://www.w3.org/2000/svg"
className={cn("fill-muted-foreground", className)}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
/>
</svg>
);
76 changes: 76 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;

--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;

--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;

--primary: 24 9.8% 10%;
--primary-foreground: 60 9.1% 97.8%;

--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;

--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;

--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;

--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;

--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 20 14.3% 4.1%;

--radius: 0.5rem;
}

.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;

--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;

--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;

--primary: 60 9.1% 97.8%;
--primary-foreground: 24 9.8% 10%;

--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;

--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;

--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;

--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;

--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%;
}
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
25 changes: 25 additions & 0 deletions src/app/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { url } from "@/lib/url";
import Link from "next/link";
import { ThemeToggle } from "./theme-toggle";

export const Header = () => {
return (
<header className="flex w-full flex-col items-center justify-center">
<div className="flex w-full max-w-xl items-center justify-between p-4">
<Link
href={url.root}
className="flex items-center justify-center gap-2"
>
<img
src={"/logo-no-padding.webp"}
loading="eager"
alt="service logo"
width={32}
/>
<h1 className="font-black text-6xl">yskk</h1>
</Link>
<ThemeToggle />
</div>
</header>
);
};
33 changes: 33 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import "./globals.css";

import { M_PLUS_2 } from "next/font/google";
import { Footer } from "./footer";
import { Header } from "./header";
import { ThemeProvider } from "./theme-provider";

export { metadata, viewport } from "./metadata";

const font = M_PLUS_2({ subsets: ["latin"] });

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className="dark"
// For next-theme
suppressHydrationWarning
>
<body className={font.className}>
<ThemeProvider>
<Header />
{children}
<Footer />
</ThemeProvider>
</body>
</html>
);
}
45 changes: 45 additions & 0 deletions src/app/logo.svg/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import satori from "satori";

export const renderLogoSVG = async () => {
const fontData = await fetch("http://localhost:8888/fonts/Inter-Black.ttf", {
cache: "force-cache",
}).then((res) => res.arrayBuffer());

const svgString = await satori(
<div
style={{
color: "hsl(0, 0%, 10%)",
fontWeight: 900,
width: "100%",
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderWidth: 1,
borderStyle: "solid",
borderColor: "hsl(0, 0%, 90%)",
}}
>
<div
style={{
fontSize: 300,
}}
>
HoN
</div>
</div>,
{
width: 1200,
height: 1200,
fonts: [
{
name: "Roboto",
data: fontData,
weight: 900,
style: "normal",
},
],
},
);
return svgString;
};
11 changes: 11 additions & 0 deletions src/app/logo.svg/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { renderLogoSVG } from "./logo";

export async function GET() {
const svgString = await renderLogoSVG();

return new Response(svgString, {
headers: {
"Content-Type": "image/webp",
},
});
}
36 changes: 36 additions & 0 deletions src/app/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { MetadataRoute } from "next";
import { description } from "./metadata";

export default function manifest(): MetadataRoute.Manifest {
return {
name: "honon",
short_name: "honon",
description,
start_url: "/",
display: "standalone",
background_color: "#000000",
theme_color: "#000000",
icons: [
{
src: "/favicon",
sizes: "256x256",
type: "image/png",
},
{
src: "/logo.webp",
sizes: "600x600",
type: "image/webp",
},
{
src: "/icon-192x192.webp",
sizes: "192x192",
type: "image/webp",
},
{
src: "/icon-512x512.webp",
sizes: "512x512",
type: "image/webp",
},
],
};
}
67 changes: 67 additions & 0 deletions src/app/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { Metadata, Viewport } from "next";

export const title = "yskk - Awesome App";
export const description = "yskk is an awesome app!";

export const metadata: Metadata = {
metadataBase: new URL("https://honon.vercel.app/"),
title,
description,
keywords: [],
authors: { name: "yoshikouki", url: "https://yoshikouki.com/" },
icons: [
{
url: "/logo.webp",
sizes: "1200x1200",
type: "image/webp",
color: "#000000",
fetchPriority: "high",
},
{
url: "/icon-192x192.webp",
sizes: "192x192",
type: "image/webp",
color: "#000000",
fetchPriority: "auto",
},
{
url: "/icon-512x512.webp",
sizes: "512x512",
type: "image/webp",
color: "#000000",
fetchPriority: "auto",
},
],
robots: "index, follow",
openGraph: {
url: "/",
title,
description,
images: [
{
url: "/favicon",
alt: title,
width: 256,
height: 256,
},
{
url: "/logo.webp",
alt: title,
width: 1200,
height: 1200,
},
],
},
twitter: {
card: "summary",
site: "@yoshikouki_",
creator: "@yoshikouki_",
title,
description,
images: "/logo.webp",
},
};

export const viewport: Viewport = {
themeColor: "#000000",
};
11 changes: 11 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ClientComponent } from "./client-component";
import { ServerComponent } from "./server-component";

export default async function HomePage() {
return (
<main className="flex flex-col items-center justify-center gap-10 py-40">
<ServerComponent />
<ClientComponent />
</main>
);
}
12 changes: 12 additions & 0 deletions src/app/server-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { client } from "@/server/client";

export const ServerComponent = async () => {
const res = await client.time.$get();
const { message } = await res.json();

return (
<>
<div className="text-2xl tabular-nums">S: {message}</div>
</>
);
};
17 changes: 17 additions & 0 deletions src/app/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client";

import { ThemeProvider as NextThemesProvider } from "next-themes";
import type { ThemeProviderProps } from "next-themes/dist/types";

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return (
<NextThemesProvider
attribute="class"
defaultTheme="dark"
enableSystem
{...props}
>
{children}
</NextThemesProvider>
);
}
26 changes: 26 additions & 0 deletions src/app/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use client";

import { MoonIcon, SunIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { useTheme } from "next-themes";

export function ThemeToggle() {
const { resolvedTheme, setTheme } = useTheme();

const toggleTheme = () => {
setTheme(resolvedTheme === "dark" ? "light" : "dark");
};

return (
<Button
onClick={toggleTheme}
variant="ghost"
size="icon"
className="animate-fade-in"
>
<SunIcon size={24} className={"hidden dark:block"} />
<MoonIcon size={24} className={"block dark:hidden"} />
</Button>
);
}
18 changes: 18 additions & 0 deletions src/app/x-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { cn } from "@/lib/utils";

export const XIcon = ({
className,
...props
}: React.SVGProps<SVGSVGElement>) => (
// biome-ignore lint/a11y/noSvgWithoutTitle: <explanation>
<svg
width="1200"
height="1227"
viewBox="0 0 1200 1227"
xmlns="http://www.w3.org/2000/svg"
{...props}
className={cn("fill-muted-foreground", className)}
>
<path d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" />
</svg>
);
56 changes: 56 additions & 0 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react";

import { cn } from "@/lib/utils";

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
4 changes: 4 additions & 0 deletions src/lib/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const url = {
root: "/",
time: "/api/time",
};
6 changes: 6 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
13 changes: 13 additions & 0 deletions src/server/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { hc } from "hono/client";
import type { AppType } from ".";

const apiUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:8888/api";

export const cachedClient = hc<AppType>(apiUrl);
export const client = hc<AppType>(apiUrl, {
fetch: (input: RequestInfo | URL, requestInit?: RequestInit) =>
fetch(input, {
cache: "no-cache",
...requestInit,
}),
});
11 changes: 11 additions & 0 deletions src/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Hono } from "hono";

export const app = new Hono();

const routes = app.get("/time", (c) => {
return c.json({
message: new Date().toISOString(),
});
});

export type AppType = typeof routes;
90 changes: 90 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { Config } from "tailwindcss";

const config = {
darkMode: ["class"],
content: [
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
"fade-in": {
from: {
opacity: "0",
},
to: {
opacity: "1",
},
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
"fade-in":
"fade-in 0.2s cubic-bezier(0.390, 0.575, 0.565, 1.000) both",
},
},
},
plugins: [require("tailwindcss-animate")],
} satisfies Config;

export default config;
27 changes: 27 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
},
"target": "ES2017"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
1,834 changes: 1,834 additions & 0 deletions yarn.lock

Large diffs are not rendered by default.

0 comments on commit b0a906c

Please sign in to comment.