Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ui/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import clsx from "clsx";
import type { Metadata } from "next";
import { Inter, Yanone_Kaffeesatz } from "next/font/google";
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import HeaderPadding from "@/components/HeaderPadding";
import "./globals.css";
Expand Down Expand Up @@ -85,6 +86,8 @@ export default function RootLayout({
<Header className="tw-fixed tw-top-0 tw-z-10" />
<HeaderPadding />
<main className="tw-grow">{children}</main>
<Footer />
<div id="portal" />
</body>
</html>
);
Expand Down
44 changes: 41 additions & 3 deletions ui/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
import MetaImg from "@/public/meta.jpg";
import Article from "@/components/Article";
import Banner from "@/components/Banner";
import Button from "@/components/Button";
import Container from "@/components/Container";

export default function Home() {
return (
<Container>
<p>hello world</p>
</Container>
<>
<Banner src={MetaImg} />
<Container>
<Article>
<section>
<h1>sciwork 是什麼?</h1>
<p>
The sciwork is a community for researchers and engineers to share
and discuss computer code for scientific, numerical, and
engineering work. We believe in the power of openness, and use
open source as a means to advance software development for
computational sciences.
</p>
<p>
As information technology blending in every aspect of human
activities, proficient use of programming languages is a
prerequisite for conducting most research and engineering work. As
the practitioners observed, the work evolved into a hierarchy of
skills that take years to acquire. We need a thorough
understanding of the problem to solve as well as the mastery of
computer programming to deliver reliable solution. It is overly
challenging since either of both is already complicated. Sciwork
would like to get involved in the global effort to solve the issue
of code development entangling with science and engineering.
</p>
<p>
Our activities include but are not limited to coding sprints,
hands-on tutorials, and technical talks and conferences (ex,
sciwork 2023), on-line or off-line. You are welcome to join us!
</p>
<Button variant="action" to="https://sciwork.dev">
前往 sciwork 官網
</Button>
</section>
</Article>
</Container>
</>
);
}
18 changes: 18 additions & 0 deletions ui/components/Article.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Container from "@/components/Container";

type Props = {
children: React.ReactNode;
};

const Article = ({ children }: Props) => {
return (
<Container
as="article"
className="tw-prose tw-mb-12 tw-mt-2 tw-max-w-none prose-headings:tw-font-yk prose-headings:tw-font-normal tablet:tw-mb-32 tablet:tw-mt-10"
>
{children}
</Container>
);
};

export default Article;
20 changes: 20 additions & 0 deletions ui/components/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Image, { StaticImageData } from "next/image";

type Props = {
src: string | StaticImageData;
};

const Banner = ({ src }: Props) => {
return (
<div className="tw-relative tw-w-full tablet:tw-h-[500px] tw-h-96">
<Image
className="tw-object-center tw-object-cover"
src={src}
alt="Banner"
fill
/>
</div>
);
};

export default Banner;
57 changes: 57 additions & 0 deletions ui/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import clsx from 'clsx';
import NextLink, { LinkProps as InternalLinkProps } from 'next/link';
import { HTMLProps, MouseEvent } from 'react';

type Props = {
className?: string;
variant?: 'default' | 'action';
children: React.ReactNode;
to?: string;
onClick?: () => void;
};

const Button = ({
className,
variant = 'default',
children,
to,
onClick,
...rest
}: Props & HTMLProps<HTMLButtonElement>) => {
let Component: any = to ? NextLink : 'button';
let props:
| {
href?: string;
onClick?: (e: MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}
| InternalLinkProps = {};

if (to) {
props['href'] = to;
}

if (onClick) {
props['onClick'] = onClick;
}

return (
<Component
className={clsx(
'tw-px-4 tw-pb-2 tw-pt-3 tw-font-yk tw-text-lg tw-font-normal tw-no-underline tw-outline-none focus:tw-ring-2 tablet:tw-text-lg',
className,
{
'tw-rounded-md tw-text-neutral-950 hover:tw-ring-1 hover:tw-ring-neutral-400':
variant === 'default',
'tw-rounded-full tw-bg-yellow-300 tw-text-black hover:tw-bg-yellow-400':
variant === 'action',
},
)}
{...props}
{...rest}
>
{children}
</Component>
);
};

export default Button;
49 changes: 49 additions & 0 deletions ui/components/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use client";

import { Transition, TransitionChild } from "@headlessui/react";
import { MouseEvent, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";

type Props = {
show: boolean;
onClick: (e: MouseEvent<HTMLDivElement>) => void;
children: React.ReactNode;
};

const Drawer = ({ show, onClick, children }: Props) => {
const ref = useRef<Element | null>(null);
const [mounted, setMounted] = useState(false);

useEffect(() => {
ref.current = document.querySelector<HTMLElement>("#portal");
setMounted(true);
}, []);

if (!mounted || !ref.current) return null;

return createPortal(
<Transition show={show}>
<TransitionChild>
<div
className="tw-fixed tw-inset-0 tw-z-10 tw-bg-black tw-transition-opacity tw-ease-linear tw-duration-300 tw-opacity-50 data-[closed]:tw-opacity-0"
onClick={onClick}
/>
</TransitionChild>
<TransitionChild
as="div"
className="tw-fixed tw-left-0 tw-top-0 tw-z-50 tw-h-screen tw-min-w-[300px] tw-bg-gray-200"
enter="tw-transition tw-ease-in-out tw-duration-300 tw-transform"
enterFrom="-tw-translate-x-full"
enterTo="tw-translate-x-0"
leave="tw-transition tw-ease-in-out tw-duration-300 tw-transform"
leaveFrom="tw-translate-x-0"
leaveTo="-tw-translate-x-full"
>
{children}
</TransitionChild>
</Transition>,
ref.current,
);
};

export default Drawer;
19 changes: 19 additions & 0 deletions ui/components/DrawerLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import NextLink from 'next/link';

const DrawerLink = ({
children,
to,
}: {
children: React.ReactNode;
to: string;
}) => {
return (
<NextLink className="tw-block tw-w-full tw-font-yk" href={to}>
<div className="tw-px-8 tw-py-2 tw-text-2xl tw-font-medium tw-leading-loose tw-text-black hover:tw-text-sky-600">
{children}
</div>
</NextLink>
);
};

export default DrawerLink;
53 changes: 53 additions & 0 deletions ui/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
faDiscord,
faSquareFacebook,
faTwitter,
} from "@fortawesome/free-brands-svg-icons";
import Container from "@/components/Container";
import SocialLink from "@/components/SocialLink";

const Footer = () => {
return (
<footer className="tw-w-full">
<Container className=" tw-bg-sky-950 tw-text-white tw-py-10">
<div className="tw-flex tw-flex-row">
<div className="tw-basis-1/2">
<h2 className="tw-text-3xl tw-font-yk">Follow us</h2>
<div className="tw-my-2">
<SocialLink
icon={faTwitter}
to="https://twitter.com/intent/tweet?screen_name=sciwork&ref_src=twsrc%5Etfw"
>
@sciwork
</SocialLink>
<SocialLink icon={faDiscord} to="https://discord.gg/6MAkFrD">
Discord
</SocialLink>
<SocialLink
icon={faSquareFacebook}
to="https://www.facebook.com/sciworkdev"
>
Facebook
</SocialLink>
</div>
</div>
<div className="tw-basis-1/2">
<h2 className="tw-text-3xl tw-font-yk">Contact us</h2>
<div className="tw-my-2">
<a
className="hover:tw-cursor-pointer hover:tw-text-sky-600"
target="_blank"
href="mailto:contact@sciwork.dev"
>
contact@sciwork.dev
</a>
</div>
</div>
</div>
<div className="tw-mt-8">Website is powered by Next.js.</div>
</Container>
</footer>
);
};

export default Footer;
4 changes: 4 additions & 0 deletions ui/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import clsx from "clsx";
import routes from "@/configurations/routes";
import Logo from "@/components/Logo";
import MobileNavigator from "@/components/MobileNavigator";
import NavLink from "@/components/NavLink";

type Props = {
Expand All @@ -17,6 +18,9 @@ const Header = ({ className }: Props) => {
role="navigation"
>
<div className="tw-grow">
<div className="desktop:tw-hidden">
<MobileNavigator />
</div>
<div className="tw-hidden tw-pt-2 desktop:tw-block">
<Logo variant="light" />
</div>
Expand Down
44 changes: 44 additions & 0 deletions ui/components/MobileNavigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import { useState } from "react";
import { faBars } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import routes from "@/configurations/routes";
import Button from "@/components/Button";
import Drawer from "@/components/Drawer";
import DrawerLink from "@/components/DrawerLink";
import Logo from "@/components/Logo";

const MobileNavigator = () => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const toggleMenu = () => setIsMenuOpen((prev) => !prev);
return (
<>
<div className="tw-flex tw-justify-between tw-items-center">
<Logo variant="light" />
<Button onClick={toggleMenu} className="tw-pb-4">
<FontAwesomeIcon className="tw-text-black" icon={faBars} />
</Button>
</div>
<Drawer show={isMenuOpen} onClick={toggleMenu}>
<div
className="tw-border-b tw-px-4 tw-pb-2 tw-pt-3 tw-h-20 tw-flex tw-items-center"
onClick={toggleMenu}
>
<Logo variant="light" />
</div>
<div onClick={toggleMenu}>
{routes
.filter((route) => !route.disabled)
.map((route) => (
<DrawerLink key={route.path} to={route.path}>
{route.name}
</DrawerLink>
))}
</div>
</Drawer>
</>
);
};

export default MobileNavigator;
26 changes: 26 additions & 0 deletions ui/components/SocialLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import NextLink from "next/link";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

type Props = {
icon: IconProp;
to: string;
children?: React.ReactNode;
};

const SocialLink = ({ icon, to, children }: Props) => {
return (
<NextLink
className="tw-text-white tw-flex tw-items-center hover:tw-text-sky-600"
href={to}
target="_blank"
>
<div className="fa-layers fa-fw fa-3x">
<FontAwesomeIcon icon={icon} transform="shrink-8" />
</div>
{children}
</NextLink>
);
};

export default SocialLink;
5 changes: 5 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"lint": "next lint"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-brands-svg-icons": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@headlessui/react": "^2.1.2",
"@tailwindcss/typography": "^0.5.13",
"clsx": "^2.1.1",
"next": "14.2.4",
Expand Down
Loading