From 2718942321e1b6188cc03b481912c7ecb473803e Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 25 Jan 2023 14:33:53 -0800 Subject: [PATCH] Move static page modals to a standalone page This will make it easier to whisk people here in notices --- components/AboutPage/index.scss | 11 ++ components/AboutPage/index.tsx | 165 ++++++++++++++++++++++++++++ components/ChangelogPage/index.scss | 64 +++++++++++ components/ChangelogPage/index.tsx | 122 ++++++++++++++++++++ components/RoadmapPage/index.scss | 108 ++++++++++++++++++ components/RoadmapPage/index.tsx | 73 ++++++++++++ pages/about.tsx | 150 +++++++++++++++++++++++++ public/locales/en/common.json | 7 ++ public/locales/ja/common.json | 7 ++ styles/globals.scss | 80 ++++++++++++++ utils/enums.tsx | 6 + 11 files changed, 793 insertions(+) create mode 100644 components/AboutPage/index.scss create mode 100644 components/AboutPage/index.tsx create mode 100644 components/ChangelogPage/index.scss create mode 100644 components/ChangelogPage/index.tsx create mode 100644 components/RoadmapPage/index.scss create mode 100644 components/RoadmapPage/index.tsx create mode 100644 pages/about.tsx diff --git a/components/AboutPage/index.scss b/components/AboutPage/index.scss new file mode 100644 index 00000000..38d21a98 --- /dev/null +++ b/components/AboutPage/index.scss @@ -0,0 +1,11 @@ +.About.PageContent { + .Links { + display: grid; + gap: $unit; + margin: $unit-2x 0; + } + + div.LinkItem { + margin-top: $unit-2x; + } +} diff --git a/components/AboutPage/index.tsx b/components/AboutPage/index.tsx new file mode 100644 index 00000000..0e3c546b --- /dev/null +++ b/components/AboutPage/index.tsx @@ -0,0 +1,165 @@ +import React from 'react' +import Link from 'next/link' + +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import ShareIcon from '~public/icons/Share.svg' +import DiscordIcon from '~public/icons/discord.svg' +import GithubIcon from '~public/icons/github.svg' + +import './index.scss' + +interface Props {} + +const AboutPage: React.FC = (props: Props) => { + const { t: common } = useTranslation('common') + return ( +
+

{common('about.segmented_control.about')}

+
+

+ Granblue.team is a tool to save and share team comps for{' '} + + Granblue Fantasy + + . +

+

+ Start adding to a team and a URL will be created for you to share + wherever you like, no account needed. +

+

+ However, if you do make an account, you can save any teams you find + for future reference and keep all of your teams together in one place. +

+
+ +
+

Feedback

+

+ This is an evolving project so feedback and suggestions are greatly + appreciated! +

+

+ If you have a feature request, would like to report a bug, or are + enjoying the tool and want to say thanks, come hang out in Discord! +

+
+ + +
+ +

granblue-tools

+
+ +
+ +
+
+ +
+

Credits

+

+ Granblue.team was built by{' '} + + @jedmund + {' '} + with a lot of help from{' '} + + @lalalalinna + {' '} + and{' '} + + @tarngerine + + . +

+

+ Many thanks also go to Disinfect, Slipper, Jif, Bless, 9highwind, and + everyone else in{' '} + + Fireplace + {' '} + that helped with bug testing and feature requests. (P.S. We're + recruiting!) And yoey, but he won't join our crew. +

+
+ +
+

Contributing

+

+ This app is open source and licensed under{' '} + + GNU AGPLv3 + + . Plainly, that means you can download the source, modify it, and + redistribute it if you attribute this project, use the same license, + and keep it open source. You can contribute on Github. +

+ +
+
+ ) +} + +export default AboutPage diff --git a/components/ChangelogPage/index.scss b/components/ChangelogPage/index.scss new file mode 100644 index 00000000..b8c6b9d0 --- /dev/null +++ b/components/ChangelogPage/index.scss @@ -0,0 +1,64 @@ +.Changelog.PageContent { + .version { + &.content { + .top h3 { + color: var(--accent-yellow); + } + + .update { + display: flex; + flex-direction: column; + gap: $unit-2x; + } + + .characters, + .weapons, + .summons { + display: grid; + grid-template-rows: 1fr auto; + gap: $unit; + + & > h4 { + font-weight: $medium; + font-size: $font-regular; + } + } + + .items { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: $unit-4x; + } + } + + .top { + align-items: baseline; + display: flex; + gap: $unit-half; + margin-bottom: $unit-2x; + + h3 { + color: var(--accent-blue); + font-weight: $medium; + font-size: $font-large; + } + + time { + color: var(--text-secondary); + font-size: $font-small; + font-weight: $medium; + } + } + } + + .notes { + color: var(--text-primary); + list-style-type: disc; + list-style-position: inside; + + li { + margin-bottom: $unit-half; + font-size: $font-regular; + } + } +} diff --git a/components/ChangelogPage/index.tsx b/components/ChangelogPage/index.tsx new file mode 100644 index 00000000..67408f8f --- /dev/null +++ b/components/ChangelogPage/index.tsx @@ -0,0 +1,122 @@ +import React from 'react' + +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import ChangelogUnit from '~components/ChangelogUnit' + +import './index.scss' + +interface Props {} + +const ChangelogPage: React.FC = (props: Props) => { + const { t: common } = useTranslation('common') + return ( +
+

{common('about.segmented_control.changelog')}

+
+
+

1.0.1

+ +
+
    +
  • Extra party fields: Full Auto, Clear Time, and more
  • +
  • Support for Youtube short URLs
  • +
  • Responsive grids and lots of other mobile fixes
  • +
  • Many other bug fixes
  • +
+
+
+
+

2022-12 Legend Festival

+ +
+
+
+

New characters

+
+ + + +
+
+
+

New weapons

+
+ + + +
+
+
+

New summons

+
+ +
+
+
+
+
+
+

2022-12 Flash Gala

+ +
+
+
+

New characters

+
+ + +
+
+
+

New weapons

+
+ + +
+
+
+
+
+
+

1.0.0

+ +
+
    +
  • First release!
  • +
  • You can embed Youtube videos now
  • +
  • Better clicking - right-click and open in a new tab
  • +
  • Manually set dark mode in Account Settings
  • +
  • Lots of bugs squashed
  • +
+
+
+ ) +} + +export default ChangelogPage diff --git a/components/RoadmapPage/index.scss b/components/RoadmapPage/index.scss new file mode 100644 index 00000000..2c106d30 --- /dev/null +++ b/components/RoadmapPage/index.scss @@ -0,0 +1,108 @@ +.Roadmap.PageContent { + h3.priority { + font-weight: $medium; + font-size: $font-large; + margin-bottom: $unit-4x; + + &.in_progress { + color: $yellow; + } + + &.high { + color: $red; + } + + &.mid { + color: $orange-10; + } + + &.low { + color: $blue; + } + } + + .notes { + display: flex; + flex-direction: column; + gap: $unit; + margin-bottom: $unit-2x; + + p { + margin-bottom: $unit; + } + + .LinkItem { + $diameter: $unit-6x; + border: 1px solid var(--link-item-bg); + border-radius: $card-corner; + + &:hover { + background-color: var(--link-item-bg); + + svg { + fill: var(--link-item-image-color-hover); + } + } + + a { + display: flex; + padding: $unit-2x; + + &:hover { + text-decoration: none; + } + + .Left { + align-items: center; + display: flex; + gap: $unit-2x; + flex-grow: 1; + } + + svg { + fill: var(--link-item-image-color); + width: $diameter; + height: auto; + + &.ShareIcon { + width: $unit-4x; + } + } + } + + h3 { + font-weight: $bold; + max-width: 70%; + line-height: 1.3; + } + } + } + + p { + color: var(--text-secondary); + + font-size: $font-regular; + line-height: 1.3; + } + + ul { + color: var(--text-primary); + list-style-type: none; + + li { + display: flex; + flex-direction: column; + gap: $unit; + margin-bottom: $unit-2x; + + h4 { + font-size: $font-medium; + font-weight: $bold; + } + + p { + font-size: $font-regular; + } + } + } +} diff --git a/components/RoadmapPage/index.tsx b/components/RoadmapPage/index.tsx new file mode 100644 index 00000000..e9fbab81 --- /dev/null +++ b/components/RoadmapPage/index.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import Link from 'next/link' + +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' + +import ShareIcon from '~public/icons/Share.svg' +import GithubIcon from '~public/icons/github.svg' + +import './index.scss' + +interface Props {} + +const RoadmapPage: React.FC = (props: Props) => { + const { t: common } = useTranslation('common') + const { t: roadmap } = useTranslation('roadmap') + return ( +
+

{common('about.segmented_control.roadmap')}

+
+

{roadmap('blurb')}

+

{roadmap('link.intro')}

+ +
+ +
+

{roadmap('subtitle')}

+
    +
  • +

    {roadmap('roadmap.item1.title')}

    +

    {roadmap('roadmap.item1.description')}

    +
  • +
  • +

    {roadmap('roadmap.item2.title')}

    +

    {roadmap('roadmap.item2.description')}

    +
  • +
  • +

    {roadmap('roadmap.item3.title')}

    +

    {roadmap('roadmap.item3.description')}

    +
  • +
  • +

    {roadmap('roadmap.item4.title')}

    +

    {roadmap('roadmap.item4.description')}

    +
  • +
  • +

    {roadmap('roadmap.item5.title')}

    +

    {roadmap('roadmap.item5.description')}

    +
  • +
  • +

    {roadmap('roadmap.item6.title')}

    +

    {roadmap('roadmap.item6.description')}

    +
  • +
+
+
+ ) +} + +export default RoadmapPage diff --git a/pages/about.tsx b/pages/about.tsx new file mode 100644 index 00000000..5e72c494 --- /dev/null +++ b/pages/about.tsx @@ -0,0 +1,150 @@ +import React, { useCallback, useEffect, useState } from 'react' +import Head from 'next/head' + +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' + +import api from '~utils/api' +import { printError } from '~utils/reportError' +import { AboutTabs } from '~utils/enums' +import setUserToken from '~utils/setUserToken' + +import AboutPage from '~components/AboutPage' +import ChangelogPage from '~components/ChangelogPage' +import RoadmapPage from '~components/RoadmapPage' +import SegmentedControl from '~components/SegmentedControl' +import Segment from '~components/Segment' + +import type { NextApiRequest, NextApiResponse } from 'next' + +interface Props {} + +const AboutRoute: React.FC = (props: Props) => { + // Set up router + const router = useRouter() + + // Import translations + const { t } = useTranslation('common') + + const [currentTab, setCurrentTab] = useState(AboutTabs.About) + + function handleTabClicked(event: React.ChangeEvent) { + const path = [ + router.asPath.split('/').filter((el) => el != '')[1], + event.target.value, + ].join('/') + + // TODO: Decide if we want /about/changlog or /changelog + // TODO: Then, set up Next.js rewrites + switch (event.target.value) { + case 'about': + // router.replace(path) + setCurrentTab(AboutTabs.About) + break + case 'changelog': + // router.replace(path) + setCurrentTab(AboutTabs.Changelog) + break + case 'roadmap': + // router.replace(path) + setCurrentTab(AboutTabs.Roadmap) + break + default: + break + } + } + + const currentSection = () => { + switch (currentTab) { + case AboutTabs.About: + return + case AboutTabs.Changelog: + return + case AboutTabs.Roadmap: + return + } + } + + return ( +
+ + {/* HTML */} + {t('page.titles.about')} + + + + {/* OpenGraph */} + + + + + + {/* Twitter */} + + + + + + +
+ + + {t('about.segmented_control.about')} + + + {t('about.segmented_control.changelog')} + + + {t('about.segmented_control.roadmap')} + + + {currentSection()} +
+
+ ) +} + +export const getServerSidePaths = async () => { + return { + paths: [], + fallback: true, + } +} + +// prettier-ignore +export const getServerSideProps = async ({ req, res, locale, query }: { req: NextApiRequest, res: NextApiResponse, locale: string, query: { [index: string]: string } }) => { + // Set headers for server-side requests + setUserToken(req, res) + + // Fetch and organize raids + return { + props: { + ...(await serverSideTranslations(locale, ['common', 'roadmap'])), + // Will be passed to the page component as props + }, + } +} + +export default AboutRoute diff --git a/public/locales/en/common.json b/public/locales/en/common.json index e97072a2..8b3e1726 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1,4 +1,11 @@ { + "about": { + "segmented_control": { + "about": "About", + "changelog": "Updates", + "roadmap": "Roadmap" + } + }, "alert": { "incompatible_weapon": "You've selected a weapon that can't be added to the Additional Weapon slots." }, diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index c0a355a6..b06ff237 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -1,4 +1,11 @@ { + "about": { + "segmented_control": { + "about": "サイトについて", + "changelog": "変更ログ", + "roadmap": "ロードマップ" + } + }, "alert": { "incompatible_weapon": "Additional Weaponsに装備できない武器を入れました。" }, diff --git a/styles/globals.scss b/styles/globals.scss index 31f35573..a0ee06fe 100644 --- a/styles/globals.scss +++ b/styles/globals.scss @@ -119,6 +119,86 @@ select { } } +.PageContent { + display: flex; + flex-direction: column; + gap: $unit-4x; + max-width: $grid-width; + margin: $unit-4x auto 0; + + h1 { + font-size: $font-xxlarge; + text-align: left; + } + + h2 { + font-size: $font-medium; + font-weight: $medium; + margin-bottom: $unit * 3; + } + + p { + color: var(--text-secondary); + font-size: $font-regular; + line-height: 1.3; + margin-bottom: $unit; + + &:last-of-type { + margin-bottom: 0; + } + } + + .LinkItem { + $diameter: $unit-6x; + border: 1px solid var(--link-item-bg); + border-radius: $card-corner; + + &:hover { + background-color: var(--link-item-bg); + + svg { + fill: var(--link-item-image-color-hover); + } + } + + a { + display: flex; + padding: $unit-2x; + + &:hover { + text-decoration: none; + } + + .Left { + align-items: center; + display: flex; + gap: $unit-2x; + flex-grow: 1; + + h3 { + font-weight: 600; + max-width: 70%; + line-height: 1.3; + } + } + + svg { + fill: var(--link-item-image-color); + width: $diameter; + height: auto; + + &.ShareIcon { + width: $unit-4x; + } + } + } + + h3 { + font-weight: $bold; + } + } +} + .Hovercard { background: #222; border-radius: $unit; diff --git a/utils/enums.tsx b/utils/enums.tsx index 54bef6c1..517e2792 100644 --- a/utils/enums.tsx +++ b/utils/enums.tsx @@ -19,3 +19,9 @@ export enum TeamElement { Dark, Light, } + +export enum AboutTabs { + About, + Changelog, + Roadmap, +}