1
0
Fork 0

wip: Implemented welcome pages

This commit is contained in:
joostdecock 2024-12-24 16:34:26 +01:00
parent f548e1ed8f
commit 54d8550683
20 changed files with 315 additions and 71 deletions

View file

@ -12,8 +12,10 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { SaveIcon } from '@freesewing/react/components/Icon'
import { SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { PassiveImageInput } from '@freesewing/react/components/Input'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
/*
* Component for the account/bio page
@ -67,10 +69,13 @@ export const Avatar = ({ welcome = false, Link = false }) => {
/>
{welcome ? (
<>
<button className={`btn btn-secondary mt-4 px-8`} onClick={save} disabled={!img}>
{t('save')}
</button>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton onClick={save} btnProps={{ disabled: !img }}>
<SaveIcon />
Save
</IconButton>
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account.control].length > 0 ? (
<>
<progress
@ -81,7 +86,7 @@ export const Avatar = ({ welcome = false, Link = false }) => {
<span className="pt-4 text-sm font-bold opacity-50">
7 / {welcomeSteps[account.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account.control].slice(0, 6)}
todo={welcomeSteps[account.control].slice(7)}
current="img"

View file

@ -11,8 +11,10 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { SaveIcon } from '@freesewing/react/components/Icon'
import { SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { MarkdownInput } from '@freesewing/react/components/Input'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
/*
* Component for the account/bio page
@ -60,18 +62,20 @@ export const Bio = ({ welcome = false, Link = false }) => {
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account.control].length > 0 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={600 / welcomeSteps[account.control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
6 / {welcomeSteps[account.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account.control].slice(0, 5)}
todo={welcomeSteps[account.control].slice(6)}
current="bio"

View file

@ -11,8 +11,10 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { NoIcon, OkIcon, SaveIcon } from '@freesewing/react/components/Icon'
import { NoIcon, OkIcon, SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { ListInput } from '@freesewing/react/components/Input'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
const strings = {
yes: {
@ -91,18 +93,20 @@ export const Compare = ({ welcome = false }) => {
/>
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account?.control].length > 0 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={400 / welcomeSteps[account?.control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
4 / {welcomeSteps[account?.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account?.control].slice(0, 3)}
todo={welcomeSteps[account?.control].slice(4)}
current="compare"

View file

@ -13,9 +13,11 @@ import { useControl } from '@freesewing/react/hooks/useControl'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { NoIcon, OkIcon, SaveIcon } from '@freesewing/react/components/Icon'
import { RightIcon, NoIcon, OkIcon, SaveIcon } from '@freesewing/react/components/Icon'
import { ListInput } from '@freesewing/react/components/Input'
import { ControlScore } from '@freesewing/react/components/Control'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
const strings = {
1: {
@ -53,7 +55,7 @@ export const Control = ({ welcome = false }) => {
<div className="w-full">
<ListInput
id="account-control"
label="User Experience"
label="What user experience do you prefer?"
list={[1, 2, 3, 4, 5].map((val) => ({
val,
label: (
@ -69,18 +71,20 @@ export const Control = ({ welcome = false }) => {
/>
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[control].length > 1 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={100 / welcomeSteps[control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
1 / {welcomeSteps[control].length}
</span>
<Icons done={[]} todo={welcomeSteps[control].slice(1)} current="" />
<WelcomeIcons done={[]} todo={welcomeSteps[control].slice(1)} current="" />
</>
) : null}
</>

View file

@ -83,7 +83,7 @@ const titles = {
img: 'Avatar',
email: 'E-mail Address',
newsletter: 'Newsletter Subscription',
compare: 'Measurements Sets Comparison',
compare: 'Measurements Comparison',
consent: 'Consent & Privacy',
control: 'User Experience',
github: 'GitHub',

View file

@ -12,24 +12,11 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { NoIcon, OkIcon, SaveIcon } from '@freesewing/react/components/Icon'
import { NoIcon, OkIcon, SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { ListInput } from '@freesewing/react/components/Input'
import { Popout } from '@freesewing/react/components/Popout'
const strings = {
yes: {
title: 'Yes, in case it may help me',
desc:
'Allowing us to compare your measurments to a baseline or others measurements sets ' +
'allows us to detect potential problems in your measurements or patterns.',
},
no: {
title: 'No, never compare',
desc:
'We get it, comparison is the thief of joy. Just be aware that this limits our ability ' +
'to warn you about potential problems in your measurements sets or patterns.',
},
}
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
/*
* Component for the account/preferences/newsletter page
@ -99,18 +86,20 @@ export const Newsletter = ({ welcome = false, Link = false }) => {
/>
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account?.control].length > 0 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={200 / welcomeSteps[account?.control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
2 / {welcomeSteps[account?.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account?.control].slice(0, 1)}
todo={welcomeSteps[account?.control].slice(2)}
current="newsletter"
@ -119,21 +108,23 @@ export const Newsletter = ({ welcome = false, Link = false }) => {
) : null}
</>
) : null}
<Popout tip>
<h5>You can unsubscribe at any time with the link below</h5>
<p>
This unsubscribe link will also be included at the bottom of every newsletter we send you,
so you do not need to bookmark it, but you can if you want to.
</p>
<p>
<Link href={`/newsletter/unsubscribe?x=${account?.ehash}`} className={linkClasses}>
Unsubscribe link
</Link>
</p>
<p className="text-sm">
This link is to unsubscribe you specifically, do not share it with other subscribers.
</p>
</Popout>
{welcome ? null : (
<Popout tip>
<h5>You can unsubscribe at any time with the link below</h5>
<p>
This unsubscribe link will also be included at the bottom of every newsletter we send
you, so you do not need to bookmark it, but you can if you want to.
</p>
<p>
<Link href={`/newsletter/unsubscribe?x=${account?.ehash}`} className={linkClasses}>
Unsubscribe link
</Link>
</p>
<p className="text-sm">
This link is to unsubscribe you specifically, do not share it with other subscribers.
</p>
</Popout>
)}
</div>
)
}

View file

@ -11,9 +11,11 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { SaveIcon } from '@freesewing/react/components/Icon'
import { SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { ListInput } from '@freesewing/react/components/Input'
import { NumberCircle } from '@freesewing/react/components/Number'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
/*
* Component for the account/preferences/units page
@ -74,18 +76,20 @@ export const Units = ({ welcome = false }) => {
/>
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account?.control].length > 0 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={300 / welcomeSteps[account?.control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
3 / {welcomeSteps[account?.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account?.control].slice(0, 2)}
todo={welcomeSteps[account?.control].slice(3)}
current="units"

View file

@ -11,8 +11,10 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Link as WebLink } from '@freesewing/react/components/Link'
import { NoIcon, OkIcon, SaveIcon } from '@freesewing/react/components/Icon'
import { NoIcon, OkIcon, SaveIcon, RightIcon } from '@freesewing/react/components/Icon'
import { StringInput } from '@freesewing/react/components/Input'
import { IconButton } from '@freesewing/react/components/Button'
import { WelcomeIcons } from './shared.mjs'
/*
* Component for the account/username page
@ -92,18 +94,20 @@ export const Username = ({ welcome = false, Link = false }) => {
{welcome ? (
<>
<ContinueButton btnProps={{ href: nextHref }} link />
<IconButton href={nextHref} className="mt-4">
<RightIcon stroke={3} /> Continue
</IconButton>
{welcomeSteps[account.control].length > 0 ? (
<>
<progress
className="progress progress-primary w-full mt-12"
className="daisy-progress daisy-progress-primary w-full mt-12"
value={500 / welcomeSteps[account.control].length}
max="100"
></progress>
<span className="pt-4 text-sm font-bold opacity-50">
5 / {welcomeSteps[account.control].length}
</span>
<Icons
<WelcomeIcons
done={welcomeSteps[account.control].slice(0, 4)}
todo={welcomeSteps[account.control].slice(5)}
current="username"

View file

@ -1,4 +1,18 @@
import React from 'react'
import { Link } from '@freesewing/react/components/Link'
import {
SettingsIcon,
ControlIcon,
NewsletterIcon,
UnitsIcon,
CompareIcon,
DocsIcon,
UserIcon,
LeftIcon,
OkIcon,
NoIcon,
ShowcaseIcon,
} from '@freesewing/react/components/Icon'
/*
* A component to display a row of data
@ -19,3 +33,50 @@ export const welcomeSteps = {
4: ['', 'newsletter', 'units', 'compare', 'username', 'bio', 'img'],
5: [''],
}
export const WelcomeDoneIcon = ({ href }) => (
<Link href={`/welcome/${href}`} className="text-success hover:text-secondary">
<WelcomeTopicIcon href={href} />
</Link>
)
export const WelcomeTodoIcon = ({ href }) => (
<Link href={`/welcome/${href}`} className="text-secondary w-6 h-6 opacity-50 hover:opacity-100">
<WelcomeTopicIcon href={href} />
</Link>
)
const WelcomeTopicIcon = (props) => {
const Icon =
props.href === '' || props.href === 'control'
? ControlIcon
: icons[props.href]
? icons[props.href]
: SettingsIcon
return <Icon {...props} />
}
const WelcomeDoingIcon = ({ href }) => (
<WelcomeTopicIcon href={href} className="w-6 h-6 text-base-content" />
)
export const WelcomeIcons = ({ done = [], todo = [], current = '' }) => (
<div className="m-auto flex flex-row items-center justify-center gap-2">
{done.map((href) => (
<WelcomeDoneIcon href={href} key={href} />
))}
<WelcomeDoingIcon href={current} />
{todo.map((href) => (
<WelcomeTodoIcon href={href} key={href} />
))}
</div>
)
const icons = {
newsletter: NewsletterIcon,
units: UnitsIcon,
compare: CompareIcon,
username: UserIcon,
bio: DocsIcon,
img: ShowcaseIcon,
}

View file

@ -19,7 +19,7 @@ export const IconButton = ({
btnProps = {},
}) => {
const allProps = {
className: `flex flex-row gap-2 lg:gap-12 items-center justify-between w-full lg:w-auto daisy-btn daisy-btn-${color} capitalize my-2 ${className}`,
className: `${staticLinkClasses} daisy-btn-${color} hover:text-${color}-content ${className}`,
title: title,
...btnProps,
}
@ -28,3 +28,5 @@ export const IconButton = ({
return onClick ? <button {...allProps}>{children}</button> : <a {...allProps}>{children}</a>
}
const staticLinkClasses = `flex flex-row gap-2 lg:gap-12 items-center justify-between w-full lg:w-auto daisy-btn hover:no-underline capitalize my-2`

View file

@ -467,11 +467,11 @@ export const MarkdownInput = ({
>
<Tabs tabs={['edit', 'preview']}>
<Tab key="edit">
<div className="flex flex-row items-center">
<div className="flex flex-row items-center mt-2">
<textarea
id={id}
rows="5"
className="textarea textarea-bordered textarea-lg w-full"
className="daisy-textarea daisy-textarea-bordered daisy-textarea-lg w-full"
value={current}
placeholder={placeholder}
onChange={(evt) => update(evt.target.value)}

View file

@ -12,8 +12,8 @@ import { useBackend } from '@freesewing/react/hooks/useBackend'
*/
export const useControl = () => {
// Hooks
const { account, setAccount, token } = useAccount()
const backend = useBackend()
const { account, setAccount, token } = useAccount()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
@ -32,10 +32,10 @@ export const useControl = () => {
} else
setLoadingStatus([true, 'Failed to update preferences. Please report this', true, true])
} else {
/*
* Control is used even when people are not logged in
* So this ensures control is always available, even if people are not authenticated
*/
/*
* Control is used even when people are not logged in
* So this ensures control is always available, even if people are not authenticated
*/
setAccount({ ...account, control: newControl })
setControl(newControl)
}

View file

@ -1 +0,0 @@
Welcome page goes here

View file

@ -0,0 +1,22 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Bio } from '@freesewing/react/components/Account'
export default function WelcomeBioPage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Bio</h1>
<p>Feel free to shamelessly plug your YouTube channel or link to other places.</p>
<DocusaurusDoc>
<RoleBlock user>
<Bio welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,30 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Compare } from '@freesewing/react/components/Account'
export default function WelcomeComparePage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Measurements Comparison</h1>
<p>
Comparing measurements can help us detect problems, but it bums you out, we can forego
it.
<br />
<small>
Regardless of what you pick, you are a beautiful person and nothing compares to you
anyway
</small>
</p>
<DocusaurusDoc>
<RoleBlock user>
<Compare welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,22 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Avatar } from '@freesewing/react/components/Account'
export default function WelcomeAvatarPage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Avatar</h1>
<p>A picture says more than a 1000 words.</p>
<DocusaurusDoc>
<RoleBlock user>
<Avatar welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,22 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Control } from '@freesewing/react/components/Account'
export default function WelcomeStartPage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Welcome</h1>
<p>We will ask you a few questions to set up your account. This won&apos;t take long.</p>
<DocusaurusDoc>
<RoleBlock user>
<Control welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,22 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Newsletter } from '@freesewing/react/components/Account'
export default function WelcomeNewsletterPage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Newsletter</h1>
<p>You wil get email from us every three months. No more. No less.</p>
<DocusaurusDoc>
<RoleBlock user>
<Newsletter welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,26 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Units } from '@freesewing/react/components/Account'
export default function WelcomeNewsletterPage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Units</h1>
<p>
FreeSewing supports both metric units, and the imperial system.
<br />
<small>The latter one slightly reluctant, but support it we do.</small>
</p>
<DocusaurusDoc>
<RoleBlock user>
<Units welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}

View file

@ -0,0 +1,22 @@
import Layout from '@theme/Layout'
import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus'
import { RoleBlock } from '@freesewing/react/components/Role'
import { Username } from '@freesewing/react/components/Account'
export default function WelcomeComparePage() {
return (
<Layout title="Welcome to FreeSewing" description="Just a few questions to set up your account">
<div className="tailwind-container">
<div className="text-base-content mdx max-w-prose text-base-content max-w-prose text-current xl:pl-4 mx-auto my-8">
<h1>Username</h1>
<p>Everyone needs one. What will yours be?</p>
<DocusaurusDoc>
<RoleBlock user>
<Username welcome />
</RoleBlock>
</DocusaurusDoc>
</div>
</div>
</Layout>
)
}