mirror of
https://github.com/Xevion/xevion.dev.git
synced 2025-12-14 14:13:45 -06:00
Prettier format global
This commit is contained in:
@@ -1,19 +1,33 @@
|
||||
import {Html, Head, Main, NextScript} from 'next/document'
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
</Head>
|
||||
<body className="bg-black">
|
||||
<Main/>
|
||||
<NextScript/>
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
</Head>
|
||||
<body className="bg-black">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,56 @@
|
||||
import {type NextPage} from "next";
|
||||
import { type NextPage } from "next";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
import {BsDiscord, BsGithub} from "react-icons/bs";
|
||||
import {AiFillMail} from "react-icons/ai";
|
||||
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 type { IconType } from "react-icons";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import 'tippy.js/dist/tippy.css';
|
||||
import "tippy.js/dist/tippy.css";
|
||||
|
||||
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"
|
||||
}
|
||||
]
|
||||
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",
|
||||
},
|
||||
];
|
||||
|
||||
const ContactPage: NextPage = () => {
|
||||
return <AppWrapper current='contact'>
|
||||
<div className="w-full my-10 flex flex-col items-center">
|
||||
<div
|
||||
className="bg-zinc-800/50 border border-zinc-800 rounded-md max-w-[23rem] sm:max-w-[25rem] lg:max-w-[30rem] mx-3 w-full p-5 flex flex-col">
|
||||
<div className="flex justify-center gap-x-5 text-center">
|
||||
{socials.map(({icon: Icon, href, hint, hideHint}, index) => {
|
||||
const inner = <Icon className="w-8 h-8"/>;
|
||||
return <Tippy key={index} disabled={hideHint} content={hint ?? href}>
|
||||
{
|
||||
href != undefined ? <Link href={href}>{inner}</Link> : <span>{inner}</span>
|
||||
}
|
||||
</Tippy>
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<AppWrapper current="contact">
|
||||
<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(({ icon: Icon, href, hint, hideHint }, index) => {
|
||||
const inner = <Icon className="h-8 w-8" />;
|
||||
return (
|
||||
<Tippy key={index} disabled={hideHint} content={hint ?? href}>
|
||||
{href != undefined ? (
|
||||
<Link href={href}>{inner}</Link>
|
||||
) : (
|
||||
<span>{inner}</span>
|
||||
)}
|
||||
</Tippy>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactPage;
|
||||
export default ContactPage;
|
||||
|
||||
@@ -1,77 +1,102 @@
|
||||
import type {NextPage} from "next";
|
||||
import type { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import {BsGithub} from "react-icons/bs";
|
||||
import {RxOpenInNewWindow} from "react-icons/rx";
|
||||
import { BsGithub } from "react-icons/bs";
|
||||
import { RxOpenInNewWindow } from "react-icons/rx";
|
||||
import Link from "next/link";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
import type {ReactNode} from "react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
type Screenshot = [string, null | string | ReactNode];
|
||||
type ScreenshotWithQuality = [string, null | string | ReactNode, number];
|
||||
const images: (Screenshot | ScreenshotWithQuality)[] = [
|
||||
["/grain/index.jpg", null, 100],
|
||||
["/grain/hidden.jpg", null, 100]
|
||||
]
|
||||
["/grain/index.jpg", null, 100],
|
||||
["/grain/hidden.jpg", null, 100],
|
||||
];
|
||||
|
||||
const GrainPage: NextPage = () => {
|
||||
return <>
|
||||
<Head>
|
||||
<title>Grain | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="w-full overflow-auto h-full min-h-screen flex justify-center">
|
||||
<div className="relative my-10 p-3 px-6 w-full max-w-screen-md">
|
||||
<div className="pb-2 flex justify-between">
|
||||
<div className="text-3xl font-semibold">
|
||||
Grain
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://grain.xevion.dev" target="_blank">
|
||||
<RxOpenInNewWindow className="w-6 h-6 hover:text-zinc-200"/>
|
||||
</Link>
|
||||
<Link href="https://github.com/Xevion/grain" target="_blank">
|
||||
<BsGithub className="w-6 h-6 hover:text-zinc-200"/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Link href="https://grain.xevion.dev/">
|
||||
<Image fill quality={100} sizes="100vw" src="/grain/banner.jpeg" alt=""
|
||||
className="!relative pointer-events-none min-h-[10rem] rounded-md object-cover"/>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-3 w-full prose prose-invert prose-lg">
|
||||
<p>
|
||||
After seeing an online post with beautiful noise patterns & gradients, I decided to
|
||||
try and recreate it. The result was Grain, a simple web app that generates beautiful noise.
|
||||
Under the hood, this app uses multiple layers of SVGs that automatically rescale with the browsers viewport.
|
||||
That way, the noise is always crisp and clear, no matter the screen size.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Performant - SVG generation and layering is optimized</li>
|
||||
<li>Small - Builds in less than 16 seconds</li>
|
||||
<li>Open Source - Want to use my gradients? Check it out on <Link href="https://github.com/Xevion/grain" target="_blank">GitHub</Link>.</li>
|
||||
</ul>
|
||||
<h3>Screenshots</h3>
|
||||
<div className="relative space-y-8">
|
||||
{images.map(([src, description, quality]) => {
|
||||
return <div key={src} className="flex flex-col justify-center w-full">
|
||||
<Image fill sizes="100vw" src={src} alt="" quality={quality ?? 75}
|
||||
className="shadow-lg !my-1 !relative pointer-events-none min-h-[10rem] rounded-md object-cover"/>
|
||||
{description != null ?
|
||||
<span
|
||||
className="text-center text-base">{description}</span> : null}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Grain | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="flex h-full min-h-screen w-full justify-center overflow-auto">
|
||||
<div className="relative my-10 w-full max-w-screen-md p-3 px-6">
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="text-3xl font-semibold">Grain</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://grain.xevion.dev" target="_blank">
|
||||
<RxOpenInNewWindow className="h-6 w-6 hover:text-zinc-200" />
|
||||
</Link>
|
||||
<Link href="https://github.com/Xevion/grain" target="_blank">
|
||||
<BsGithub className="h-6 w-6 hover:text-zinc-200" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
|
||||
<div className="relative">
|
||||
<Link href="https://grain.xevion.dev/">
|
||||
<Image
|
||||
fill
|
||||
quality={100}
|
||||
sizes="100vw"
|
||||
src="/grain/banner.jpeg"
|
||||
alt=""
|
||||
className="pointer-events-none !relative min-h-[10rem] rounded-md object-cover"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="prose prose-lg prose-invert mt-3 w-full">
|
||||
<p>
|
||||
After seeing an online post with beautiful noise patterns &
|
||||
gradients, I decided to try and recreate it. The result was
|
||||
Grain, a simple web app that generates beautiful noise. Under
|
||||
the hood, this app uses multiple layers of SVGs that
|
||||
automatically rescale with the browsers viewport. That way, the
|
||||
noise is always crisp and clear, no matter the screen size.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Performant - SVG generation and layering is optimized</li>
|
||||
<li>Small - Builds in less than 16 seconds</li>
|
||||
<li>
|
||||
Open Source - Want to use my gradients? Check it out on{" "}
|
||||
<Link href="https://github.com/Xevion/grain" target="_blank">
|
||||
GitHub
|
||||
</Link>
|
||||
.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Screenshots</h3>
|
||||
<div className="relative space-y-8">
|
||||
{images.map(([src, description, quality]) => {
|
||||
return (
|
||||
<div
|
||||
key={src}
|
||||
className="flex w-full flex-col justify-center"
|
||||
>
|
||||
<Image
|
||||
fill
|
||||
sizes="100vw"
|
||||
src={src}
|
||||
alt=""
|
||||
quality={quality ?? 75}
|
||||
className="pointer-events-none !relative !my-1 min-h-[10rem] rounded-md object-cover shadow-lg"
|
||||
/>
|
||||
{description != null ? (
|
||||
<span className="text-center text-base">
|
||||
{description}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default GrainPage;
|
||||
export default GrainPage;
|
||||
|
||||
@@ -104,7 +104,7 @@ export async function getStaticProps() {
|
||||
...project,
|
||||
bannerBlur: base64,
|
||||
};
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
};
|
||||
@@ -145,7 +145,7 @@ const Home: NextPage<HomeStaticProps> = ({
|
||||
{buttons.map(({ text, href }) => (
|
||||
<Link
|
||||
key={href}
|
||||
className="text-sm text-zinc-500 duration-500 hover:text-zinc-300"
|
||||
className="text-sm text-zinc-500 duration-500 hover:text-zinc-300"
|
||||
href={href}
|
||||
>
|
||||
{text}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import {type NextPage} from "next";
|
||||
import { type NextPage } from "next";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
import WorkInProgress from "../components/WorkInProgress";
|
||||
|
||||
const PathsPage: NextPage = () => {
|
||||
return <AppWrapper>
|
||||
<WorkInProgress />
|
||||
return (
|
||||
<AppWrapper>
|
||||
<WorkInProgress />
|
||||
</AppWrapper>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default PathsPage;
|
||||
export default PathsPage;
|
||||
|
||||
@@ -1,59 +1,65 @@
|
||||
import {NextPage} from "next";
|
||||
import { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import {BsGithub} from "react-icons/bs";
|
||||
import { BsGithub } from "react-icons/bs";
|
||||
import Link from "next/link";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
|
||||
const PhototagPage: NextPage = () => {
|
||||
return <>
|
||||
<Head>
|
||||
<title>Phototag | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="w-full overflow-auto h-full min-h-screen flex justify-center">
|
||||
<div className="relative my-10 p-3 px-6 w-full max-w-screen-md">
|
||||
<div className="pb-2 flex justify-between">
|
||||
<div className="text-2xl font-semibold">
|
||||
Phototag
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://github.com/Xevion/phototag" target="_blank">
|
||||
<BsGithub className="w-5 h-5 hover:text-zinc-200"/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Image fill sizes="100vw" src="/phototag.png" alt=""
|
||||
className="!relative pointer-events-none min-h-[10rem] rounded-md object-cover"/>
|
||||
</div>
|
||||
<div className="mt-3 w-full prose prose-invert prose-lg">
|
||||
<p>
|
||||
Phototag is a powerful tool that helps you quickly and easily add rich, descriptive tags to
|
||||
your photos. Using Google's Vision API, Phototag automatically generates tags based on
|
||||
the visual content of your photos, making it easier than ever to organize and find your
|
||||
photos.
|
||||
</p>
|
||||
<p>
|
||||
With support for IPTC metadata and Adobe XMP Sidecar files, you can easily integrate
|
||||
Phototag into your existing workflow on Windows. Whether you're a professional
|
||||
photographer or a casual snapshot taker, Phototag is the perfect tool for adding clarity and
|
||||
context to your photos.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Simple, but configurable</li>
|
||||
<li>Fully automatic</li>
|
||||
<li>Leverages compression to reduce network load</li>
|
||||
<li>Supports JPEG, PNG, GIF etc.</li>
|
||||
<li>Supports IPTC metadata</li>
|
||||
<li>Supports Adobe XMP sidecar files</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Phototag | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="flex h-full min-h-screen w-full justify-center overflow-auto">
|
||||
<div className="relative my-10 w-full max-w-screen-md p-3 px-6">
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="text-2xl font-semibold">Phototag</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://github.com/Xevion/phototag" target="_blank">
|
||||
<BsGithub className="h-5 w-5 hover:text-zinc-200" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
|
||||
<div className="relative">
|
||||
<Image
|
||||
fill
|
||||
sizes="100vw"
|
||||
src="/phototag.png"
|
||||
alt=""
|
||||
className="pointer-events-none !relative min-h-[10rem] rounded-md object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="prose prose-lg prose-invert mt-3 w-full">
|
||||
<p>
|
||||
Phototag is a powerful tool that helps you quickly and easily
|
||||
add rich, descriptive tags to your photos. Using Google's
|
||||
Vision API, Phototag automatically generates tags based on the
|
||||
visual content of your photos, making it easier than ever to
|
||||
organize and find your photos.
|
||||
</p>
|
||||
<p>
|
||||
With support for IPTC metadata and Adobe XMP Sidecar files, you
|
||||
can easily integrate Phototag into your existing workflow on
|
||||
Windows. Whether you're a professional photographer or a
|
||||
casual snapshot taker, Phototag is the perfect tool for adding
|
||||
clarity and context to your photos.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Simple, but configurable</li>
|
||||
<li>Fully automatic</li>
|
||||
<li>Leverages compression to reduce network load</li>
|
||||
<li>Supports JPEG, PNG, GIF etc.</li>
|
||||
<li>Supports IPTC metadata</li>
|
||||
<li>Supports Adobe XMP sidecar files</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default PhototagPage;
|
||||
export default PhototagPage;
|
||||
|
||||
@@ -1,81 +1,114 @@
|
||||
import type {NextPage} from "next";
|
||||
import type { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import {BsGithub} from "react-icons/bs";
|
||||
import { BsGithub } from "react-icons/bs";
|
||||
import Link from "next/link";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
import type {ReactNode} from "react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
const images: [string, string | ReactNode][] = [
|
||||
["/portal/home.jpeg", "The home page."],
|
||||
["/portal/events.png", <> A page listing all current events. <br/> Initial data is cached for performance, but
|
||||
becomes
|
||||
dynamic when filtered.</>],
|
||||
["/portal/admin.png", "A secure admin panel for our officers to view, filter & edit members & events."],
|
||||
["/portal/event.png", "The view of a specific event."],
|
||||
["/portal/checkin.png", "The check-in view."],
|
||||
["/portal/filters.png", "Organization filtering options. Dynamic semester filtering & event sorting is also available."],
|
||||
["/portal/login.png", "The login. Fast form validation, seamless login."],
|
||||
["/portal/profile.png", <>The member profile view; fully editable on both desktop & mobile. <br/> Seamless editing
|
||||
of profiles for users. Full validation available.</>],
|
||||
["/portal/status.png", "Members can check their progress towards becoming full members & view what events they attended."],
|
||||
]
|
||||
["/portal/home.jpeg", "The home page."],
|
||||
[
|
||||
"/portal/events.png",
|
||||
<>
|
||||
{" "}
|
||||
A page listing all current events. <br /> Initial data is cached for
|
||||
performance, but becomes dynamic when filtered.
|
||||
</>,
|
||||
],
|
||||
[
|
||||
"/portal/admin.png",
|
||||
"A secure admin panel for our officers to view, filter & edit members & events.",
|
||||
],
|
||||
["/portal/event.png", "The view of a specific event."],
|
||||
["/portal/checkin.png", "The check-in view."],
|
||||
[
|
||||
"/portal/filters.png",
|
||||
"Organization filtering options. Dynamic semester filtering & event sorting is also available.",
|
||||
],
|
||||
["/portal/login.png", "The login. Fast form validation, seamless login."],
|
||||
[
|
||||
"/portal/profile.png",
|
||||
<>
|
||||
The member profile view; fully editable on both desktop & mobile. <br />{" "}
|
||||
Seamless editing of profiles for users. Full validation available.
|
||||
</>,
|
||||
],
|
||||
[
|
||||
"/portal/status.png",
|
||||
"Members can check their progress towards becoming full members & view what events they attended.",
|
||||
],
|
||||
];
|
||||
|
||||
const PortalPage: NextPage = () => {
|
||||
return <>
|
||||
<Head>
|
||||
<title>Portal | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="w-full overflow-auto h-full min-h-screen flex justify-center">
|
||||
<div className="relative my-10 p-3 px-6 w-full max-w-screen-md">
|
||||
<div className="pb-2 flex justify-between">
|
||||
<div className="text-3xl font-semibold">
|
||||
Portal
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://github.com/acmutsa/Portal" target="_blank">
|
||||
<BsGithub className="w-6 h-6 hover:text-zinc-200"/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Link href="https://portal.acmutsa.org/">
|
||||
<Image fill sizes="100vw" src="/portal/banner.jpeg" alt=""
|
||||
className="!relative pointer-events-none min-h-[10rem] rounded-md object-cover"/>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-3 w-full prose prose-invert prose-lg">
|
||||
<p>
|
||||
Created in service of our membership, Portal was designed as a approachable membership
|
||||
portal
|
||||
for our users so we could <b>track membership</b>, <b>advertise events</b> and replace our
|
||||
existing <b>database solution</b>.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Fast - built to serve thousands</li>
|
||||
<li>Cheap - minimize costs</li>
|
||||
<li>Open Source - help us improve</li>
|
||||
<li>Cutting Edge - the latest technology</li>
|
||||
</ul>
|
||||
<h3>Screenshots</h3>
|
||||
<div className="relative space-y-8">
|
||||
{images.map(([src, description]) => {
|
||||
return <div key={src} className="flex flex-col justify-center w-full">
|
||||
<Image fill sizes="100vw" src={src} alt=""
|
||||
className="shadow-lg !my-1 !relative pointer-events-none min-h-[10rem] rounded-md object-cover"/>
|
||||
<span
|
||||
className="text-center text-base">{description}</span>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Portal | Xevion.dev</title>
|
||||
</Head>
|
||||
<AppWrapper>
|
||||
<div className="flex h-full min-h-screen w-full justify-center overflow-auto">
|
||||
<div className="relative my-10 w-full max-w-screen-md p-3 px-6">
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="text-3xl font-semibold">Portal</div>
|
||||
<div className="flex items-center justify-end space-x-1.5">
|
||||
<Link href="https://github.com/acmutsa/Portal" target="_blank">
|
||||
<BsGithub className="h-6 w-6 hover:text-zinc-200" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
|
||||
<div className="relative">
|
||||
<Link href="https://portal.acmutsa.org/">
|
||||
<Image
|
||||
fill
|
||||
sizes="100vw"
|
||||
src="/portal/banner.jpeg"
|
||||
alt=""
|
||||
className="pointer-events-none !relative min-h-[10rem] rounded-md object-cover"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="prose prose-lg prose-invert mt-3 w-full">
|
||||
<p>
|
||||
Created in service of our membership, Portal was designed as a
|
||||
approachable membership portal for our users so we could{" "}
|
||||
<b>track membership</b>, <b>advertise events</b> and replace our
|
||||
existing <b>database solution</b>.
|
||||
</p>
|
||||
<ul className="md:columns-2">
|
||||
<li>Fast - built to serve thousands</li>
|
||||
<li>Cheap - minimize costs</li>
|
||||
<li>Open Source - help us improve</li>
|
||||
<li>Cutting Edge - the latest technology</li>
|
||||
</ul>
|
||||
<h3>Screenshots</h3>
|
||||
<div className="relative space-y-8">
|
||||
{images.map(([src, description]) => {
|
||||
return (
|
||||
<div
|
||||
key={src}
|
||||
className="flex w-full flex-col justify-center"
|
||||
>
|
||||
<Image
|
||||
fill
|
||||
sizes="100vw"
|
||||
src={src}
|
||||
alt=""
|
||||
className="pointer-events-none !relative !my-1 min-h-[10rem] rounded-md object-cover shadow-lg"
|
||||
/>
|
||||
<span className="text-center text-base">
|
||||
{description}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppWrapper>
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default PortalPage;
|
||||
export default PortalPage;
|
||||
|
||||
@@ -1,142 +1,158 @@
|
||||
import {type NextPage} from "next";
|
||||
import { type NextPage } from "next";
|
||||
import AppWrapper from "../components/AppWrapper";
|
||||
import {RiMagicLine} from "react-icons/ri";
|
||||
import {BiBus, BiHash, BiNetworkChart} from "react-icons/bi";
|
||||
import { RiMagicLine } from "react-icons/ri";
|
||||
import { BiBus, BiHash, BiNetworkChart } from "react-icons/bi";
|
||||
import Link from "next/link";
|
||||
import {IconType} from "react-icons";
|
||||
import {PiPlantBold} from "react-icons/pi";
|
||||
import {HiOutlineRss} from "react-icons/hi";
|
||||
import {GiHummingbird, GiPathDistance} from "react-icons/gi";
|
||||
import {MdOutlineGrain, MdOutlineDns, MdOutlineLeaderboard} from "react-icons/md";
|
||||
import {FiLayers} from "react-icons/fi";
|
||||
import {FaReact} from "react-icons/fa";
|
||||
import {SiPowershell} from "react-icons/si";
|
||||
import {RxTimer} from "react-icons/rx";
|
||||
import { IconType } from "react-icons";
|
||||
import { PiPlantBold } from "react-icons/pi";
|
||||
import { HiOutlineRss } from "react-icons/hi";
|
||||
import { GiHummingbird, GiPathDistance } from "react-icons/gi";
|
||||
import {
|
||||
MdOutlineGrain,
|
||||
MdOutlineDns,
|
||||
MdOutlineLeaderboard,
|
||||
} from "react-icons/md";
|
||||
import { FiLayers } from "react-icons/fi";
|
||||
import { FaReact } from "react-icons/fa";
|
||||
import { SiPowershell } from "react-icons/si";
|
||||
import { RxTimer } from "react-icons/rx";
|
||||
|
||||
const ProjectsPage: NextPage = () => {
|
||||
const projects: { name: string, description: string, url?: string, icon: IconType }[] = [
|
||||
{
|
||||
name: "Portal",
|
||||
description: "ACM Membership & Event System",
|
||||
url: "https://portal.acmutsa.org",
|
||||
icon: RiMagicLine
|
||||
},
|
||||
{
|
||||
name: "Runnerspace",
|
||||
description: "Hackathon MySpace Clone",
|
||||
url: "https://runnerspace.xevion.dev",
|
||||
icon: RiMagicLine
|
||||
},
|
||||
{
|
||||
name: "v6 Place",
|
||||
description: "Paint Images with IPv6 Addresses",
|
||||
url: "https://github.com/Xevion/v6-place",
|
||||
icon: BiNetworkChart
|
||||
},
|
||||
{
|
||||
name: "Phototag",
|
||||
description: "Effortlessly Tag Photos",
|
||||
url: "/phototag",
|
||||
icon: BiHash
|
||||
},
|
||||
{
|
||||
name: "Paths",
|
||||
description: "Graph Traversal Algorithms",
|
||||
url: "https://github.com/Xevion/Paths",
|
||||
icon: GiPathDistance
|
||||
},
|
||||
{
|
||||
name: "undefined behaviors",
|
||||
description: "Astro-based Blog",
|
||||
url: "https://undefined.behavio.rs",
|
||||
icon: HiOutlineRss
|
||||
},
|
||||
{
|
||||
name: "v2.xevion.dev",
|
||||
description: "Jekyll-based Blog",
|
||||
url: "https://v2.xevion.dev",
|
||||
icon: HiOutlineRss
|
||||
},
|
||||
{
|
||||
name: "Grain",
|
||||
description: "Pretty SVG-based Noise",
|
||||
url: "https://grain.xevion.dev",
|
||||
icon: MdOutlineGrain
|
||||
},
|
||||
{
|
||||
name: "Hydroponics Expanded",
|
||||
description: "A RimWorld Mod for Hydroponics",
|
||||
url: "https://github.com/Xevion/RimWorld-Hydroponics-Expanded",
|
||||
icon: PiPlantBold
|
||||
},
|
||||
{
|
||||
name: "Time Banner",
|
||||
description: "Instant PNG Timestamps in Rust",
|
||||
url: "https://github.com/Xevion/time-banner",
|
||||
icon: RxTimer
|
||||
},
|
||||
{
|
||||
name: "The Office",
|
||||
description: "View Quotes from The Office",
|
||||
url: "https://the-office.xevion.dev",
|
||||
icon: FiLayers
|
||||
},
|
||||
{
|
||||
name: "Boids",
|
||||
description: "Flocking Simulation",
|
||||
url: "https://github.com/Xevion/Boids",
|
||||
icon: GiHummingbird
|
||||
},
|
||||
{
|
||||
name: "bus-reminder",
|
||||
description: "Last Bus Departure Reminder",
|
||||
url: "http://github.com/Xevion/bus-reminder",
|
||||
icon: BiBus
|
||||
},
|
||||
{
|
||||
name: "rdap",
|
||||
description: "Javascript RDAP Client",
|
||||
url: "https://rdap.xevion.dev",
|
||||
icon: MdOutlineDns
|
||||
},
|
||||
{
|
||||
name: "icons",
|
||||
description: "Dynamic React-Icons Loading",
|
||||
url: "https://icons.xevion.dev",
|
||||
icon: FaReact
|
||||
},
|
||||
{
|
||||
name: "trivia",
|
||||
description: "CLI + Flask Leaderboard",
|
||||
url: "http://github.com/Xevion/trivia",
|
||||
icon: MdOutlineLeaderboard
|
||||
},
|
||||
{
|
||||
name: "Powershell",
|
||||
description: "Scripts & Guides",
|
||||
url: "https://powershell.xevion.dev",
|
||||
icon: SiPowershell
|
||||
}
|
||||
]
|
||||
return <AppWrapper current='projects'>
|
||||
<div className="mt-20 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-20 gap-y-14 h-full py-2 max-w-500 w-max mx-auto flex ">
|
||||
{projects.map(({name, description, url, icon: Icon}) => <Link
|
||||
key={name}
|
||||
className="relative flex flex-shrink items-center opacity-75 hover:opacity-100 transition-opacity"
|
||||
href={url ?? ""}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title={name}>
|
||||
<div className="pt-2 pr-5">
|
||||
<Icon className="text-3xl saturate-0 opacity-80"/>
|
||||
</div>
|
||||
<div className="flex-auto">
|
||||
<div className="text-normal">{name}</div>
|
||||
<div className="text-sm opacity-70 font-normal">{description}</div>
|
||||
</div>
|
||||
</Link>)}
|
||||
</div>
|
||||
const projects: {
|
||||
name: string;
|
||||
description: string;
|
||||
url?: string;
|
||||
icon: IconType;
|
||||
}[] = [
|
||||
{
|
||||
name: "Portal",
|
||||
description: "ACM Membership & Event System",
|
||||
url: "https://portal.acmutsa.org",
|
||||
icon: RiMagicLine,
|
||||
},
|
||||
{
|
||||
name: "Runnerspace",
|
||||
description: "Hackathon MySpace Clone",
|
||||
url: "https://runnerspace.xevion.dev",
|
||||
icon: RiMagicLine,
|
||||
},
|
||||
{
|
||||
name: "v6 Place",
|
||||
description: "Paint Images with IPv6 Addresses",
|
||||
url: "https://github.com/Xevion/v6-place",
|
||||
icon: BiNetworkChart,
|
||||
},
|
||||
{
|
||||
name: "Phototag",
|
||||
description: "Effortlessly Tag Photos",
|
||||
url: "/phototag",
|
||||
icon: BiHash,
|
||||
},
|
||||
{
|
||||
name: "Paths",
|
||||
description: "Graph Traversal Algorithms",
|
||||
url: "https://github.com/Xevion/Paths",
|
||||
icon: GiPathDistance,
|
||||
},
|
||||
{
|
||||
name: "undefined behaviors",
|
||||
description: "Astro-based Blog",
|
||||
url: "https://undefined.behavio.rs",
|
||||
icon: HiOutlineRss,
|
||||
},
|
||||
{
|
||||
name: "v2.xevion.dev",
|
||||
description: "Jekyll-based Blog",
|
||||
url: "https://v2.xevion.dev",
|
||||
icon: HiOutlineRss,
|
||||
},
|
||||
{
|
||||
name: "Grain",
|
||||
description: "Pretty SVG-based Noise",
|
||||
url: "https://grain.xevion.dev",
|
||||
icon: MdOutlineGrain,
|
||||
},
|
||||
{
|
||||
name: "Hydroponics Expanded",
|
||||
description: "A RimWorld Mod for Hydroponics",
|
||||
url: "https://github.com/Xevion/RimWorld-Hydroponics-Expanded",
|
||||
icon: PiPlantBold,
|
||||
},
|
||||
{
|
||||
name: "Time Banner",
|
||||
description: "Instant PNG Timestamps in Rust",
|
||||
url: "https://github.com/Xevion/time-banner",
|
||||
icon: RxTimer,
|
||||
},
|
||||
{
|
||||
name: "The Office",
|
||||
description: "View Quotes from The Office",
|
||||
url: "https://the-office.xevion.dev",
|
||||
icon: FiLayers,
|
||||
},
|
||||
{
|
||||
name: "Boids",
|
||||
description: "Flocking Simulation",
|
||||
url: "https://github.com/Xevion/Boids",
|
||||
icon: GiHummingbird,
|
||||
},
|
||||
{
|
||||
name: "bus-reminder",
|
||||
description: "Last Bus Departure Reminder",
|
||||
url: "http://github.com/Xevion/bus-reminder",
|
||||
icon: BiBus,
|
||||
},
|
||||
{
|
||||
name: "rdap",
|
||||
description: "Javascript RDAP Client",
|
||||
url: "https://rdap.xevion.dev",
|
||||
icon: MdOutlineDns,
|
||||
},
|
||||
{
|
||||
name: "icons",
|
||||
description: "Dynamic React-Icons Loading",
|
||||
url: "https://icons.xevion.dev",
|
||||
icon: FaReact,
|
||||
},
|
||||
{
|
||||
name: "trivia",
|
||||
description: "CLI + Flask Leaderboard",
|
||||
url: "http://github.com/Xevion/trivia",
|
||||
icon: MdOutlineLeaderboard,
|
||||
},
|
||||
{
|
||||
name: "Powershell",
|
||||
description: "Scripts & Guides",
|
||||
url: "https://powershell.xevion.dev",
|
||||
icon: SiPowershell,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<AppWrapper current="projects">
|
||||
<div className="max-w-500 mx-auto mt-20 flex grid h-full w-max grid-cols-1 gap-x-20 gap-y-14 py-2 md:grid-cols-2 lg:grid-cols-3">
|
||||
{projects.map(({ name, description, url, icon: Icon }) => (
|
||||
<Link
|
||||
key={name}
|
||||
className="relative flex flex-shrink items-center opacity-75 transition-opacity hover:opacity-100"
|
||||
href={url ?? ""}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title={name}
|
||||
>
|
||||
<div className="pr-5 pt-2">
|
||||
<Icon className="text-3xl opacity-80 saturate-0" />
|
||||
</div>
|
||||
<div className="flex-auto">
|
||||
<div className="text-normal">{name}</div>
|
||||
<div className="text-sm font-normal opacity-70">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</AppWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectsPage;
|
||||
export default ProjectsPage;
|
||||
|
||||
Reference in New Issue
Block a user