Migrated code from Kobold Kid webite amd made a simple static page site.
This commit is contained in:
14
src/app/layout.tsx
Normal file
14
src/app/layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import { Provider } from "@/components/ui/provider";
|
||||
|
||||
export default function RootLayout(props: { children: React.ReactNode }) {
|
||||
const { children } = props;
|
||||
return (
|
||||
<html suppressHydrationWarning>
|
||||
<link rel="icon" href="/images/logo/favicon/favicon.ico" sizes="any" />
|
||||
<body>
|
||||
<Provider>{children}</Provider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
113
src/app/page.tsx
Normal file
113
src/app/page.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { Button, Heading, HStack, Link, Text, VStack } from "@chakra-ui/react";
|
||||
import newLogo from "../../public/images/logo/New Logo (transparent).png";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<VStack
|
||||
w="100vw"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
spaceY={12}
|
||||
pt="5vh"
|
||||
pb="20vh"
|
||||
>
|
||||
<VStack spaceY={2}>
|
||||
<Image height={250} src={newLogo} alt="New LCM logo" />
|
||||
<Heading
|
||||
lineHeight="1"
|
||||
w="80vw"
|
||||
as="h1"
|
||||
color="cyan"
|
||||
fontSize="4rem"
|
||||
textAlign="center"
|
||||
>
|
||||
{"Lucid Creations Media Website"}
|
||||
</Heading>
|
||||
</VStack>
|
||||
|
||||
<VStack w="80vw" spaceY={2}>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{"The LCM website and eShop has been temporarily discontinued."}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
"Over the years there have been many external factors that interfered with my ability to dedicate time and find motivation to work on my creative passions. This includes erotica, streaming, hypno files, and more."
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
"It has also interfered with my ability to learn new skills such as music creation and digital art."
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
"Last year I faced a layoff and haven't been able to get back into my field. I can no longer afford the costs of hosting this website on it's current platform. The website generated no sales and thus I had to make the difficult decision to shut the site down for now."
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
'I have no time frame for when or if I will reopen the eShop. I do wish to at some point, on a more modern platform. I know that the next few months will be hell for me and I will have no time to dedicate to any of this. I will have to see how things are once I start getting more free time and if I can start working on a new website, "remastering" old hypno files, and making new ones for the relaunch.'
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
"Since LCM is not registered as an LLC yet I have been contemplating rebranding the company one last time. A few weeks before coming to this decision and making this page I was being pulled to shelf Kobold as Lucid's default form. I have been enjoying hearing/seeing everyone refer to me as wolf/werwolf so much that I might keep it this way. Just like when I changed my original fursona and alias it might be time to flip to a new chapter in my life."
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
'For a little while I was debating using "Kobold Kid", my new vanity domain name, as the new brand, but I have a new idea. I will sit on it for a few months before I make any decisions.'
|
||||
}
|
||||
</Text>
|
||||
<Text w="100%" textAlign="left" fontSize="lg">
|
||||
{
|
||||
"Another option I was considering is keeping Kobold as marketing/mascot, but I am not sure about it."
|
||||
}
|
||||
</Text>
|
||||
</VStack>
|
||||
|
||||
<VStack spaceY={6} w="80vw">
|
||||
<Heading as="h2" color="cyan" fontSize="2.5rem">
|
||||
{"Other LCM Resources"}
|
||||
</Heading>
|
||||
|
||||
<HStack gap="6" wrap="wrap">
|
||||
<Button variant="solid" bgColor="teal" fontSize="xl">
|
||||
<Link
|
||||
target="_blank"
|
||||
color="whiteAlpha.950"
|
||||
href="https://community.lucidcreations.media/"
|
||||
>
|
||||
{"The Cove"}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="solid" bgColor="teal" fontSize="xl">
|
||||
<Link
|
||||
target="_blank"
|
||||
color="whiteAlpha.950"
|
||||
href="https://vrchat.com/home/group/grp_781bbe4b-51ec-4025-a14f-cf23ced90507"
|
||||
>
|
||||
{"Dreamy Drove"}
|
||||
</Link>
|
||||
</Button>
|
||||
</HStack>
|
||||
<Heading as="h2" color="cyan" fontSize="2.5rem">
|
||||
{"Lucid's Socials"}
|
||||
</Heading>
|
||||
|
||||
<HStack gap="6" wrap="wrap">
|
||||
<Button variant="solid" bgColor="teal" fontSize="xl">
|
||||
<Link
|
||||
target="_blank"
|
||||
color="whiteAlpha.950"
|
||||
href="https://koboldkid.com/"
|
||||
>
|
||||
{"Kobold Kid Website"}
|
||||
</Link>
|
||||
</Button>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import React from "react";
|
||||
import { Box, Link, Button, BoxProps, Text } from "@chakra-ui/react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
interface CustomButtonProps {
|
||||
text: string;
|
||||
link: string;
|
||||
type: "primary" | "secondary" | "footer";
|
||||
}
|
||||
|
||||
const MotionBox = motion<BoxProps>(Box);
|
||||
|
||||
const CustomButton = ({ text, link, type }: CustomButtonProps): JSX.Element => {
|
||||
return (
|
||||
<MotionBox whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }}>
|
||||
<Link href={link} target="_blank" rel="noopener">
|
||||
<Button variant={type}>
|
||||
<Text>{text}</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</MotionBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomButton;
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from "react";
|
||||
import { Box, Link, Button, BoxProps, Text } from "@chakra-ui/react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
const MotionBox = motion<BoxProps>(Box);
|
||||
|
||||
const GitHub = (): JSX.Element => {
|
||||
return (
|
||||
<MotionBox whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }}>
|
||||
<Link
|
||||
href="work/lcm/LucidCreationsWebsite/src/components/buttons/KoFi.tsx"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<Button variant="primary" leftIcon={<Icon icon="mdi:github" />}>
|
||||
<Text>{"View Codebase"}</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</MotionBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default GitHub;
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from "react";
|
||||
import { Box, Link, Button, BoxProps, Text } from "@chakra-ui/react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
const MotionBox = motion<BoxProps>(Box);
|
||||
|
||||
const KoFi = (): JSX.Element => {
|
||||
return (
|
||||
<MotionBox whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }}>
|
||||
<Link
|
||||
href="https://ko-fi.com/lucidcreationsmedia"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<Button variant="kofi" leftIcon={<Icon icon="cib:ko-fi" />}>
|
||||
<Text>{"Fund The App"}</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</MotionBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default KoFi;
|
||||
@@ -1,28 +0,0 @@
|
||||
export interface LinkObj {
|
||||
href?: string;
|
||||
name?: string;
|
||||
type: "primary" | "secondary" | "ko-fi" | "GitHub";
|
||||
}
|
||||
|
||||
type Links = LinkObj[];
|
||||
|
||||
const links: Links = [
|
||||
{
|
||||
href: "https://docs.google.com/document/d/1y1tbTG6TYoLMEde4XHzInByyHQ0T6Aw2RF6Y4Z7Yabs",
|
||||
name: "Roadmap and Progress",
|
||||
type: "secondary"
|
||||
},
|
||||
// {
|
||||
// type: "ko-fi"
|
||||
// },
|
||||
{
|
||||
href: "https://t.me/LucidCreationsMedia",
|
||||
name: "Dev Updates",
|
||||
type: "secondary"
|
||||
},
|
||||
{
|
||||
type: "GitHub"
|
||||
}
|
||||
];
|
||||
|
||||
export default links;
|
||||
@@ -1,77 +0,0 @@
|
||||
import React from "react";
|
||||
import { Box, HStack, VStack } from "@chakra-ui/react";
|
||||
import CustomButton from "./Custom";
|
||||
import links, { LinkObj } from "./data/links";
|
||||
import KoFi from "./KoFi";
|
||||
import GitHub from "./GitHub";
|
||||
|
||||
const Buttons = (): JSX.Element => {
|
||||
return (
|
||||
<Box h="auto" w="100%">
|
||||
<HStack
|
||||
display={{ base: "none", lg: "flex" }}
|
||||
h="auto"
|
||||
w="100%"
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
spacing={4}
|
||||
>
|
||||
{links.map((link: LinkObj) => {
|
||||
const { href, name, type } = link;
|
||||
|
||||
if (type === "primary" || type === "secondary") {
|
||||
return (
|
||||
<CustomButton
|
||||
key={name.replaceAll(" ", "-")}
|
||||
link={href}
|
||||
text={name}
|
||||
type={type}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "ko-fi") {
|
||||
return <KoFi key={type} />;
|
||||
}
|
||||
|
||||
if (type === "GitHub") {
|
||||
return <GitHub key={type} />;
|
||||
}
|
||||
})}
|
||||
</HStack>
|
||||
<VStack
|
||||
display={{ base: "flex", lg: "none" }}
|
||||
h="auto"
|
||||
w="100%"
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
spacing={4}
|
||||
>
|
||||
{links.map((link: LinkObj) => {
|
||||
const { href, name, type } = link;
|
||||
|
||||
if (type === "primary" || type === "secondary") {
|
||||
return (
|
||||
<CustomButton
|
||||
key={name.replaceAll(" ", "-")}
|
||||
link={href}
|
||||
text={name}
|
||||
type={type}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "ko-fi") {
|
||||
return <KoFi key={type} />;
|
||||
}
|
||||
|
||||
if (type === "GitHub") {
|
||||
return <GitHub key={type} />;
|
||||
}
|
||||
})}
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Buttons;
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Button, Heading, Text, Link, VStack } from "@chakra-ui/react";
|
||||
import React from "react";
|
||||
|
||||
const AboutProject = (): JSX.Element => {
|
||||
const description = `This project and website is a replacement for the current Lucid Creations Media Website. It is going to being designed to be faster, more user friendly, and better accessible compared to Wordpress. This platform is being built on React and Next.js`;
|
||||
|
||||
return (
|
||||
<VStack
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
w="100%"
|
||||
my="10"
|
||||
px={{ base: "5vw", md: "15vw", lg: "20vw", xl: "30vw" }}
|
||||
spacing="4"
|
||||
>
|
||||
<Heading w="100%">{"About This Website"}</Heading>
|
||||
<Text w="100%">{description}</Text>
|
||||
<Link href="htps://lucidcreations.media" target="_blank" rel="noopener">
|
||||
<Button type="button" variant="secondary">
|
||||
<Text>{"Visit the current website"}</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutProject;
|
||||
@@ -1,84 +0,0 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { Flex, HStack, Text, VStack } from "@chakra-ui/react";
|
||||
import BrandText from "../../theme/components/BrandText";
|
||||
import { Icon } from "@iconify/react";
|
||||
import mp3SVG from "../../../public/images/mp3.svg";
|
||||
|
||||
const WhatIMakeBanner = (): JSX.Element => {
|
||||
return (
|
||||
<VStack
|
||||
bgColor="brand.cosmic"
|
||||
w="100%"
|
||||
alignContent="center"
|
||||
justifyContent="center"
|
||||
py="10"
|
||||
px={{ base: "0", lg: "5vw", "2xl": "10vw" }}
|
||||
>
|
||||
<VStack w="100%" alignContent="center" pb={{ base: "10", md: "6" }}>
|
||||
<BrandText type="Heading" headerLevel="h2" text={"What I Make"} />
|
||||
</VStack>
|
||||
<Flex
|
||||
w="100%"
|
||||
justifyContent="space-around"
|
||||
alignContent="center"
|
||||
direction={{ base: "column", md: "row" }}
|
||||
gap="5rem"
|
||||
>
|
||||
<VStack spacing="4" w="100%">
|
||||
<BrandText type="Heading" headerLevel="h3" text={"Communities"} />
|
||||
<VStack spacing="4" alignContent="start" justifyContent="center">
|
||||
<HStack spacing="4">
|
||||
<Text fontSize="5xl">
|
||||
<Icon icon="ic:baseline-discord" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"Lucid's Cove"} />
|
||||
</HStack>
|
||||
<HStack spacing="4">
|
||||
<Text fontSize="5xl">
|
||||
<Icon icon="ic:baseline-telegram" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"Lucid's Cove"} />
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
<VStack spacing="4" w="100%">
|
||||
<BrandText type="Heading" headerLevel="h3" text={"Content"} />
|
||||
<VStack spacing="4" alignContent="start" justifyContent="center">
|
||||
<HStack spacing="4" w="100%">
|
||||
<Text fontSize="5xl">
|
||||
<Icon icon="heroicons-solid:pencil" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"Erotic Stories"} />
|
||||
</HStack>
|
||||
<HStack spacing="4" w="100%">
|
||||
<Text fontSize="5xl">
|
||||
<Image height="35" width="35" src={mp3SVG} alt="MP3 Icon" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"Hypno Audio Files"} />
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
<VStack spacing="4" w="100%">
|
||||
<BrandText type="Heading" headerLevel="h3" text={"Streams"} />
|
||||
<VStack spacing="4" alignContent="start" justifyContent="center">
|
||||
<HStack spacing="4">
|
||||
<Text fontSize="5xl">
|
||||
<Icon icon="mdi:twitch" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"LucidKobold"} />
|
||||
</HStack>
|
||||
<HStack spacing="4">
|
||||
<Text fontSize="5xl">
|
||||
<Icon icon="mdi:youtube" />
|
||||
</Text>
|
||||
<BrandText type="Text" size="xl" text={"LucidKobold"} />
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</Flex>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhatIMakeBanner;
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Heading, VStack } from "@chakra-ui/react";
|
||||
import React from "react";
|
||||
import WhatIMakeBanner from "./WhatIMakeBanner";
|
||||
import AboutProject from "./AboutProject";
|
||||
|
||||
const TempHero = (): JSX.Element => {
|
||||
return (
|
||||
<VStack
|
||||
bg="brand.content"
|
||||
h="100%"
|
||||
w="100%"
|
||||
spacing="0"
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
>
|
||||
<WhatIMakeBanner />
|
||||
<AboutProject />
|
||||
<VStack
|
||||
w="100%"
|
||||
h="36.3vh"
|
||||
justifyContent="space-around"
|
||||
alignContent="center"
|
||||
>
|
||||
<Heading size="3xl" as="h2">
|
||||
{"Placeholder section"}
|
||||
</Heading>
|
||||
</VStack>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default TempHero;
|
||||
@@ -1,37 +0,0 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Box,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalContent,
|
||||
ModalOverlay
|
||||
} from "@chakra-ui/react";
|
||||
import LoadingSpinner from "./LoadingSpinner";
|
||||
|
||||
const LoadingOverlay = (): JSX.Element => {
|
||||
return (
|
||||
<Modal
|
||||
isCentered
|
||||
isOpen
|
||||
onClose={() => null}
|
||||
motionPreset="slideInBottom"
|
||||
scrollBehavior="inside"
|
||||
size="xs"
|
||||
>
|
||||
<ModalOverlay bg="loading.overlayBg" />
|
||||
<ModalContent bg="transparent" boxShadow="none">
|
||||
{/* <ModalHeader>
|
||||
</ModalHeader> */}
|
||||
<ModalBody border="0px">
|
||||
<Box h="100%" w="100%" textAlign="center">
|
||||
<LoadingSpinner />
|
||||
</Box>
|
||||
</ModalBody>
|
||||
{/* <ModalFooter>
|
||||
</ModalFooter> */}
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingOverlay;
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from "react";
|
||||
import { Spinner } from "@chakra-ui/react";
|
||||
|
||||
const LoadingSpinner = (): JSX.Element => {
|
||||
return (
|
||||
<Spinner
|
||||
thickness="4px"
|
||||
speed="0.50s"
|
||||
emptyColor="loading.spinnerEmptySpace"
|
||||
color="loading.spinnerColor"
|
||||
size="xl"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingSpinner;
|
||||
110
src/components/ui/color-mode.tsx
Normal file
110
src/components/ui/color-mode.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
||||
"use client";
|
||||
|
||||
import type { IconButtonProps, SpanProps } from "@chakra-ui/react";
|
||||
import { ClientOnly, IconButton, Skeleton, Span } from "@chakra-ui/react";
|
||||
import { ThemeProvider, useTheme } from "next-themes";
|
||||
import type { ThemeProviderProps } from "next-themes";
|
||||
import * as React from "react";
|
||||
import { LuMoon, LuSun } from "react-icons/lu";
|
||||
|
||||
export interface ColorModeProviderProps extends ThemeProviderProps { }
|
||||
|
||||
export function ColorModeProvider(props: ColorModeProviderProps) {
|
||||
return (
|
||||
<ThemeProvider attribute="class" disableTransitionOnChange {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export type ColorMode = "light" | "dark";
|
||||
|
||||
export interface UseColorModeReturn {
|
||||
colorMode: ColorMode;
|
||||
setColorMode: (colorMode: ColorMode) => void;
|
||||
toggleColorMode: () => void;
|
||||
}
|
||||
|
||||
export function useColorMode(): UseColorModeReturn {
|
||||
const { resolvedTheme, setTheme, forcedTheme } = useTheme();
|
||||
const colorMode = forcedTheme || resolvedTheme;
|
||||
const toggleColorMode = () => {
|
||||
setTheme(resolvedTheme === "dark" ? "light" : "dark");
|
||||
};
|
||||
return {
|
||||
colorMode: colorMode as ColorMode,
|
||||
setColorMode: setTheme,
|
||||
toggleColorMode
|
||||
};
|
||||
}
|
||||
|
||||
export function useColorModeValue<T>(light: T, dark: T) {
|
||||
const { colorMode } = useColorMode();
|
||||
return colorMode === "dark" ? dark : light;
|
||||
}
|
||||
|
||||
export function ColorModeIcon() {
|
||||
const { colorMode } = useColorMode();
|
||||
return colorMode === "dark" ? <LuMoon /> : <LuSun />;
|
||||
}
|
||||
|
||||
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> { }
|
||||
|
||||
export const ColorModeButton = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
ColorModeButtonProps
|
||||
>(function ColorModeButton(props, ref) {
|
||||
const { toggleColorMode } = useColorMode();
|
||||
return (
|
||||
<ClientOnly fallback={<Skeleton boxSize="8" />}>
|
||||
<IconButton
|
||||
onClick={toggleColorMode}
|
||||
variant="ghost"
|
||||
aria-label="Toggle color mode"
|
||||
size="sm"
|
||||
ref={ref}
|
||||
{...props}
|
||||
css={{
|
||||
_icon: {
|
||||
width: "5",
|
||||
height: "5"
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ColorModeIcon />
|
||||
</IconButton>
|
||||
</ClientOnly>
|
||||
);
|
||||
});
|
||||
|
||||
export const LightMode = React.forwardRef<HTMLSpanElement, SpanProps>(
|
||||
function LightMode(props, ref) {
|
||||
return (
|
||||
<Span
|
||||
color="fg"
|
||||
display="contents"
|
||||
className="chakra-theme light"
|
||||
colorPalette="gray"
|
||||
colorScheme="light"
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const DarkMode = React.forwardRef<HTMLSpanElement, SpanProps>(
|
||||
function DarkMode(props, ref) {
|
||||
return (
|
||||
<Span
|
||||
color="fg"
|
||||
display="contents"
|
||||
className="chakra-theme dark"
|
||||
colorPalette="gray"
|
||||
colorScheme="dark"
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
12
src/components/ui/provider.tsx
Normal file
12
src/components/ui/provider.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
|
||||
import { ColorModeProvider, type ColorModeProviderProps } from "./color-mode";
|
||||
|
||||
export function Provider(props: ColorModeProviderProps) {
|
||||
return (
|
||||
<ChakraProvider value={defaultSystem}>
|
||||
<ColorModeProvider {...props} />
|
||||
</ChakraProvider>
|
||||
);
|
||||
}
|
||||
43
src/components/ui/toaster.tsx
Normal file
43
src/components/ui/toaster.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Toaster as ChakraToaster,
|
||||
Portal,
|
||||
Spinner,
|
||||
Stack,
|
||||
Toast,
|
||||
createToaster
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
export const toaster = createToaster({
|
||||
placement: "bottom-end",
|
||||
pauseOnPageIdle: true
|
||||
});
|
||||
|
||||
export const Toaster = () => {
|
||||
return (
|
||||
<Portal>
|
||||
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
|
||||
{(toast) => (
|
||||
<Toast.Root width={{ md: "sm" }}>
|
||||
{toast.type === "loading" ? (
|
||||
<Spinner size="sm" color="blue.solid" />
|
||||
) : (
|
||||
<Toast.Indicator />
|
||||
)}
|
||||
<Stack gap="1" flex="1" maxWidth="100%">
|
||||
{toast.title && <Toast.Title>{toast.title}</Toast.Title>}
|
||||
{toast.description && (
|
||||
<Toast.Description>{toast.description}</Toast.Description>
|
||||
)}
|
||||
</Stack>
|
||||
{toast.action && (
|
||||
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
|
||||
)}
|
||||
{toast.closable && <Toast.CloseTrigger />}
|
||||
</Toast.Root>
|
||||
)}
|
||||
</ChakraToaster>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
46
src/components/ui/tooltip.tsx
Normal file
46
src/components/ui/tooltip.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react";
|
||||
import * as React from "react";
|
||||
|
||||
export interface TooltipProps extends ChakraTooltip.RootProps {
|
||||
showArrow?: boolean;
|
||||
portalled?: boolean;
|
||||
portalRef?: React.RefObject<HTMLElement>;
|
||||
content: React.ReactNode;
|
||||
contentProps?: ChakraTooltip.ContentProps;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
|
||||
function Tooltip(props, ref) {
|
||||
const {
|
||||
showArrow,
|
||||
children,
|
||||
disabled,
|
||||
portalled = true,
|
||||
content,
|
||||
contentProps,
|
||||
portalRef,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
if (disabled) return children;
|
||||
|
||||
return (
|
||||
<ChakraTooltip.Root {...rest}>
|
||||
<ChakraTooltip.Trigger asChild>{children}</ChakraTooltip.Trigger>
|
||||
<Portal disabled={!portalled} container={portalRef}>
|
||||
<ChakraTooltip.Positioner>
|
||||
<ChakraTooltip.Content ref={ref} {...contentProps}>
|
||||
{showArrow && (
|
||||
<ChakraTooltip.Arrow>
|
||||
<ChakraTooltip.ArrowTip />
|
||||
</ChakraTooltip.Arrow>
|
||||
)}
|
||||
{content}
|
||||
</ChakraTooltip.Content>
|
||||
</ChakraTooltip.Positioner>
|
||||
</Portal>
|
||||
</ChakraTooltip.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -1,66 +0,0 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { format } from "date-fns";
|
||||
import populate from "../../../lib/populateMonth";
|
||||
|
||||
interface CalenderSlice {
|
||||
currDate: string;
|
||||
selectedDateInfo: SelectedDateInfo;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
const getCurrDate = (): Date => new Date();
|
||||
const dateParse = (date: Date) => date.toJSON();
|
||||
const dateFormatter = (date: Date): string => format(date, "LLLL uuuu");
|
||||
|
||||
const initialState: CalenderSlice = {
|
||||
currDate: dateParse(getCurrDate()),
|
||||
selectedDateInfo: {
|
||||
date: dateParse(getCurrDate()),
|
||||
title: dateFormatter(getCurrDate()),
|
||||
layout: populate(getCurrDate())
|
||||
},
|
||||
isLoading: true
|
||||
};
|
||||
|
||||
// TODO: Add a function that validated if a month has at least one sticker in it. Use that within the nav function (when filter is enabled).
|
||||
|
||||
// TODO: Add a function that will give the closest date, if available, when the nav func detects an empty month.
|
||||
// Use the chart creation date to aid with this. (When filter is enabled)
|
||||
|
||||
/**
|
||||
* TODO: Add logic that prevents navigation to the future and too far in the past. (Use chart creation date)
|
||||
* Update to use a promise and return appropriate errors. Display those errors on the front end.
|
||||
* Update the use of this function on the front to handle the fails of the promise.
|
||||
*/
|
||||
|
||||
// TODO: (When filter is enabled) Update the calender update function that will take in a direction so that the the navigation buttons will take the user to the next month with stickers. Assuming there was a gap with empty months.
|
||||
|
||||
const calenderSlice = createSlice({
|
||||
name: "Calender",
|
||||
initialState,
|
||||
reducers: {
|
||||
// Update month info
|
||||
updateMonth(state: CalenderSlice, action: PayloadAction<string>) {
|
||||
const { payload } = action;
|
||||
|
||||
const toDateObj: Date = new Date(payload);
|
||||
|
||||
state.selectedDateInfo.date = payload;
|
||||
state.selectedDateInfo.title = dateFormatter(toDateObj);
|
||||
state.selectedDateInfo.layout = populate(toDateObj);
|
||||
},
|
||||
// Update current date
|
||||
updateCurrDate(state: CalenderSlice) {
|
||||
state.currDate = dateParse(new Date());
|
||||
},
|
||||
// Update isLoading
|
||||
updateLoading(state: CalenderSlice, action: PayloadAction<boolean>) {
|
||||
const { payload } = action;
|
||||
state.isLoading = payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const { updateMonth, updateCurrDate, updateLoading } =
|
||||
calenderSlice.actions;
|
||||
export default calenderSlice.reducer;
|
||||
@@ -1,62 +0,0 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { format, getDate, isSameDay } from "date-fns";
|
||||
import stickersSeeder from "../../../data/stickerSeeder";
|
||||
|
||||
interface StickersSlice {
|
||||
stickersMonth: StickerDays;
|
||||
}
|
||||
|
||||
interface UpdateStickerSlicePayload {
|
||||
stickerDate: string;
|
||||
sticker: StickerVal;
|
||||
}
|
||||
|
||||
const initialState: StickersSlice = {
|
||||
stickersMonth: stickersSeeder()
|
||||
};
|
||||
|
||||
const stickersSlice = createSlice({
|
||||
name: "Stickers",
|
||||
initialState,
|
||||
reducers: {
|
||||
addEditSticker(
|
||||
state: StickersSlice,
|
||||
actions: PayloadAction<UpdateStickerSlicePayload>
|
||||
) {
|
||||
const { stickerDate, sticker } = actions.payload;
|
||||
|
||||
const dateObj = new Date(stickerDate);
|
||||
|
||||
// Getting index for the stickers array, sticker from the stickers array, and the date from the sticker.
|
||||
const index: number = getDate(dateObj) - 1;
|
||||
const currSticker: Sticker = state.stickersMonth[index];
|
||||
|
||||
// Updating the edited status by checking if the sticker date is today's date.
|
||||
const edited = currSticker.edited
|
||||
? true
|
||||
: isSameDay(new Date(stickerDate), new Date())
|
||||
? false
|
||||
: true;
|
||||
currSticker.edited = edited;
|
||||
|
||||
// TODO: Add manually added here.
|
||||
|
||||
// Updating the id of the sticker.
|
||||
const id = format(dateObj, "yyyyddLL") + sticker;
|
||||
|
||||
// Updating the information of the sticker.
|
||||
const newSticker: Sticker = {
|
||||
id: id,
|
||||
date: stickerDate,
|
||||
sticker: sticker,
|
||||
edited: edited,
|
||||
manual: false
|
||||
};
|
||||
|
||||
state.stickersMonth[index] = newSticker;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const { addEditSticker } = stickersSlice.actions;
|
||||
export default stickersSlice.reducer;
|
||||
@@ -1,140 +0,0 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { addMonths, endOfDay } from "date-fns";
|
||||
import versionStringToNumber from "../../../lib/versionStringToNumber";
|
||||
|
||||
export interface StorageState {
|
||||
exp: string;
|
||||
version: number;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
const endOfToday: Date = endOfDay(new Date());
|
||||
|
||||
const generateExpDate = (): string => {
|
||||
return endOfDay(addMonths(endOfToday, 1)).toJSON();
|
||||
};
|
||||
|
||||
const generateVersion = (): number => {
|
||||
const versionStr: string = process.env.NEXT_PUBLIC_APP_VERSION;
|
||||
|
||||
return versionStringToNumber(versionStr);
|
||||
};
|
||||
|
||||
// * Storage Helpers * //
|
||||
|
||||
const setTempStorage = (storageState: StorageState): void => {
|
||||
sessionStorage.setItem("completedTutorial", JSON.stringify(storageState));
|
||||
};
|
||||
|
||||
const getTempStorage = (): StorageState | null => {
|
||||
return JSON.parse(sessionStorage.getItem("completedTutorial"));
|
||||
};
|
||||
|
||||
const clearTempStorage = (): void => {
|
||||
sessionStorage.removeItem("completedTutorial");
|
||||
};
|
||||
|
||||
const setStorage = (storageState: StorageState): void => {
|
||||
localStorage.setItem("completedTutorial", JSON.stringify(storageState));
|
||||
};
|
||||
|
||||
const getStorage = (): StorageState | null => {
|
||||
return JSON.parse(localStorage.getItem("completedTutorial"));
|
||||
};
|
||||
|
||||
const clearStorage = (): void => {
|
||||
localStorage.removeItem("completedTutorial");
|
||||
};
|
||||
|
||||
interface TutorialSlice {
|
||||
completedTutorial: boolean | null;
|
||||
storageState: StorageState | null;
|
||||
rememberCompleted: boolean;
|
||||
currWeek: MonthDay[] | null;
|
||||
}
|
||||
|
||||
const initialState: TutorialSlice = {
|
||||
completedTutorial: null,
|
||||
storageState: null,
|
||||
rememberCompleted: false,
|
||||
currWeek: null
|
||||
};
|
||||
|
||||
const tutorialSlice = createSlice({
|
||||
name: "Tutorial",
|
||||
initialState,
|
||||
reducers: {
|
||||
// Set temp complete
|
||||
setTempTutorialComplete(state: TutorialSlice) {
|
||||
const exp: string = generateExpDate();
|
||||
const version: number = generateVersion();
|
||||
const storageState: StorageState = {
|
||||
exp,
|
||||
version,
|
||||
completed: true
|
||||
};
|
||||
|
||||
setTempStorage(storageState);
|
||||
state.storageState = storageState;
|
||||
state.completedTutorial = true;
|
||||
},
|
||||
// Set completed (remember)
|
||||
setTutorialCompleted(state: TutorialSlice) {
|
||||
const exp: string = generateExpDate();
|
||||
const version: number = generateVersion();
|
||||
const storageState: StorageState = {
|
||||
exp,
|
||||
version,
|
||||
completed: true
|
||||
};
|
||||
|
||||
setStorage(storageState);
|
||||
state.storageState = storageState;
|
||||
state.completedTutorial = true;
|
||||
},
|
||||
// Clear states and storages
|
||||
clearTutorialCompleted(state: TutorialSlice) {
|
||||
clearTempStorage();
|
||||
clearStorage();
|
||||
state.storageState = null;
|
||||
state.completedTutorial = null;
|
||||
},
|
||||
// Get and set states
|
||||
getAndSetTutorial(state: TutorialSlice) {
|
||||
const temp = getTempStorage();
|
||||
const local = getStorage();
|
||||
|
||||
if (temp !== null || local !== null) {
|
||||
state.storageState = temp !== null ? temp : local;
|
||||
state.completedTutorial =
|
||||
temp !== null ? temp.completed : local.completed;
|
||||
}
|
||||
|
||||
if (temp === null && local === null) {
|
||||
state.completedTutorial = false;
|
||||
}
|
||||
},
|
||||
// Toggle remember completed
|
||||
toggleRememberCompleted(state: TutorialSlice) {
|
||||
const { rememberCompleted } = state;
|
||||
|
||||
state.rememberCompleted = !rememberCompleted;
|
||||
},
|
||||
// Set current week
|
||||
setCurrentWeek(state: TutorialSlice, action: PayloadAction<MonthDay[]>) {
|
||||
const { payload } = action;
|
||||
|
||||
state.currWeek = payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const {
|
||||
setTempTutorialComplete,
|
||||
setTutorialCompleted,
|
||||
clearTutorialCompleted,
|
||||
getAndSetTutorial,
|
||||
toggleRememberCompleted,
|
||||
setCurrentWeek
|
||||
} = tutorialSlice.actions;
|
||||
export default tutorialSlice.reducer;
|
||||
@@ -1,37 +0,0 @@
|
||||
import "@fontsource/montserrat/500.css";
|
||||
import "@fontsource/tilt-neon/400.css";
|
||||
import "@fontsource/anonymous-pro/400.css";
|
||||
import "@fontsource/kalam/400.css";
|
||||
import "@fontsource/anybody/400.css";
|
||||
|
||||
import type { AppProps } from "next/app";
|
||||
import React from "react";
|
||||
import { ChakraProvider } from "@chakra-ui/react";
|
||||
import AppTheme from "../theme/AppTheme";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "../redux/store";
|
||||
import Layout from "../theme/layout/Layout";
|
||||
import Head from "next/head";
|
||||
|
||||
function LCMPottyChart({ Component, pageProps }: AppProps): JSX.Element {
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<ChakraProvider theme={AppTheme}>
|
||||
<Layout {...pageProps}>
|
||||
<Head>
|
||||
<title>{"LCM Website"}</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, user-scalable=yes, initial-scale=1.0"
|
||||
/>
|
||||
</Head>
|
||||
<Provider store={store}>
|
||||
<Component {...pageProps} />
|
||||
</Provider>
|
||||
</Layout>
|
||||
</ChakraProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
export default LCMPottyChart;
|
||||
@@ -1,56 +0,0 @@
|
||||
import NextDocument, { Html, Head, Main, NextScript } from "next/document";
|
||||
import React from "react";
|
||||
import { ColorModeScript } from "@chakra-ui/react";
|
||||
import AppTheme from "../theme/AppTheme";
|
||||
|
||||
const description =
|
||||
"Official website for Lucid Creations Media. Where you can back us, donate to us, and purchase our official content such as hypno audio files.";
|
||||
|
||||
const logo = "images/logo.svg";
|
||||
const logoOG = "/images/logo.png";
|
||||
|
||||
class Document extends NextDocument {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<meta name="theme-color" content="#3138dc" />
|
||||
<link rel="icon" href={logo} sizes="32x32 192x192" />
|
||||
<link rel="apple-touch-icon" href={logo} />
|
||||
<meta property="og:title" content="Lucid Creations Media Website" />
|
||||
<meta name="og:description" content={description} />
|
||||
<meta property="og:type" content="eCommerce" />
|
||||
<meta property="og:image" content={logoOG} />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:alt" content="Lucid Creations Media Logo" />
|
||||
<meta property="og:url" content="https://lucidcreations.media" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta property="title" content="Lucid Creations Media Website" />
|
||||
<meta name="description" content={description} />
|
||||
<meta property="type" content="eCommerce" />
|
||||
<meta property="image" content={logoOG} />
|
||||
<meta property="image:type" content="image/png" />
|
||||
<meta property="image:alt" content="Lucid Creations Media Logo" />
|
||||
<meta property="url" content="https://https://lucidcreations.media" />
|
||||
<meta httpEquiv="content-language" content="en_US" />
|
||||
<meta charSet="UTF-8" />
|
||||
<meta name="keywords" content={description} />
|
||||
<meta name="copyright" content="Lucid Creations Media" />
|
||||
<meta name="page-topic" content="eCommerce" />
|
||||
<meta name="audience" content="E" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
</Head>
|
||||
<html lang="en" />
|
||||
<body>
|
||||
<ColorModeScript
|
||||
initialColorMode={AppTheme.config.initialColorMode}
|
||||
/>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Document;
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from "react";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "../redux/store";
|
||||
import { Box } from "@chakra-ui/react";
|
||||
import TempHero from "../components/hero";
|
||||
|
||||
const IndexPage = (): JSX.Element => {
|
||||
return (
|
||||
<Box textAlign="center" w="100%" h="auto" pt="50px" minWidth="min-content">
|
||||
<Provider store={store}>
|
||||
<TempHero />
|
||||
</Provider>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default IndexPage;
|
||||
@@ -1,5 +0,0 @@
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
|
||||
import { RootState, AppDispatch } from "./store";
|
||||
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
@@ -1,15 +0,0 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import calenderReducer from "../features/calender";
|
||||
import stickersReducer from "../features/calender/stickers";
|
||||
import tutorialReducer from "../features/tutorial";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
calender: calenderReducer,
|
||||
stickers: stickersReducer,
|
||||
tutorial: tutorialReducer
|
||||
}
|
||||
});
|
||||
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
@@ -1,69 +0,0 @@
|
||||
import { extendTheme, ThemeConfig } from "@chakra-ui/react";
|
||||
// import { createBreakpoints } from "@chakra-ui/theme-tools";
|
||||
import "@fontsource/montserrat";
|
||||
import "@fontsource/tilt-neon";
|
||||
import "@fontsource/anonymous-pro";
|
||||
import "@fontsource/kalam";
|
||||
import "@fontsource/anybody";
|
||||
import buttons from "./components/buttonStyles";
|
||||
|
||||
const config: ThemeConfig = {
|
||||
initialColorMode: "dark",
|
||||
useSystemColorMode: false
|
||||
};
|
||||
|
||||
// const breakpoints = createBreakpoints({
|
||||
// sm: "30em",
|
||||
// md: "48em",
|
||||
// lg: "75em",
|
||||
// xl: "85em",
|
||||
// "2xl": "100em",
|
||||
// });
|
||||
|
||||
const fonts = {
|
||||
heading: `'Tilt Neon', system-ui`,
|
||||
body: `'Montserrat', sans-serif`,
|
||||
mono: `'Anonymous Pro', monospace`,
|
||||
brand: `'Kalam', cursive`,
|
||||
LCM: `'Anybody', system-ui`
|
||||
};
|
||||
|
||||
const AppTheme = extendTheme({
|
||||
config,
|
||||
colors: {
|
||||
brand: {
|
||||
main: "#3138dc",
|
||||
primary: "#0068ff",
|
||||
secondary: "#0086ff",
|
||||
cosmic: "#314a9e",
|
||||
hover: "#00aec1",
|
||||
warning: "#ffbd48",
|
||||
danger: "#FC8181",
|
||||
valid: "#00c17c",
|
||||
footer: "#0097a7",
|
||||
footerText: "black",
|
||||
content: "#2d3748",
|
||||
kofi: "#FF5E5B"
|
||||
},
|
||||
loading: {
|
||||
overlayBg: "#171923cb",
|
||||
spinnerColor: "#0088ff",
|
||||
spinnerEmptySpace: "#2D374860"
|
||||
}
|
||||
},
|
||||
styles: {
|
||||
global: {
|
||||
body: {
|
||||
bg: "gray.900"
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Button: buttons
|
||||
},
|
||||
fonts
|
||||
// breakpoints,
|
||||
});
|
||||
|
||||
export default AppTheme;
|
||||
export { fonts };
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Heading, Text } from "@chakra-ui/react";
|
||||
import React from "react";
|
||||
import { fonts } from "../AppTheme";
|
||||
|
||||
interface BrandTextProps {
|
||||
type: "Heading" | "Text";
|
||||
text: string;
|
||||
headerLevel?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
||||
size?: string;
|
||||
}
|
||||
|
||||
const BrandText = ({
|
||||
type,
|
||||
text,
|
||||
headerLevel,
|
||||
size
|
||||
}: BrandTextProps): JSX.Element => {
|
||||
return type === "Heading" ? (
|
||||
<Heading fontFamily={fonts.brand} fontSize={size} as={headerLevel}>
|
||||
{text}
|
||||
</Heading>
|
||||
) : (
|
||||
<Text fontFamily={fonts.brand} fontSize={size}>
|
||||
{text}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
export default BrandText;
|
||||
@@ -1,177 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { darken, mode, whiten } from "@chakra-ui/theme-tools";
|
||||
import { Dict } from "@chakra-ui/utils";
|
||||
|
||||
const buttonStyles = {
|
||||
// style object for base or default style
|
||||
baseStyle: {},
|
||||
// styles for different sizes ("sm", "md", "lg")
|
||||
sizes: {},
|
||||
// styles for different visual variants ("outline", "solid")
|
||||
variants: {
|
||||
primary: (props: Dict<never>) => ({
|
||||
bg: "brand.primary",
|
||||
fontSize: "xl",
|
||||
py: 3,
|
||||
px: 4,
|
||||
color: "whiteAlpha",
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.primary", 20),
|
||||
darken("brand.primary", 20)
|
||||
)(props)
|
||||
}
|
||||
}),
|
||||
secondary: (props: Dict<never>) => ({
|
||||
bg: "brand.secondary",
|
||||
fontSize: "xl",
|
||||
py: 3,
|
||||
px: 4,
|
||||
color: "whiteAlpha",
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.secondary", 20),
|
||||
darken("brand.secondary", 20)
|
||||
)(props)
|
||||
}
|
||||
}),
|
||||
skip: (props: Dict<never>) => ({
|
||||
bg: "transparent",
|
||||
fontSize: "xl",
|
||||
py: 3,
|
||||
px: 4,
|
||||
color: "whiteAlpha.800",
|
||||
_hover: {
|
||||
bg: mode(whiten("brand.danger", 20), darken("brand.danger", 20))(props),
|
||||
color: "whiteAlpha.900"
|
||||
}
|
||||
}),
|
||||
stickerButton: (props: Dict<never>) => ({
|
||||
bg: "transparent",
|
||||
fontSize: "4rem",
|
||||
px: 2,
|
||||
py: 14,
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.secondary", 20),
|
||||
darken("brand.secondary", 20)
|
||||
)(props)
|
||||
}
|
||||
}),
|
||||
nav: (props: Dict<never>) => ({
|
||||
bg: "transparent",
|
||||
fontSize: "md",
|
||||
px: 2,
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.secondary", 20),
|
||||
darken("brand.secondary", 20)
|
||||
)(props)
|
||||
}
|
||||
}),
|
||||
stickyNav: (/* props: Dict<never> | StyleFunctionProps */) => ({
|
||||
bg: "transparent",
|
||||
fontSize: "md",
|
||||
px: 2,
|
||||
_hover: {
|
||||
textDecoration: "underline"
|
||||
}
|
||||
}),
|
||||
footer: (props: Dict<never>) => ({
|
||||
bg: "brand.main",
|
||||
fontSize: "lg",
|
||||
py: 3,
|
||||
px: 4,
|
||||
color: "whiteAlpha",
|
||||
_hover: {
|
||||
bg: mode(whiten("brand.main", 20), darken("brand.main", 20))(props)
|
||||
}
|
||||
}),
|
||||
backToTop: (props: Dict<never>) => ({
|
||||
bg: "rgba(23, 25, 35, 0.5)",
|
||||
fontSize: "lg",
|
||||
py: 2,
|
||||
px: 4,
|
||||
color: "rgba(0, 134, 255, 0.6)",
|
||||
boxShadow:
|
||||
"rgba(0, 134, 255, 0.05) 0px 0px 15px, rgba(0, 134, 255, 0.1) 0px 0px 3px 1px",
|
||||
border: "1px solid rgba(0, 134, 255, 0.15)",
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.secondary", 20),
|
||||
darken("brand.secondary", 20)
|
||||
)(props),
|
||||
boxShadow:
|
||||
"rgba(0, 104, 255, 0.5) 0px 0px 15px, rgba(0, 104, 255, 0.3) 0px 0px 3px 1px",
|
||||
color: "whiteAlpha.900",
|
||||
border: "1px solid rgba(0, 134, 255, 1)"
|
||||
}
|
||||
}),
|
||||
submit: (props: Dict<never>) => ({
|
||||
fontSize: "lg",
|
||||
py: 2,
|
||||
px: 4,
|
||||
type: "submit",
|
||||
_hover: {
|
||||
color: "whiteAlpha.900",
|
||||
bg: mode(whiten("brand.valid", 20), darken("brand.valid", 20))(props),
|
||||
_disabled: {
|
||||
color: mode(
|
||||
whiten("brand.danger", 20),
|
||||
darken("brand.danger", 20)
|
||||
)(props),
|
||||
boxShadow:
|
||||
"rgba(252, 129, 129, .95) 0px 0px 15px, rgba(252, 129, 129, 0.75) 0px 0px 3px 1px",
|
||||
border: "1px solid #FC8181"
|
||||
}
|
||||
}
|
||||
}),
|
||||
mobileNav: (props: Dict<never>) => ({
|
||||
// bg: "transparent",
|
||||
fontSize: "md",
|
||||
px: 2,
|
||||
boxShadow:
|
||||
"rgba(0, 134, 255, 0.30) 0px 0px 15px, rgba(0, 134, 255, 0.15) 0px 0px 3px 1px",
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.secondary", 20),
|
||||
darken("brand.secondary", 20)
|
||||
)(props),
|
||||
boxShadow:
|
||||
"rgba(0, 134, 255, 0.5) 0px 0px 15px, rgba(0, 134, 255, 0.3) 0px 0px 3px 1px"
|
||||
},
|
||||
_expanded: {
|
||||
bg: "brand.primary",
|
||||
boxShadow:
|
||||
"rgba(0, 134, 255, 0.5) 0px 0px 15px, rgba(0, 134, 255, 0.3) 0px 0px 3px 1px",
|
||||
border: "1px solid #0068ff"
|
||||
}
|
||||
}),
|
||||
kofi: (props: Dict<never>) => ({
|
||||
bg: "brand.kofi",
|
||||
fontSize: "lg",
|
||||
p: 3,
|
||||
color: "whiteAlpha",
|
||||
_hover: {
|
||||
bg: mode(whiten("brand.kofi", 20), darken("brand.kofi", 20))(props)
|
||||
}
|
||||
}),
|
||||
twitter: (props: Dict<never>) => ({
|
||||
bg: "brand.twitter",
|
||||
fontSize: "lg",
|
||||
py: 3,
|
||||
px: 4,
|
||||
color: "whiteAlpha",
|
||||
_hover: {
|
||||
bg: mode(
|
||||
whiten("brand.twitter", 20),
|
||||
darken("brand.twitter", 20)
|
||||
)(props)
|
||||
}
|
||||
})
|
||||
},
|
||||
// default values for `size` and `variant`
|
||||
defaultProps: {}
|
||||
};
|
||||
|
||||
export default buttonStyles;
|
||||
@@ -1,32 +0,0 @@
|
||||
import React, { FC } from "react";
|
||||
import { Button, Flex, Link } from "@chakra-ui/react";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
interface BackToTopButtonProps {
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
const BackToTopButton: FC<BackToTopButtonProps> = ({
|
||||
show
|
||||
}: BackToTopButtonProps) => {
|
||||
return (
|
||||
<Flex
|
||||
display={show ? "flex" : "none"}
|
||||
pos="fixed"
|
||||
top="85vh"
|
||||
right={{
|
||||
base: "1.25rem",
|
||||
sm: "2rem",
|
||||
md: "3rem"
|
||||
}}
|
||||
>
|
||||
<Link href="/#top">
|
||||
<Button variant="backToTop">
|
||||
<Icon icon="akar-icons:chevron-up" />
|
||||
</Button>
|
||||
</Link>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackToTopButton;
|
||||
@@ -1,31 +0,0 @@
|
||||
import React from "react";
|
||||
import { Button, HStack, Link, Text } from "@chakra-ui/react";
|
||||
import navItems, { NavItem } from "./navItems";
|
||||
|
||||
const DesktopNav = (): JSX.Element => {
|
||||
return (
|
||||
<HStack
|
||||
as="nav"
|
||||
display={{ base: "none", lg: "flex" }}
|
||||
h="auto"
|
||||
w="auto"
|
||||
spacing={4}
|
||||
// m="auto"
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
{navItems.map((navItem: NavItem) => {
|
||||
return (
|
||||
<Link id={"dekstop-" + navItem[0]} key={navItem[0]} href={navItem[1]}>
|
||||
<Button variant="nav">
|
||||
<Text>{navItem[0]}</Text>
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default DesktopNav;
|
||||
@@ -1,37 +0,0 @@
|
||||
import React /*, { useEffect, useRef, useState }*/ from "react";
|
||||
import { Box, Text, VStack, Link } from "@chakra-ui/react";
|
||||
// import BackToTopButton from "./BackToTopButton";
|
||||
import Buttons from "../../components/buttons";
|
||||
|
||||
const Footer = (): JSX.Element => {
|
||||
return (
|
||||
<Box bg="brand.footer" as="footer" w="100%" h="auto">
|
||||
{/* <BackToTopButton show={showBackToTop} /> */}
|
||||
<VStack
|
||||
h="auto"
|
||||
w="auto"
|
||||
py={12}
|
||||
spacing={5}
|
||||
justifyItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<VStack spacing={4}>
|
||||
<Buttons />
|
||||
<Text color="brand.footerText" fontSize="xs">
|
||||
©
|
||||
{` 2021 - ${new Date().getFullYear()} `}
|
||||
<Link
|
||||
href="https://lucidcreations.media"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{"Lucid Creations Media"}
|
||||
</Link>
|
||||
</Text>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
@@ -1,195 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
Heading,
|
||||
HStack,
|
||||
Box,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuButton
|
||||
} from "@chakra-ui/react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import DesktopNav from "./DesktopNav";
|
||||
import MobileNav from "./MobileNav";
|
||||
import appLogo from "../../../public/images/logo.svg";
|
||||
import { fonts } from "../AppTheme";
|
||||
|
||||
const Header = (): JSX.Element => {
|
||||
const appName = "Lucid Creations Media";
|
||||
const appVersion = process.env.NEXT_PUBLIC_APP_VERSION_HEADER || "";
|
||||
|
||||
// Add transparency while not at the top of the page.
|
||||
const [transparentNavbar, setTransparentNavbar] = useState<boolean>(false);
|
||||
const lastScroll = useRef<number>(0);
|
||||
|
||||
const handleScroll = (): void => {
|
||||
// Sticky Nav
|
||||
if (window.scrollY >= 20) {
|
||||
setTransparentNavbar(true);
|
||||
} else {
|
||||
setTransparentNavbar(false);
|
||||
}
|
||||
|
||||
// Scroll Position.
|
||||
const currentScroll =
|
||||
window.scrollY || window.pageYOffset || document.body.scrollTop;
|
||||
|
||||
// Update Scroll Position Reference
|
||||
lastScroll.current = currentScroll <= 0 ? 0 : currentScroll;
|
||||
// setScroll(lastScroll.current = currentScroll <= 0 ? 0 : currentScroll)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!window) {
|
||||
console.log("waiting for mount");
|
||||
} else if (window) {
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
}
|
||||
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, []);
|
||||
|
||||
// Mobile Menu Icon && Open/Close
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [hover, setHover] = useState<boolean>(false);
|
||||
|
||||
const menuIcon = (): JSX.Element => {
|
||||
const iconType = {
|
||||
default: <Icon icon="bx:bx-menu-alt-right" />,
|
||||
hover: <Icon icon="bx:bx-menu" />,
|
||||
open: <Icon icon="bx:bx-x" />
|
||||
};
|
||||
|
||||
if (open) {
|
||||
return iconType.open;
|
||||
} else if (hover) {
|
||||
return iconType.hover;
|
||||
} else {
|
||||
return iconType.default;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
zIndex={1}
|
||||
w="100%"
|
||||
pos="fixed"
|
||||
top={0}
|
||||
alignItems="center"
|
||||
boxShadow={
|
||||
open
|
||||
? "none"
|
||||
: "rgba(0, 134, 255, 0.75) 0px 0px 15px, rgba(0, 134, 255, 0.5) 0px 0px 3px 1px"
|
||||
}
|
||||
bg={
|
||||
open
|
||||
? "brand.main"
|
||||
: transparentNavbar
|
||||
? "rgba(49, 56, 220, 0.9)"
|
||||
: "brand.main"
|
||||
}
|
||||
transition=".5s ease"
|
||||
borderRadius="0px 0px 10px 10px"
|
||||
_hover={{
|
||||
bg: "brand.main",
|
||||
boxShadow: open
|
||||
? "none"
|
||||
: "rgba(0, 134, 255, 0.9) 0px 0px 15px, rgba(0, 134, 255, 0.7) 0px 0px 3px 1px"
|
||||
}}
|
||||
h={open ? "125px" : "auto"}
|
||||
>
|
||||
{/* Logo | Site Name */}
|
||||
<HStack
|
||||
display={{ base: "flex", lg: "none" }}
|
||||
position="absolute"
|
||||
width="100%"
|
||||
height={12}
|
||||
top={0}
|
||||
ml={4}
|
||||
spacing="5px"
|
||||
justifyContent={{
|
||||
base: "flex-start",
|
||||
sm: "center"
|
||||
}}
|
||||
alignItems="center"
|
||||
_hover={{
|
||||
cursor: "default"
|
||||
}}
|
||||
>
|
||||
<Image height="30" width="30" src={appLogo} alt="App Logo" />
|
||||
|
||||
<Heading as="h1" size="md" fontFamily={fonts.LCM} fontWeight="400">
|
||||
{appName}
|
||||
</Heading>
|
||||
<Heading color="whiteAlpha.500" as="h2" size="sm">
|
||||
{appVersion}
|
||||
</Heading>
|
||||
</HStack>
|
||||
|
||||
{/* Desktop Nav Items and Mobile Menu Button */}
|
||||
<HStack
|
||||
w="100%"
|
||||
px={4}
|
||||
h={12}
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<HStack
|
||||
w="100%"
|
||||
h="auto"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Box w="auto" display={{ base: "flex", lg: "none " }}></Box>
|
||||
<Box w="100%" display={{ base: "none", lg: "flex" }} m="auto">
|
||||
<HStack
|
||||
width="100%"
|
||||
alignItems="center"
|
||||
height="auto"
|
||||
spacing="5px"
|
||||
_hover={{
|
||||
cursor: "default"
|
||||
}}
|
||||
>
|
||||
<Image height="30" width="30" src={appLogo} alt="App Logo" />
|
||||
<Heading
|
||||
as="h1"
|
||||
size="md"
|
||||
fontFamily={fonts.LCM}
|
||||
fontWeight="400"
|
||||
>
|
||||
{appName}
|
||||
</Heading>
|
||||
<Heading color="whiteAlpha.500" as="h2" size="sm">
|
||||
{appVersion}
|
||||
</Heading>
|
||||
</HStack>
|
||||
</Box>
|
||||
<DesktopNav />
|
||||
</HStack>
|
||||
<Menu isLazy lazyBehavior="unmount" isOpen={open}>
|
||||
<MenuButton
|
||||
id="mobile-menu-button"
|
||||
as={IconButton}
|
||||
aria-label="Mobile Menu"
|
||||
icon={menuIcon()}
|
||||
display={{
|
||||
base: "inline-flex",
|
||||
lg: "none"
|
||||
}}
|
||||
bg={transparentNavbar ? "transparent" : "rgba(255, 255, 255, .15)"}
|
||||
border={transparentNavbar ? "1px solid #0068ff" : "none"}
|
||||
variant="mobileNav"
|
||||
type="button"
|
||||
onClick={() => setOpen(!open)}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => setHover(false)}
|
||||
/>
|
||||
<MobileNav updateOpen={setOpen} />
|
||||
</Menu>
|
||||
</HStack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -1,24 +0,0 @@
|
||||
import React, { FC, ReactNode } from "react";
|
||||
import type { AppProps } from "next/app";
|
||||
import Header from "../layout/Header";
|
||||
import { Box } from "@chakra-ui/layout";
|
||||
import Footer from "./Footer";
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode;
|
||||
elementType?: string;
|
||||
}
|
||||
|
||||
const Layout: FC<LayoutProps> = (
|
||||
{ children }: LayoutProps,
|
||||
{ pageProps }: AppProps
|
||||
) => {
|
||||
return (
|
||||
<Box w="100%">
|
||||
<Header {...pageProps} />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default Layout;
|
||||
@@ -1,57 +0,0 @@
|
||||
import React, { FC, Fragment } from "react";
|
||||
import {
|
||||
Button,
|
||||
Link,
|
||||
MenuDivider,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
Text
|
||||
} from "@chakra-ui/react";
|
||||
import navItems, { NavItem } from "./navItems";
|
||||
|
||||
interface MobileNavProps {
|
||||
updateOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const MobileNav: FC<MobileNavProps> = ({ updateOpen }: MobileNavProps) => {
|
||||
return (
|
||||
<MenuList
|
||||
as="nav"
|
||||
display={{ base: "block", lg: "none" }}
|
||||
h="auto"
|
||||
w="100%"
|
||||
p={0}
|
||||
border="none"
|
||||
boxShadow="none"
|
||||
bg="brand.main"
|
||||
>
|
||||
{navItems.map((navItem: NavItem, index: number) => {
|
||||
return (
|
||||
<MenuItem
|
||||
id={"mobile-" + navItem[0]}
|
||||
key={navItem[0]}
|
||||
w="auto"
|
||||
h="auto"
|
||||
p={0}
|
||||
_hover={{
|
||||
backgroundColor: "none"
|
||||
}}
|
||||
_focus={{
|
||||
backgroundColor: "none"
|
||||
}}
|
||||
>
|
||||
<Link onClick={() => updateOpen(false)} href={navItem[1]}>
|
||||
{index === 0 ? <MenuDivider /> : <Fragment></Fragment>}
|
||||
<Button w="100vw" variant={"nav"} p={0} m="auto">
|
||||
<Text>{navItem[0]}</Text>
|
||||
</Button>
|
||||
<MenuDivider />
|
||||
</Link>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</MenuList>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileNav;
|
||||
@@ -1,6 +0,0 @@
|
||||
export type NavItem = [string, string];
|
||||
export type NavItems = NavItem[];
|
||||
|
||||
const navItems: NavItems = [["Home", "/"]];
|
||||
|
||||
export default navItems;
|
||||
Reference in New Issue
Block a user