mirror of
https://github.com/Xevion/xevion.dev.git
synced 2026-01-31 08:26:41 -06:00
chore: migrate from Tailwind v3 to v4 and upgrade dependencies
Major changes: - Upgrade Tailwind CSS from v3 to v4 with @tailwindcss/postcss - Remove deprecated Tailwind v3 configuration and PostCSS plugins - Upgrade Zod from v3 to v4 - Update React Markdown and other dependencies to latest versions - Remove @plaiceholder, @headlessui, and other unused dependencies - Replace SCSS with standard CSS globals - Add font packages (@fontsource-variable) for better typography - Consolidate Prettier configuration to .prettierrc - Remove legacy contact page and custom Payload SCSS - Add Mantine hooks and Lucide React for improved UI components
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
+1
-6
@@ -12,12 +12,7 @@ const compat = new FlatCompat({
|
||||
const eslintConfig = [
|
||||
...compat.extends("next/core-web-vitals"),
|
||||
{
|
||||
ignores: [
|
||||
".next/**",
|
||||
"out/**",
|
||||
"build/**",
|
||||
"next-env.d.ts",
|
||||
],
|
||||
ignores: [".next/**", "out/**", "build/**", "next-env.d.ts"],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
+4
-3
@@ -1,8 +1,6 @@
|
||||
import { withPayload } from "@payloadcms/next/withPayload";
|
||||
// @ts-check
|
||||
|
||||
import withPlaiceholder from "@plaiceholder/next";
|
||||
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
|
||||
* This is especially useful for Docker builds.
|
||||
@@ -70,6 +68,9 @@ const config = {
|
||||
},
|
||||
],
|
||||
},
|
||||
turbopack: {
|
||||
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.json'],
|
||||
},
|
||||
async redirects() {
|
||||
// Source cannot end with / slash
|
||||
return [
|
||||
@@ -92,4 +93,4 @@ const config = {
|
||||
];
|
||||
},
|
||||
};
|
||||
export default withPayload(withPlaiceholder(config));
|
||||
export default withPayload(config);
|
||||
|
||||
+19
-28
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"name": "xevion.dev",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -11,55 +10,47 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "^0.27.16",
|
||||
"@headlessui/react": "^2.2.0",
|
||||
"@kodingdotninja/use-tailwind-breakpoint": "^1.0.0",
|
||||
"@fontsource-variable/inter": "^5.1.0",
|
||||
"@fontsource-variable/roboto": "^5.1.0",
|
||||
"@fontsource-variable/roboto-mono": "^5.1.0",
|
||||
"@fontsource/hanken-grotesk": "^5.1.0",
|
||||
"@mantine/hooks": "^8",
|
||||
"@next/eslint-plugin-next": "^15.1.1",
|
||||
"@octokit/core": "^6.1.2",
|
||||
"@octokit/core": "^7.0.5",
|
||||
"@payloadcms/db-postgres": "^3.61.1",
|
||||
"@payloadcms/next": "^3.61.1",
|
||||
"@payloadcms/payload-cloud": "^3.61.1",
|
||||
"@payloadcms/richtext-lexical": "^3.61.1",
|
||||
"@plaiceholder/next": "^3.0.0",
|
||||
"@tailwindcss/typography": "^0.5.8",
|
||||
"@tanstack/react-query": "^5.90",
|
||||
"@vercel/analytics": "^1.5.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cssnano": "^7.0.6",
|
||||
"cssnano": "^7.1.1",
|
||||
"graphql": "^16.11.0",
|
||||
"lucide-react": "^0.548.0",
|
||||
"next": "^15.5.6",
|
||||
"p5i": "^0.6.0",
|
||||
"payload": "^3.61.1",
|
||||
"plaiceholder": "^3.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-wrap-balancer": "^1",
|
||||
"sass": "^1.56.2",
|
||||
"sharp": "^0.34",
|
||||
"superjson": "^2.2",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"usehooks-ts": "^3.1.1",
|
||||
"zod": "^3.24.1"
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zod": "^4.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.38.0",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"eslint": "^9.17.0",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^24.9.1",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"eslint": "^9.38.0",
|
||||
"eslint-config-next": "^15.1.1",
|
||||
"postcss": "^8",
|
||||
"prettier-plugin-tailwindcss": "^0.6.9",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "6.11.3"
|
||||
"prettier": "^3.6.2",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"packageManager": "pnpm@9.15.1+sha512.1acb565e6193efbebda772702950469150cf12bcc764262e7587e71d19dc98a423dff9536e57ea44c49bdf790ff694e83c27be5faa23d67e0c033b583be4bfcf"
|
||||
}
|
||||
|
||||
Generated
+7145
-4553
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
"@tailwindcss/postcss": {},
|
||||
...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {}),
|
||||
},
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
module.exports = {
|
||||
plugins: [require.resolve("prettier-plugin-tailwindcss")],
|
||||
};
|
||||
@@ -1,128 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import AppWrapper from "@/components/AppWrapper";
|
||||
import { BsDiscord, BsGithub } from "react-icons/bs";
|
||||
import { AiFillMail } from "react-icons/ai";
|
||||
import Link from "next/link";
|
||||
import type { IconType } from "react-icons";
|
||||
import {
|
||||
useFloating,
|
||||
autoUpdate,
|
||||
offset,
|
||||
flip,
|
||||
shift,
|
||||
useHover,
|
||||
useFocus,
|
||||
useDismiss,
|
||||
useRole,
|
||||
useInteractions,
|
||||
FloatingPortal,
|
||||
} from "@floating-ui/react";
|
||||
import { useState } from "react";
|
||||
|
||||
const socials: {
|
||||
icon: IconType;
|
||||
href?: string;
|
||||
hint?: string;
|
||||
hideHint?: boolean;
|
||||
}[] = [
|
||||
{
|
||||
icon: BsGithub,
|
||||
href: "https://github.com/Xevion/",
|
||||
},
|
||||
{
|
||||
icon: AiFillMail,
|
||||
href: "mailto:xevion@xevion.dev",
|
||||
hint: "xevion@xevion.dev",
|
||||
},
|
||||
{
|
||||
icon: BsDiscord,
|
||||
hint: "Xevion#8506",
|
||||
},
|
||||
];
|
||||
|
||||
function SocialTooltip({
|
||||
icon: Icon,
|
||||
href,
|
||||
hint,
|
||||
hideHint,
|
||||
}: {
|
||||
icon: IconType;
|
||||
href?: string;
|
||||
hint?: string;
|
||||
hideHint?: boolean;
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
open: isOpen,
|
||||
onOpenChange: setIsOpen,
|
||||
placement: "top",
|
||||
whileElementsMounted: autoUpdate,
|
||||
middleware: [offset(10), flip(), shift()],
|
||||
});
|
||||
|
||||
const hover = useHover(context);
|
||||
const focus = useFocus(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const role = useRole(context, { role: "tooltip" });
|
||||
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([
|
||||
hover,
|
||||
focus,
|
||||
dismiss,
|
||||
role,
|
||||
]);
|
||||
|
||||
const inner = <Icon className="h-8 w-8" />;
|
||||
const tooltipContent = hint ?? href;
|
||||
|
||||
return (
|
||||
<>
|
||||
{href != undefined ? (
|
||||
<Link
|
||||
href={href}
|
||||
ref={refs.setReference}
|
||||
{...getReferenceProps()}
|
||||
>
|
||||
{inner}
|
||||
</Link>
|
||||
) : (
|
||||
<span
|
||||
ref={refs.setReference}
|
||||
{...getReferenceProps()}
|
||||
>
|
||||
{inner}
|
||||
</span>
|
||||
)}
|
||||
{!hideHint && isOpen && tooltipContent && (
|
||||
<FloatingPortal>
|
||||
<div
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
{...getFloatingProps()}
|
||||
className="z-50 rounded bg-zinc-900 px-3 py-2 text-sm text-zinc-100 shadow-lg"
|
||||
>
|
||||
{tooltipContent}
|
||||
</div>
|
||||
</FloatingPortal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ContactPage() {
|
||||
return (
|
||||
<AppWrapper>
|
||||
<div className="my-10 flex w-full flex-col items-center">
|
||||
<div className="mx-3 flex w-full max-w-[23rem] flex-col rounded-md border border-zinc-800 bg-zinc-800/50 p-5 sm:max-w-[25rem] lg:max-w-[30rem]">
|
||||
<div className="flex justify-center gap-x-5 text-center">
|
||||
{socials.map((social, index) => (
|
||||
<SocialTooltip key={index} {...social} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
import React from "react";
|
||||
import "@/styles/globals.scss";
|
||||
|
||||
// Fontsource imports
|
||||
import "@fontsource-variable/inter";
|
||||
import "@fontsource-variable/roboto";
|
||||
import "@fontsource-variable/roboto-mono";
|
||||
import "@fontsource/hanken-grotesk/900.css";
|
||||
|
||||
import "@/styles/globals.css";
|
||||
import type { Metadata } from "next";
|
||||
import { Providers } from "./providers";
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ export default async function ProjectsPage() {
|
||||
// Group links by project ID
|
||||
const linksByProject = new Map<number, PayloadLink[]>();
|
||||
for (const link of allLinks) {
|
||||
const projectId = typeof link.project === "number" ? link.project : link.project.id;
|
||||
const projectId =
|
||||
typeof link.project === "number" ? link.project : link.project.id;
|
||||
if (!linksByProject.has(projectId)) {
|
||||
linksByProject.set(projectId, []);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { handleServerFunctions, RootLayout } from "@payloadcms/next/layouts";
|
||||
import React from "react";
|
||||
|
||||
import { importMap } from "./admin/importMap.js";
|
||||
import "./custom.scss";
|
||||
|
||||
type Args = {
|
||||
children: React.ReactNode;
|
||||
|
||||
@@ -224,9 +224,7 @@ export async function GET(req: Request) {
|
||||
const urls = allLinks
|
||||
.filter((link) => {
|
||||
const projectId =
|
||||
typeof link.project === "number"
|
||||
? link.project
|
||||
: link.project.id;
|
||||
typeof link.project === "number" ? link.project : link.project.id;
|
||||
return projectId === project.id;
|
||||
})
|
||||
.map((link) => link.url)
|
||||
|
||||
@@ -41,7 +41,11 @@ const Dots = ({ className }: DotsProps) => {
|
||||
|
||||
function addPoints() {
|
||||
for (let x = -SPACING / 2; x < w.current + SPACING; x += SPACING) {
|
||||
for (let y = -SPACING / 2; y < h.current + offsetY + SPACING; y += SPACING) {
|
||||
for (
|
||||
let y = -SPACING / 2;
|
||||
y < h.current + offsetY + SPACING;
|
||||
y += SPACING
|
||||
) {
|
||||
const id = `${x}-${y}`;
|
||||
if (pointIds.has(id)) continue;
|
||||
pointIds.add(id);
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
import React, { useRef } from "react";
|
||||
import { useOnClickOutside, useToggle } from "usehooks-ts";
|
||||
import { cn, isHoverable } from "@/utils/helpers";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import Balancer from "react-wrap-balancer";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { type LinkIcon, LinkIcons } from "@/utils/types";
|
||||
import DependentImage from "@/components/DependentImage";
|
||||
|
||||
type ItemCardProps = {
|
||||
banner: string;
|
||||
bannerSettings?: { quality: number };
|
||||
title: string;
|
||||
description: string;
|
||||
links?: LinkIcon[];
|
||||
location: string;
|
||||
};
|
||||
|
||||
const ItemCard = ({
|
||||
banner,
|
||||
title,
|
||||
description,
|
||||
links,
|
||||
location,
|
||||
bannerSettings,
|
||||
}: ItemCardProps) => {
|
||||
const itemRef = useRef<HTMLDivElement>(null);
|
||||
const mobileButtonRef = useRef<HTMLAnchorElement>(null);
|
||||
const [active, toggleActive, setActive] = useToggle();
|
||||
const router = useRouter();
|
||||
|
||||
// @ts-expect-error Some kind of regression in usehooks-ts causes the useOnClickOutside hook to not accept 'null' types
|
||||
useOnClickOutside(itemRef, (event) => {
|
||||
if (
|
||||
mobileButtonRef.current != null &&
|
||||
mobileButtonRef.current?.contains(event.target as Node)
|
||||
)
|
||||
return;
|
||||
else setActive(false);
|
||||
});
|
||||
|
||||
const navigate = () => {
|
||||
if (!isHoverable()) toggleActive();
|
||||
else {
|
||||
router.push(location);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={itemRef}
|
||||
className={cn(
|
||||
"item [&:not(:first-child)]:mt-3",
|
||||
active ? "active" : null,
|
||||
)}
|
||||
onClick={navigate}
|
||||
>
|
||||
<DependentImage
|
||||
fill
|
||||
src={banner}
|
||||
quality={bannerSettings?.quality ?? 75}
|
||||
className={(loaded) => cn("object-cover", loaded ? null : "blur-xl")}
|
||||
alt={`Banner for ${title}`}
|
||||
/>
|
||||
<div className="elements m-2 grid h-full grid-cols-12 px-1 sm:px-4">
|
||||
<div className="col-span-12 max-h-full overflow-hidden pb-2 pl-2 drop-shadow-2xl sm:col-span-9 md:p-1 lg:col-span-8">
|
||||
<Link
|
||||
href={{ pathname: location }}
|
||||
className="font-roboto text-lg font-semibold sm:text-2xl md:text-3xl"
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
<div
|
||||
className="description mt-0 overflow-hidden text-base font-light sm:text-xl md:mt-1.5 md:text-xl"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
navigate();
|
||||
}}
|
||||
>
|
||||
<Balancer>
|
||||
<ReactMarkdown>{description}</ReactMarkdown>
|
||||
</Balancer>
|
||||
</div>
|
||||
</div>
|
||||
{(links?.length ?? 0) > 0 ? (
|
||||
<div className="col-span-3 hidden max-h-full w-full justify-end sm:flex md:py-5 lg:col-span-4">
|
||||
<div className="icon-grid grid aspect-square grid-cols-2 grid-rows-2 p-2 md:gap-3">
|
||||
{links!.map(({ icon, location, newTab }) => (
|
||||
<Link
|
||||
key={location}
|
||||
href={location}
|
||||
target={(newTab ?? true) ? "_blank" : "_self"}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{LinkIcons[icon]?.({})}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
aria-disabled={!active}
|
||||
ref={mobileButtonRef}
|
||||
href={active ? { pathname: location } : {}}
|
||||
className={cn(
|
||||
"flex w-full items-center justify-center rounded border border-zinc-900 bg-zinc-800 shadow transition-all",
|
||||
active ? "h-9 p-2 opacity-100" : "h-0 p-0 opacity-0",
|
||||
)}
|
||||
>
|
||||
Learn More
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemCard;
|
||||
@@ -0,0 +1,617 @@
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
* and re-run `payload generate:db-schema` to regenerate this file.
|
||||
*/
|
||||
|
||||
import type {} from "@payloadcms/db-postgres";
|
||||
import {
|
||||
pgTable,
|
||||
index,
|
||||
uniqueIndex,
|
||||
foreignKey,
|
||||
integer,
|
||||
varchar,
|
||||
timestamp,
|
||||
serial,
|
||||
numeric,
|
||||
boolean,
|
||||
jsonb,
|
||||
pgEnum,
|
||||
} from "@payloadcms/db-postgres/drizzle/pg-core";
|
||||
import { sql, relations } from "@payloadcms/db-postgres/drizzle";
|
||||
export const enum_projects_status = pgEnum("enum_projects_status", [
|
||||
"draft",
|
||||
"published",
|
||||
"archived",
|
||||
]);
|
||||
|
||||
export const users_sessions = pgTable(
|
||||
"users_sessions",
|
||||
{
|
||||
_order: integer("_order").notNull(),
|
||||
_parentID: integer("_parent_id").notNull(),
|
||||
id: varchar("id").primaryKey(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
expiresAt: timestamp("expires_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}).notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("users_sessions_order_idx").on(columns._order),
|
||||
index("users_sessions_parent_id_idx").on(columns._parentID),
|
||||
foreignKey({
|
||||
columns: [columns["_parentID"]],
|
||||
foreignColumns: [users.id],
|
||||
name: "users_sessions_parent_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
],
|
||||
);
|
||||
|
||||
export const users = pgTable(
|
||||
"users",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
email: varchar("email").notNull(),
|
||||
resetPasswordToken: varchar("reset_password_token"),
|
||||
resetPasswordExpiration: timestamp("reset_password_expiration", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
salt: varchar("salt"),
|
||||
hash: varchar("hash"),
|
||||
loginAttempts: numeric("login_attempts", { mode: "number" }).default(0),
|
||||
lockUntil: timestamp("lock_until", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
},
|
||||
(columns) => [
|
||||
index("users_updated_at_idx").on(columns.updatedAt),
|
||||
index("users_created_at_idx").on(columns.createdAt),
|
||||
uniqueIndex("users_email_idx").on(columns.email),
|
||||
],
|
||||
);
|
||||
|
||||
export const media = pgTable(
|
||||
"media",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
alt: varchar("alt").notNull(),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
url: varchar("url"),
|
||||
thumbnailURL: varchar("thumbnail_u_r_l"),
|
||||
filename: varchar("filename"),
|
||||
mimeType: varchar("mime_type"),
|
||||
filesize: numeric("filesize", { mode: "number" }),
|
||||
width: numeric("width", { mode: "number" }),
|
||||
height: numeric("height", { mode: "number" }),
|
||||
focalX: numeric("focal_x", { mode: "number" }),
|
||||
focalY: numeric("focal_y", { mode: "number" }),
|
||||
},
|
||||
(columns) => [
|
||||
index("media_updated_at_idx").on(columns.updatedAt),
|
||||
index("media_created_at_idx").on(columns.createdAt),
|
||||
uniqueIndex("media_filename_idx").on(columns.filename),
|
||||
],
|
||||
);
|
||||
|
||||
export const projects = pgTable(
|
||||
"projects",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
name: varchar("name").notNull(),
|
||||
description: varchar("description").notNull(),
|
||||
shortDescription: varchar("short_description").notNull(),
|
||||
icon: varchar("icon"),
|
||||
status: enum_projects_status("status").notNull().default("draft"),
|
||||
featured: boolean("featured").default(false),
|
||||
autocheckUpdated: boolean("autocheck_updated").default(false),
|
||||
lastUpdated: timestamp("last_updated", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
wakatimeOffset: numeric("wakatime_offset", { mode: "number" }),
|
||||
bannerImage: integer("banner_image_id").references(() => media.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("projects_banner_image_idx").on(columns.bannerImage),
|
||||
index("projects_updated_at_idx").on(columns.updatedAt),
|
||||
index("projects_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const projects_rels = pgTable(
|
||||
"projects_rels",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
order: integer("order"),
|
||||
parent: integer("parent_id").notNull(),
|
||||
path: varchar("path").notNull(),
|
||||
technologiesID: integer("technologies_id"),
|
||||
},
|
||||
(columns) => [
|
||||
index("projects_rels_order_idx").on(columns.order),
|
||||
index("projects_rels_parent_idx").on(columns.parent),
|
||||
index("projects_rels_path_idx").on(columns.path),
|
||||
index("projects_rels_technologies_id_idx").on(columns.technologiesID),
|
||||
foreignKey({
|
||||
columns: [columns["parent"]],
|
||||
foreignColumns: [projects.id],
|
||||
name: "projects_rels_parent_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["technologiesID"]],
|
||||
foreignColumns: [technologies.id],
|
||||
name: "projects_rels_technologies_fk",
|
||||
}).onDelete("cascade"),
|
||||
],
|
||||
);
|
||||
|
||||
export const technologies = pgTable(
|
||||
"technologies",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
name: varchar("name").notNull(),
|
||||
url: varchar("url"),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("technologies_updated_at_idx").on(columns.updatedAt),
|
||||
index("technologies_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const links = pgTable(
|
||||
"links",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
url: varchar("url").notNull(),
|
||||
icon: varchar("icon"),
|
||||
description: varchar("description"),
|
||||
project: integer("project_id")
|
||||
.notNull()
|
||||
.references(() => projects.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("links_project_idx").on(columns.project),
|
||||
index("links_updated_at_idx").on(columns.updatedAt),
|
||||
index("links_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_locked_documents = pgTable(
|
||||
"payload_locked_documents",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
globalSlug: varchar("global_slug"),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("payload_locked_documents_global_slug_idx").on(columns.globalSlug),
|
||||
index("payload_locked_documents_updated_at_idx").on(columns.updatedAt),
|
||||
index("payload_locked_documents_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_locked_documents_rels = pgTable(
|
||||
"payload_locked_documents_rels",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
order: integer("order"),
|
||||
parent: integer("parent_id").notNull(),
|
||||
path: varchar("path").notNull(),
|
||||
usersID: integer("users_id"),
|
||||
mediaID: integer("media_id"),
|
||||
projectsID: integer("projects_id"),
|
||||
technologiesID: integer("technologies_id"),
|
||||
linksID: integer("links_id"),
|
||||
},
|
||||
(columns) => [
|
||||
index("payload_locked_documents_rels_order_idx").on(columns.order),
|
||||
index("payload_locked_documents_rels_parent_idx").on(columns.parent),
|
||||
index("payload_locked_documents_rels_path_idx").on(columns.path),
|
||||
index("payload_locked_documents_rels_users_id_idx").on(columns.usersID),
|
||||
index("payload_locked_documents_rels_media_id_idx").on(columns.mediaID),
|
||||
index("payload_locked_documents_rels_projects_id_idx").on(
|
||||
columns.projectsID,
|
||||
),
|
||||
index("payload_locked_documents_rels_technologies_id_idx").on(
|
||||
columns.technologiesID,
|
||||
),
|
||||
index("payload_locked_documents_rels_links_id_idx").on(columns.linksID),
|
||||
foreignKey({
|
||||
columns: [columns["parent"]],
|
||||
foreignColumns: [payload_locked_documents.id],
|
||||
name: "payload_locked_documents_rels_parent_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["usersID"]],
|
||||
foreignColumns: [users.id],
|
||||
name: "payload_locked_documents_rels_users_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["mediaID"]],
|
||||
foreignColumns: [media.id],
|
||||
name: "payload_locked_documents_rels_media_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["projectsID"]],
|
||||
foreignColumns: [projects.id],
|
||||
name: "payload_locked_documents_rels_projects_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["technologiesID"]],
|
||||
foreignColumns: [technologies.id],
|
||||
name: "payload_locked_documents_rels_technologies_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["linksID"]],
|
||||
foreignColumns: [links.id],
|
||||
name: "payload_locked_documents_rels_links_fk",
|
||||
}).onDelete("cascade"),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_preferences = pgTable(
|
||||
"payload_preferences",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
key: varchar("key"),
|
||||
value: jsonb("value"),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("payload_preferences_key_idx").on(columns.key),
|
||||
index("payload_preferences_updated_at_idx").on(columns.updatedAt),
|
||||
index("payload_preferences_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_preferences_rels = pgTable(
|
||||
"payload_preferences_rels",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
order: integer("order"),
|
||||
parent: integer("parent_id").notNull(),
|
||||
path: varchar("path").notNull(),
|
||||
usersID: integer("users_id"),
|
||||
},
|
||||
(columns) => [
|
||||
index("payload_preferences_rels_order_idx").on(columns.order),
|
||||
index("payload_preferences_rels_parent_idx").on(columns.parent),
|
||||
index("payload_preferences_rels_path_idx").on(columns.path),
|
||||
index("payload_preferences_rels_users_id_idx").on(columns.usersID),
|
||||
foreignKey({
|
||||
columns: [columns["parent"]],
|
||||
foreignColumns: [payload_preferences.id],
|
||||
name: "payload_preferences_rels_parent_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["usersID"]],
|
||||
foreignColumns: [users.id],
|
||||
name: "payload_preferences_rels_users_fk",
|
||||
}).onDelete("cascade"),
|
||||
],
|
||||
);
|
||||
|
||||
export const payload_migrations = pgTable(
|
||||
"payload_migrations",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
name: varchar("name"),
|
||||
batch: numeric("batch", { mode: "number" }),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
})
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("payload_migrations_updated_at_idx").on(columns.updatedAt),
|
||||
index("payload_migrations_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const metadata = pgTable(
|
||||
"metadata",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
tagline: varchar("tagline").notNull(),
|
||||
resume: integer("resume_id")
|
||||
.notNull()
|
||||
.references(() => media.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
resumeFilename: varchar("resume_filename"),
|
||||
updatedAt: timestamp("updated_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
createdAt: timestamp("created_at", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}),
|
||||
},
|
||||
(columns) => [index("metadata_resume_idx").on(columns.resume)],
|
||||
);
|
||||
|
||||
export const relations_users_sessions = relations(
|
||||
users_sessions,
|
||||
({ one }) => ({
|
||||
_parentID: one(users, {
|
||||
fields: [users_sessions._parentID],
|
||||
references: [users.id],
|
||||
relationName: "sessions",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_users = relations(users, ({ many }) => ({
|
||||
sessions: many(users_sessions, {
|
||||
relationName: "sessions",
|
||||
}),
|
||||
}));
|
||||
export const relations_media = relations(media, () => ({}));
|
||||
export const relations_projects_rels = relations(projects_rels, ({ one }) => ({
|
||||
parent: one(projects, {
|
||||
fields: [projects_rels.parent],
|
||||
references: [projects.id],
|
||||
relationName: "_rels",
|
||||
}),
|
||||
technologiesID: one(technologies, {
|
||||
fields: [projects_rels.technologiesID],
|
||||
references: [technologies.id],
|
||||
relationName: "technologies",
|
||||
}),
|
||||
}));
|
||||
export const relations_projects = relations(projects, ({ one, many }) => ({
|
||||
bannerImage: one(media, {
|
||||
fields: [projects.bannerImage],
|
||||
references: [media.id],
|
||||
relationName: "bannerImage",
|
||||
}),
|
||||
_rels: many(projects_rels, {
|
||||
relationName: "_rels",
|
||||
}),
|
||||
}));
|
||||
export const relations_technologies = relations(technologies, () => ({}));
|
||||
export const relations_links = relations(links, ({ one }) => ({
|
||||
project: one(projects, {
|
||||
fields: [links.project],
|
||||
references: [projects.id],
|
||||
relationName: "project",
|
||||
}),
|
||||
}));
|
||||
export const relations_payload_locked_documents_rels = relations(
|
||||
payload_locked_documents_rels,
|
||||
({ one }) => ({
|
||||
parent: one(payload_locked_documents, {
|
||||
fields: [payload_locked_documents_rels.parent],
|
||||
references: [payload_locked_documents.id],
|
||||
relationName: "_rels",
|
||||
}),
|
||||
usersID: one(users, {
|
||||
fields: [payload_locked_documents_rels.usersID],
|
||||
references: [users.id],
|
||||
relationName: "users",
|
||||
}),
|
||||
mediaID: one(media, {
|
||||
fields: [payload_locked_documents_rels.mediaID],
|
||||
references: [media.id],
|
||||
relationName: "media",
|
||||
}),
|
||||
projectsID: one(projects, {
|
||||
fields: [payload_locked_documents_rels.projectsID],
|
||||
references: [projects.id],
|
||||
relationName: "projects",
|
||||
}),
|
||||
technologiesID: one(technologies, {
|
||||
fields: [payload_locked_documents_rels.technologiesID],
|
||||
references: [technologies.id],
|
||||
relationName: "technologies",
|
||||
}),
|
||||
linksID: one(links, {
|
||||
fields: [payload_locked_documents_rels.linksID],
|
||||
references: [links.id],
|
||||
relationName: "links",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_locked_documents = relations(
|
||||
payload_locked_documents,
|
||||
({ many }) => ({
|
||||
_rels: many(payload_locked_documents_rels, {
|
||||
relationName: "_rels",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_preferences_rels = relations(
|
||||
payload_preferences_rels,
|
||||
({ one }) => ({
|
||||
parent: one(payload_preferences, {
|
||||
fields: [payload_preferences_rels.parent],
|
||||
references: [payload_preferences.id],
|
||||
relationName: "_rels",
|
||||
}),
|
||||
usersID: one(users, {
|
||||
fields: [payload_preferences_rels.usersID],
|
||||
references: [users.id],
|
||||
relationName: "users",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_preferences = relations(
|
||||
payload_preferences,
|
||||
({ many }) => ({
|
||||
_rels: many(payload_preferences_rels, {
|
||||
relationName: "_rels",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
export const relations_payload_migrations = relations(
|
||||
payload_migrations,
|
||||
() => ({}),
|
||||
);
|
||||
export const relations_metadata = relations(metadata, ({ one }) => ({
|
||||
resume: one(media, {
|
||||
fields: [metadata.resume],
|
||||
references: [media.id],
|
||||
relationName: "resume",
|
||||
}),
|
||||
}));
|
||||
|
||||
type DatabaseSchema = {
|
||||
enum_projects_status: typeof enum_projects_status;
|
||||
users_sessions: typeof users_sessions;
|
||||
users: typeof users;
|
||||
media: typeof media;
|
||||
projects: typeof projects;
|
||||
projects_rels: typeof projects_rels;
|
||||
technologies: typeof technologies;
|
||||
links: typeof links;
|
||||
payload_locked_documents: typeof payload_locked_documents;
|
||||
payload_locked_documents_rels: typeof payload_locked_documents_rels;
|
||||
payload_preferences: typeof payload_preferences;
|
||||
payload_preferences_rels: typeof payload_preferences_rels;
|
||||
payload_migrations: typeof payload_migrations;
|
||||
metadata: typeof metadata;
|
||||
relations_users_sessions: typeof relations_users_sessions;
|
||||
relations_users: typeof relations_users;
|
||||
relations_media: typeof relations_media;
|
||||
relations_projects_rels: typeof relations_projects_rels;
|
||||
relations_projects: typeof relations_projects;
|
||||
relations_technologies: typeof relations_technologies;
|
||||
relations_links: typeof relations_links;
|
||||
relations_payload_locked_documents_rels: typeof relations_payload_locked_documents_rels;
|
||||
relations_payload_locked_documents: typeof relations_payload_locked_documents;
|
||||
relations_payload_preferences_rels: typeof relations_payload_preferences_rels;
|
||||
relations_payload_preferences: typeof relations_payload_preferences;
|
||||
relations_payload_migrations: typeof relations_payload_migrations;
|
||||
relations_metadata: typeof relations_metadata;
|
||||
};
|
||||
|
||||
declare module "@payloadcms/db-postgres" {
|
||||
export interface GeneratedDatabaseSchema {
|
||||
schema: DatabaseSchema;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* tslint:disable */
|
||||
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
/* Custom colors */
|
||||
--color-zinc-850: #1d1d20;
|
||||
|
||||
/* Custom font sizes */
|
||||
--font-size-10xl: 10rem;
|
||||
|
||||
/* Drop shadows */
|
||||
--drop-shadow-extreme: 0 0 50px black;
|
||||
|
||||
/* Font families */
|
||||
--font-inter: "Inter", sans-serif;
|
||||
--font-roboto: "Roboto", sans-serif;
|
||||
--font-mono: "Roboto Mono", monospace;
|
||||
--font-hanken: "Hanken Grotesk", sans-serif;
|
||||
|
||||
/* Background images */
|
||||
--background-image-gradient-radial: radial-gradient(
|
||||
50% 50% at 50% 50%,
|
||||
var(--tw-gradient-stops)
|
||||
);
|
||||
|
||||
/* Animations */
|
||||
--animate-bg-fast: fade 0.5s ease-in-out 0.5s forwards;
|
||||
--animate-bg: fade 1.2s ease-in-out 1.1s forwards;
|
||||
--animate-fade-in: fade-in 2.5s ease-in-out forwards;
|
||||
--animate-title: title 3s ease-out forwards;
|
||||
--animate-fade-left: fade-left 3s ease-in-out forwards;
|
||||
--animate-fade-right: fade-right 3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
0% {
|
||||
opacity: 0%;
|
||||
}
|
||||
100% {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0%;
|
||||
}
|
||||
75% {
|
||||
opacity: 0%;
|
||||
}
|
||||
100% {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-left {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
opacity: 0%;
|
||||
}
|
||||
30% {
|
||||
transform: translateX(0%);
|
||||
opacity: 100%;
|
||||
}
|
||||
100% {
|
||||
opacity: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-right {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0%;
|
||||
}
|
||||
30% {
|
||||
transform: translateX(0%);
|
||||
opacity: 100%;
|
||||
}
|
||||
100% {
|
||||
opacity: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes title {
|
||||
0% {
|
||||
line-height: 0%;
|
||||
letter-spacing: 0.25em;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
line-height: 0%;
|
||||
opacity: 0%;
|
||||
}
|
||||
80% {
|
||||
opacity: 100%;
|
||||
}
|
||||
100% {
|
||||
line-height: 100%;
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply font-inter overflow-x-hidden text-white;
|
||||
}
|
||||
|
||||
.description {
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.description {
|
||||
hyphens: none;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
@apply h-full;
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@900&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@200;300;400;500;700;900&display=swap");
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
// Used for ItemCard
|
||||
@mixin active {
|
||||
.elements {
|
||||
@apply grid opacity-100;
|
||||
}
|
||||
|
||||
> img {
|
||||
@apply blur-2xl;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
@apply overflow-x-hidden font-inter text-white;
|
||||
}
|
||||
|
||||
.item {
|
||||
@apply pointer-events-auto relative aspect-[7/2] w-full cursor-pointer overflow-hidden rounded transition-all sm:h-[14rem] md:h-[16rem] lg:aspect-[5/3];
|
||||
> img {
|
||||
@apply rounded transition-all;
|
||||
}
|
||||
|
||||
.elements {
|
||||
@apply hidden opacity-0 transition-all delay-100;
|
||||
> * {
|
||||
// z-index: 30;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
@include active;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
@include active;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-grid {
|
||||
direction: rtl;
|
||||
@apply max-h-full min-h-0 min-w-0 max-w-full;
|
||||
|
||||
> a > svg {
|
||||
@apply h-full w-full;
|
||||
}
|
||||
|
||||
> svg,
|
||||
a {
|
||||
width: 75%;
|
||||
height: 75%;
|
||||
@apply m-auto aspect-square text-white opacity-80 drop-shadow-md transition-transform hover:scale-[120%] hover:opacity-100;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
hyphens: auto;
|
||||
@screen md {
|
||||
hyphens: none;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
@apply h-full;
|
||||
}
|
||||
@@ -1,7 +1,3 @@
|
||||
import create from "@kodingdotninja/use-tailwind-breakpoint";
|
||||
import resolveConfig from "tailwindcss/resolveConfig";
|
||||
import tailwindConfig from "@/../tailwind.config.cjs";
|
||||
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
@@ -24,7 +20,3 @@ const hoverableQuery: MediaQueryList | null = isClient()
|
||||
export function isHoverable() {
|
||||
return hoverableQuery?.matches;
|
||||
}
|
||||
|
||||
const config = resolveConfig(tailwindConfig);
|
||||
export const { useBreakpoint, useBreakpointValue, useBreakpointEffect } =
|
||||
create(config.theme!.screens);
|
||||
|
||||
+6
-7
@@ -1,6 +1,5 @@
|
||||
import type { IconType } from "react-icons";
|
||||
import { AiFillGithub, AiOutlineLink } from "react-icons/ai";
|
||||
import { RxOpenInNewWindow } from "react-icons/rx";
|
||||
import { Github, ExternalLink, Link } from "lucide-react";
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
|
||||
// Promise.allSettled type guards
|
||||
export const isFulfilled = <T>(
|
||||
@@ -10,10 +9,10 @@ export const isRejected = <T>(
|
||||
p: PromiseSettledResult<T>,
|
||||
): p is PromiseRejectedResult => p.status === "rejected";
|
||||
|
||||
export const LinkIcons: Record<string, IconType> = {
|
||||
github: AiFillGithub,
|
||||
external: RxOpenInNewWindow,
|
||||
link: AiOutlineLink,
|
||||
export const LinkIcons: Record<string, LucideIcon> = {
|
||||
github: Github,
|
||||
external: ExternalLink,
|
||||
link: Link,
|
||||
};
|
||||
export type LinkIcon = {
|
||||
icon: keyof typeof LinkIcons;
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
zinc: {
|
||||
850: "#1D1D20",
|
||||
},
|
||||
},
|
||||
fontSize: {
|
||||
"10xl": "10rem",
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
"code::before": {
|
||||
content: '""',
|
||||
},
|
||||
"code::after": {
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
},
|
||||
quoteless: {
|
||||
css: {
|
||||
"blockquote p:first-of-type::before": { content: "none" },
|
||||
"blockquote p:first-of-type::after": { content: "none" },
|
||||
},
|
||||
},
|
||||
},
|
||||
dropShadow: {
|
||||
extreme: "0 0 50px black",
|
||||
},
|
||||
fontFamily: {
|
||||
inter: ['"Inter"', "sans-serif"],
|
||||
roboto: ['"Roboto"', "sans-serif"],
|
||||
mono: ['"Roboto Mono"', "monospace"],
|
||||
hanken: ['"Hanken Grotesk"', "sans-serif"],
|
||||
},
|
||||
backgroundImage: {
|
||||
"gradient-radial":
|
||||
"radial-gradient(50% 50% at 50% 50%, var(--tw-gradient-stops))",
|
||||
},
|
||||
animation: {
|
||||
"bg-fast": "fade 0.5s ease-in-out 0.5s forwards",
|
||||
bg: "fade 1.2s ease-in-out 1.1s forwards",
|
||||
"fade-in": "fade-in 2.5s ease-in-out forwards",
|
||||
title: "title 3s ease-out forwards",
|
||||
"fade-left": "fade-left 3s ease-in-out forwards",
|
||||
"fade-right": "fade-right 3s ease-in-out forwards",
|
||||
},
|
||||
keyframes: {
|
||||
fade: {
|
||||
"0%": {
|
||||
opacity: "0%",
|
||||
},
|
||||
"100%": {
|
||||
opacity: "100%",
|
||||
},
|
||||
},
|
||||
"fade-in": {
|
||||
"0%": {
|
||||
opacity: "0%",
|
||||
},
|
||||
"75%": {
|
||||
opacity: "0%",
|
||||
},
|
||||
"100%": {
|
||||
opacity: "100%",
|
||||
},
|
||||
},
|
||||
"fade-left": {
|
||||
"0%": {
|
||||
transform: "translateX(100%)",
|
||||
opacity: "0%",
|
||||
},
|
||||
|
||||
"30%": {
|
||||
transform: "translateX(0%)",
|
||||
opacity: "100%",
|
||||
},
|
||||
"100%": {
|
||||
opacity: "0%",
|
||||
},
|
||||
},
|
||||
"fade-right": {
|
||||
"0%": {
|
||||
transform: "translateX(-100%)",
|
||||
opacity: "0%",
|
||||
},
|
||||
|
||||
"30%": {
|
||||
transform: "translateX(0%)",
|
||||
opacity: "100%",
|
||||
},
|
||||
"100%": {
|
||||
opacity: "0%",
|
||||
},
|
||||
},
|
||||
title: {
|
||||
"0%": {
|
||||
"line-height": "0%",
|
||||
"letter-spacing": "0.25em",
|
||||
opacity: "0",
|
||||
},
|
||||
"25%": {
|
||||
"line-height": "0%",
|
||||
opacity: "0%",
|
||||
},
|
||||
"80%": {
|
||||
opacity: "100%",
|
||||
},
|
||||
|
||||
"100%": {
|
||||
"line-height": "100%",
|
||||
opacity: "100%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
};
|
||||
Reference in New Issue
Block a user