1
0
Fork 0

feat(org): Bookmarks for docs

This commit is contained in:
joostdecock 2023-09-04 08:40:05 +02:00
parent e21d262ec2
commit 2106a38154
66 changed files with 380 additions and 467 deletions

View file

@ -1,8 +1,7 @@
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
import { useState, useContext } from 'react'
// Components
import { ChoiceButton } from 'shared/components/choice-button.mjs'
@ -43,12 +42,9 @@ const languages = [
]
export const SuggestLanguageForm = () => {
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
// Hooks
const backend = useBackend()
const toast = useToast()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [language, setLanguage] = useState(false)
@ -58,15 +54,12 @@ export const SuggestLanguageForm = () => {
const [comments, setComments] = useState('')
const sendSuggestion = async () => {
startLoading()
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.sendLanguageSuggestion({ language, help, friends, comments })
if (result.success) {
setSent(true)
stopLoading()
toast.success('Suggestion submitted')
} else {
toast.for.backendError()
}
setLoadingStatus([true, 'status:nailedIt', true, true])
} else setLoadingStatus([true, 'status:backendError', true, false])
}
if (sent)

View file

@ -2,10 +2,9 @@
import { siteConfig } from 'site/site.config.mjs'
import translators from 'site/prebuild/translators.json'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Components
@ -22,28 +21,22 @@ const languages = [
].sort()
export const TranslatorInvite = () => {
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
// Hooks
const { t } = useTranslation(ns)
const backend = useBackend()
const toast = useToast()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [team, setTeam] = useState(false)
const [sent, setSent] = useState(false)
const sendInvite = async () => {
startLoading()
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.sendTranslatorInvite(team)
if (result.success) {
setSent(true)
stopLoading()
toast.success(t('translation:inviteSent'))
} else {
toast.for.backendError()
}
setLoadingStatus([true, 'status:settingsSaved', true, true])
} else setLoadingStatus([true, 'status:backendError', true, false])
}
if (sent)

View file

@ -5,14 +5,13 @@ import { freeSewingConfig as conf } from 'shared/config/freesewing.config.mjs'
import { measurements } from 'config/measurements.mjs'
import { measurements as designMeasurements } from 'shared/prebuild/data/design-measurements.mjs'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
import { ModalContext } from 'shared/context/modal-context.mjs'
// Hooks
import { useState, useEffect, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Components
import { Collapse } from 'shared/components/collapse.mjs'
import { ClearIcon, EditIcon, FilterIcon } from 'shared/components/icons.mjs'
@ -22,7 +21,7 @@ import { PageLink } from 'shared/components/link.mjs'
import { ModalDesignPicker } from 'shared/components/modal/design-picker.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
export const ns = ['toast', 'curate', 'sets', 'account']
export const ns = ['curate', 'sets', 'account']
const EditField = (props) => {
if (props.field === 'nameEn') return <EditName {...props} lang="en" />
@ -137,7 +136,7 @@ export const EditCuratedSet = ({ id }) => {
/*
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { setModal } = useContext(ModalContext)
// Hooks
@ -171,8 +170,6 @@ export const EditCuratedSet = ({ id }) => {
}, [reload, backend, id])
const editProps = {
startLoading,
stopLoading,
account,
backend,
t,

View file

@ -2,7 +2,7 @@
import { capitalize } from 'shared/utils.mjs'
import { siteConfig } from 'site/site.config.mjs'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
import { ModalContext } from 'shared/context/modal-context.mjs'
// Hooks
import { useState, useEffect, useContext } from 'react'
@ -27,28 +27,17 @@ export const Row = ({ title, children }) => (
</div>
)
const CuratedSet = ({
set,
account,
t,
startLoading,
stopLoading,
backend,
refresh,
toast,
language,
}) => {
const CuratedSet = ({ set, account, t, setLoadingStatus, backend, refresh, toast, language }) => {
const { setModal } = useContext(ModalContext)
const remove = async () => {
startLoading()
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.removeCuratedMeasurementsSet(set.id)
if (result) toast.success(t('gone'))
else toast.for.backendError()
if (result) setLoadingStatus([true, 'status:settingsSaved', true, true])
else setLoadingStatus([true, 'status:backendError', true, false])
// This just forces a refresh of the list from the server
// We obviously did not add a key here, but rather removed one
refresh()
stopLoading()
}
const removeModal = () => {
@ -119,7 +108,7 @@ const CuratedSet = ({
export const CurateSets = () => {
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
// Hooks
const { account } = useAccount()
@ -209,7 +198,7 @@ export const CurateSets = () => {
{list.map((set) => (
<CuratedSet
key={set.id}
{...{ set, account, t, startLoading, stopLoading, backend, refresh, toast, language }}
{...{ set, account, t, setLoadingStatus, backend, refresh, toast, language }}
/>
))}
</div>

View file

@ -5,6 +5,8 @@ import { useState, Fragment } from 'react'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { Popout } from 'shared/components/popout/index.mjs'
import { AuthWrapper, ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
@ -22,7 +24,6 @@ import { CodeBox } from 'shared/components/code-box.mjs'
import { PostArticle, ns as mdxNs } from 'site/components/mdx/posts/article.mjs'
import { PageLink, WebLink } from 'shared/components/link.mjs'
import { OkIcon, WarningIcon as KoIcon } from 'shared/components/icons.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
export const ns = nsMerge('account', 'posts', authNs, mdxNs)
@ -64,7 +65,7 @@ export const CreatePost = ({ type = 'showcase' }) => {
const backend = useBackend()
const { account } = useAccount()
const { t, i18n } = useTranslation(ns)
const { loading, setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { loading, setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [designs, setDesigns] = useState([])
@ -151,7 +152,6 @@ export const CreatePost = ({ type = 'showcase' }) => {
return (
<AuthWrapper>
<LoadingStatus />
{pr ? (
<div className="w-full max-w-3xl m-auto p-4">
<h1>Thank you for submitting this {type} post</h1>

View file

@ -5,6 +5,8 @@ import { useState, Fragment } from 'react'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { Popout } from 'shared/components/popout/index.mjs'
import { AuthWrapper, ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
@ -22,7 +24,6 @@ import { CodeBox } from 'shared/components/code-box.mjs'
import { PostArticle, ns as mdxNs } from 'site/components/mdx/posts/article.mjs'
import { PageLink, WebLink } from 'shared/components/link.mjs'
import { OkIcon, WarningIcon as KoIcon } from 'shared/components/icons.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
export const ns = nsMerge('account', 'posts', authNs, mdxNs)
@ -53,7 +54,7 @@ export const CreateShowcasePost = () => {
const { account } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { loading, setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { loading, setLoadingStatus } = useContext(LoadingStatusContext)
const [designs, setDesigns] = useState([])
const [title, setTitle] = useState('')
@ -135,7 +136,6 @@ export const CreateShowcasePost = () => {
return (
<AuthWrapper>
<LoadingStatus />
{pr ? (
<div className="w-full max-w-3xl m-auto p-4">
<h1>Thank you for submitting this showcase</h1>

View file

@ -1,4 +1,5 @@
import { NavigationContext } from 'shared/context/navigation-context.mjs'
import { nsMerge } from 'shared/utils.mjs'
// Hooks
import { useContext } from 'react'
// Components
@ -16,10 +17,10 @@ import {
ns as navNs,
} from 'shared/components/navigation/sitenav.mjs'
import { Toc } from 'shared/components/mdx/toc.mjs'
import { MdxMetaData } from 'shared/components/mdx/meta.mjs'
import { MdxMetaData, ns as metaNs } from 'shared/components/mdx/meta.mjs'
import { PrevNext } from 'shared/components/prev-next.mjs'
export const ns = [navNs, 'docs'] //navNs
export const ns = nsMerge(navNs, 'docs', metaNs)
export const FrontmatterHead = ({ frontmatter, slug, locale }) => (
<Head>

View file

@ -4,7 +4,6 @@ import React from 'react'
import Bugsnag from '@bugsnag/js'
import BugsnagPluginReact from '@bugsnag/plugin-react'
import { siteConfig } from 'site/site.config.mjs'
import { Toaster as DefaultToaster } from 'react-hot-toast'
import { ContextWrapper } from 'shared/components/wrappers/context.mjs'
Bugsnag.start({
@ -19,24 +18,6 @@ const FreeSewingOrg = ({ Component, pageProps }) => (
<ErrorBoundary>
<ContextWrapper>
<Component {...pageProps} />
<DefaultToaster
position="bottom-right"
toastOptions={{
className: 'bg-base-100 text-base-content',
success: {
className: 'bg-success text-success-content',
},
error: {
className: 'bg-error text-error-content',
},
loading: {
className: 'bg-warning text-warning-content',
},
custom: {
className: 'bg-accent text-accent-content',
},
}}
/>
</ContextWrapper>
</ErrorBoundary>
)

View file

@ -6,14 +6,13 @@ import { nsMerge } from 'shared/utils.mjs'
import { useTranslation } from 'next-i18next'
import { useState, useEffect } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
import { ns as apikeysNs } from 'shared/components/account/apikeys.mjs'
// Translation namespaces used on this page
const ns = nsMerge(apikeysNs, authNs, pageNs, 'status')
const ns = nsMerge(apikeysNs, authNs, pageNs)
/*
* Some things should never generated as SSR
@ -38,26 +37,20 @@ const DynamicApikey = dynamic(
const ApikeyPage = ({ page, id }) => {
const { t } = useTranslation(ns)
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const [apikey, setApikey] = useState()
useEffect(() => {
const getApikey = async () => {
setLoadingStatus([true, t('backendLoadingStarted')])
const result = await backend.getApikey(id)
if (result.success) {
setApikey(result.data.apikey)
console.log(result.data.apikey)
setLoadingStatus([true, 'backendLoadingCompleted', true, true])
} else setLoadingStatus([false])
if (result.success) setApikey(result.data.apikey)
else setLoadingStatus([false])
}
getApikey()
}, [id])
return (
<PageWrapper {...page} title={`${t('apikeys')}: ${apikey?.name}`}>
<LoadingStatus />
<DynamicAuthWrapper>
<DynamicApikey apikey={apikey} t={t} />
</DynamicAuthWrapper>

View file

@ -6,7 +6,6 @@ import { nsMerge } from 'shared/utils.mjs'
import { useTranslation } from 'next-i18next'
import { useState, useEffect } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
@ -38,25 +37,20 @@ const DynamicBookmark = dynamic(
const BookmarkPage = ({ page, id }) => {
const { t } = useTranslation(ns)
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const [bookmark, setBookmark] = useState()
useEffect(() => {
const getBookmark = async () => {
setLoadingStatus([true, t('backendLoadingStarted')])
const result = await backend.getBookmark(id)
if (result.success) {
setBookmark(result.data.bookmark)
setLoadingStatus([true, 'backendLoadingCompleted', true, true])
} else setLoadingStatus([false])
if (result.success) setBookmark(result.data.bookmark)
else setLoadingStatus([false])
}
getBookmark()
}, [id])
return (
<PageWrapper {...page} title={`${t('bookmarks')}: ${bookmark?.title}`}>
<LoadingStatus />
<DynamicAuthWrapper>
<DynamicBookmark bookmark={bookmark} />
</DynamicAuthWrapper>

View file

@ -2,11 +2,10 @@
import { useEffect, useState, useContext } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import Link from 'next/link'
@ -22,13 +21,10 @@ import { HelpIcon } from 'shared/components/icons.mjs'
const ns = Array.from(new Set([...pageNs, 'account']))
const ConfirmSignUpPage = ({ page }) => {
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
// Hooks
const { setAccount, setToken, token } = useAccount()
const backend = useBackend()
const toast = useToast()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t } = useTranslation(ns)
const router = useRouter()
// Get confirmation ID and check from url
@ -41,7 +37,7 @@ const ConfirmSignUpPage = ({ page }) => {
useEffect(() => {
// Async inside useEffect requires this approach
const confirmEmail = async () => {
startLoading()
setLoadingStatus([true, 'status:contactingBackend'])
const confirmation = await backend.loadConfirmation({ id, check })
if (confirmation?.result === 'success' && confirmation.confirmation) {
const result = await backend.updateAccount({
@ -50,35 +46,23 @@ const ConfirmSignUpPage = ({ page }) => {
check: confirmation.confirmation.check,
})
if (result.success) {
setLoadingStatus([true, 'status:settingsSaved', true, true])
setAccount(result.data.account)
setToken(result.data.token)
stopLoading()
setError(false)
toast.for.settingsSaved()
router.push('/account')
} else {
stopLoading()
setLoadingStatus([true, 'status:backendError', true, false])
setError(true)
}
} else {
stopLoading()
setLoadingStatus([true, 'status:backendError', true, false])
setError(true)
}
}
// Call async methods
if (token) confirmEmail()
}, [
id,
check,
token,
backend,
router,
setAccount,
setToken,
startLoading,
stopLoading,
toast.for,
])
}, [id, check, token, backend, router, setAccount, setToken])
// Update path with dynamic ID
if (!page) return null

View file

@ -1,3 +1,4 @@
import { nsMerge } from 'shared/utils.mjs'
// Used in static paths
import { pages } from 'site/prebuild/docs.en.mjs'
// Dependencies
@ -11,7 +12,7 @@ import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
import { loaders } from 'shared/components/dynamic-docs/org.mjs'
export const ns = [...pageNs, layoutNs]
export const ns = nsMerge(pageNs, layoutNs)
/**
* a page to display documentation markdown
@ -49,7 +50,7 @@ export default DocsPage
export async function getStaticProps({ locale, params }) {
return {
props: {
...(await serverSideTranslations('en', ['docs', ...ns])),
...(await serverSideTranslations('en', ns)),
slug: params.slug.join('/'),
locale,
page: {

View file

@ -6,7 +6,7 @@ import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -23,15 +23,15 @@ const namespaces = nsMerge(pageNs, 'newsletter')
*/
const NewsletterPage = ({ page, id, ehash }) => {
const { t } = useTranslation(namespaces)
const { setLoading } = useContext(LoadingContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const [confirmed, setConfirmed] = useState(false)
const handler = async () => {
setLoading(true)
setLoadingStatus([true, 'status:contactingBackend'])
await backend.confirmNewsletterSubscribe({ id, ehash })
setLoading(false)
setLoadingStatus([true, 'status:settingsSaved', true, true])
setConfirmed(true)
}

View file

@ -6,7 +6,7 @@ import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -23,15 +23,15 @@ const namespaces = nsMerge(pageNs, 'newsletter')
*/
const NewsletterPage = ({ page, id, ehash }) => {
const { t } = useTranslation(namespaces)
const { setLoading } = useContext(LoadingContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const [confirmed, setConfirmed] = useState(false)
const handler = async () => {
setLoading(true)
setLoadingStatus([true, 'status:contactingBackend'])
await backend.confirmNewsletterUnsubscribe({ id, ehash })
setLoading(false)
setLoadingStatus([true, 'status:settingsSaved', true, true])
setConfirmed(true)
}

View file

@ -6,8 +6,9 @@ import { useEffect } from 'react'
import { useRouter } from 'next/router'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { BareLayout } from 'site/components/layouts/bare.mjs'
@ -27,7 +28,7 @@ const OauthCallbackPage = ({ page, provider }) => {
const { t } = useTranslation(ns)
const backend = useBackend()
const { setAccount, setToken, setSeenUser } = useAccount()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
useEffect(() => {
const oauthFlow = async () => {
@ -53,7 +54,6 @@ const OauthCallbackPage = ({ page, provider }) => {
return (
<PageWrapper {...page} layout={BareLayout}>
<LoadingStatus />
<div className="flex flex-col items-center h-screen justify-center text-base-content px-4">
<div className="max-w-lg w-full">
<Loading />

View file

@ -4,11 +4,12 @@ import { useTranslation } from 'next-i18next'
import { DateTime } from 'luxon'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { shortDate, formatNumber } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton, DisplayRow, NumberBullet } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -55,7 +56,7 @@ const ExpiryPicker = ({ t, expires, setExpires }) => {
const CopyInput = ({ text }) => {
const { t } = useTranslation(['status'])
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [copied, setCopied] = useState(false)
@ -67,7 +68,6 @@ const CopyInput = ({ text }) => {
return (
<div className="flex flez-row gap-2 items-center w-full">
<LoadingStatus />
<input
readOnly
value={text}
@ -147,7 +147,7 @@ const NewKey = ({ account, setGenerate, backend }) => {
const [level, setLevel] = useState(1)
const [expires, setExpires] = useState(Date.now())
const [apikey, setApikey] = useState(false)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
const docs = {}
@ -179,7 +179,6 @@ const NewKey = ({ account, setGenerate, backend }) => {
return (
<div>
<LoadingStatus />
{apikey ? (
<ShowKey {...{ apikey, t, clear }} />
) : (
@ -264,7 +263,7 @@ export const Apikeys = () => {
const { account } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus, LoadingProgress } = useLoadingStatus()
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
// State
const [keys, setKeys] = useState([])
@ -319,7 +318,6 @@ export const Apikeys = () => {
return (
<div className="max-w-4xl xl:pl-4">
<LoadingStatus />
<p className="text-center md:text-right">
<Link
className="btn btn-primary capitalize w-full md:w-auto"

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
@ -30,7 +31,7 @@ export const BioSettings = ({ welcome = false }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [bio, setBio] = useState(account.bio)
@ -53,7 +54,6 @@ export const BioSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl xl:pl-4">
<LoadingStatus />
<MarkdownInput
id="account-bio"
label={t('bioTitle')}

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState, useEffect, Fragment } from 'react'
import { useState, useEffect, Fragment, useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { PlusIcon, TrashIcon, LeftIcon } from 'shared/components/icons.mjs'
@ -43,7 +44,7 @@ export const Bookmark = ({ bookmark }) => {
// Component for the 'new/apikey' page
export const NewBookmark = () => {
// Hooks
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const router = useRouter()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
@ -72,7 +73,6 @@ export const NewBookmark = () => {
return (
<div className="max-w-2xl xl:pl-4">
<LoadingStatus />
<StringInput
id="bookmark-title"
label={t('title')}
@ -109,7 +109,7 @@ export const Bookmarks = () => {
// Hooks
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus, LoadingProgress } = useLoadingStatus()
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
// State
const [bookmarks, setBookmarks] = useState([])
@ -167,7 +167,6 @@ export const Bookmarks = () => {
return (
<div className="max-w-4xl xl:pl-4">
<LoadingStatus />
<p className="text-center md:text-right">
<Link
className="btn btn-primary capitalize w-full md:w-auto"

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
@ -18,7 +19,7 @@ export const CompareSettings = ({ welcome = false }) => {
// Hooks
const { account, setAccount } = useAccount()
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns)
// State
@ -47,7 +48,6 @@ export const CompareSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<ListInput
id="account-compare"
label={t('compareTitle')}

View file

@ -1,11 +1,12 @@
// Dependencies
import { useState } from 'react'
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { nsMerge } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import Link from 'next/link'
import { Popout } from 'shared/components/popout/index.mjs'
@ -13,7 +14,7 @@ import { BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
import { GdprAccountDetails, ns as gdprNs } from 'shared/components/gdpr/details.mjs'
export const ns = nsMerge(gdprNs, 'account', 'toast')
export const ns = nsMerge(gdprNs, 'account', 'status')
const Checkbox = ({ value, setter, label, children = null }) => (
<div
@ -39,7 +40,7 @@ export const ConsentSettings = ({ title = false }) => {
// Hooks
const { account, setAccount, setToken } = useAccount()
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t } = useTranslation(ns)
// State
@ -73,7 +74,6 @@ export const ConsentSettings = ({ title = false }) => {
return (
<div className="max-w-xl xl:pl-4">
<LoadingStatus />
{title ? <h2 className="text-4xl">{t('privacyMatters')}</h2> : null}
<p>{t('compliant')}</p>
<p>{t('consentWhyAnswer')}</p>

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
@ -19,7 +20,7 @@ export const useControlState = () => {
// Hooks
const { account, setAccount, token } = useAccount()
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [selection, setSelection] = useState(account.control)
@ -44,7 +45,7 @@ export const useControlState = () => {
}
}
return { selection, update, LoadingStatus }
return { selection, update }
}
export const ControlSettings = ({ welcome = false, noBack = false }) => {
@ -61,7 +62,6 @@ export const ControlSettings = ({ welcome = false, noBack = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<ListInput
id="account-control"
label={t('controlTitle')}

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Verification methods
import { validateEmail, validateTld } from 'shared/utils.mjs'
// Components
@ -20,7 +21,7 @@ export const EmailSettings = () => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [email, setEmail] = useState(account.email)
@ -42,7 +43,6 @@ export const EmailSettings = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
{changed ? (
<Popout note>
<h3>{t('oneMoreThing')}</h3>

View file

@ -193,6 +193,7 @@ csetBookmark: Curated Measurements Sets
docBookmark: Documentation
customBookmark: Custom Bookmarks
yourBookmarks: Your bookmarks
bookmarkThisPage: Bookmark this page
# sets
set: Measurements Set

View file

@ -1,9 +1,10 @@
// Dependencies
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -15,7 +16,7 @@ export const ExportAccount = () => {
// Hooks
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [link, setLink] = useState()
@ -31,7 +32,6 @@ export const ExportAccount = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
{link ? (
<Popout link>
<h5>{t('exportDownload')}</h5>

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
@ -18,7 +19,7 @@ export const GithubSettings = () => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [githubUsername, setGithubUsername] = useState(account.data.githubUsername || '')
@ -36,7 +37,6 @@ export const GithubSettings = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
<h2 className="text-4xl">{t('githubTitle')}</h2>
<StringInput
id="account-github-email"

View file

@ -2,10 +2,11 @@
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
import { cloudflareImageUrl } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
@ -18,7 +19,7 @@ export const ns = ['account', 'status']
export const ImgSettings = ({ welcome = false }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns)
const [img, setImg] = useState('')
@ -36,7 +37,6 @@ export const ImgSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
{!welcome || img !== false ? (
<img
alt="img"

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { Icons, welcomeSteps, BackToAccountButton, NumberBullet } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
@ -16,7 +17,7 @@ export const ns = ['account', 'status']
export const ImperialSettings = ({ welcome = false }) => {
// Hooks
const { account, setAccount } = useAccount()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
@ -44,7 +45,6 @@ export const ImperialSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<ListInput
id="account-units"
label={t('unitsTitle')}

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus, ns as statusNs } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton, NumberBullet } from './shared.mjs'
import { ListInput } from 'shared/components/inputs.mjs'
@ -17,7 +18,7 @@ export const ns = ['account', 'locales', statusNs]
export const LanguageSettings = () => {
// Hooks
const { account, setAccount } = useAccount()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
@ -39,7 +40,6 @@ export const LanguageSettings = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
<ListInput
id="account-language"
label={t('languageTitle')}

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -27,7 +28,7 @@ export const MfaSettings = ({ title = false, welcome = false }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [enable, setEnable] = useState(false)
@ -87,7 +88,6 @@ export const MfaSettings = ({ title = false, welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
{title ? <h2 className="text-4xl">{titleText}</h2> : null}
{enable ? (
<>

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
@ -19,7 +20,7 @@ export const NewsletterSettings = ({ welcome = false }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { LoadingStatus, setLoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [selection, setSelection] = useState(account?.newsletter ? 'yes' : 'no')
@ -44,7 +45,6 @@ export const NewsletterSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<ListInput
id="account-newsletter"
label={t('newsletterTitle')}

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import Link from 'next/link'
import { BackToAccountButton } from './shared.mjs'
@ -21,7 +22,7 @@ export const PasswordSettings = ({ welcome = false }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [password, setPassword] = useState('')
@ -38,7 +39,6 @@ export const PasswordSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<PasswordInput
id="account-password"
label={t('passwordTitle')}

View file

@ -3,11 +3,12 @@ import { useState, useEffect, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { capitalize, shortDate, cloudflareImageUrl, horFlexClasses } from 'shared/utils.mjs'
import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Context
import { ModalContext } from 'shared/context/modal-context.mjs'
// Components
@ -45,7 +46,7 @@ export const ns = ['account', 'patterns', 'status']
export const Pattern = ({ id, publicOnly = false }) => {
// Hooks
const { account, control } = useAccount()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically
@ -122,7 +123,6 @@ export const Pattern = ({ id, publicOnly = false }) => {
const heading = (
<>
<LoadingStatus />
<div className="flex flex-wrap md:flex-nowrap flex-row gap-2 w-full">
<div className="w-full md:w-96 shrink-0">
<PatternCard pattern={pattern} size="md" />
@ -428,7 +428,7 @@ export const Patterns = () => {
// Hooks
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus, LoadingProgress } = useLoadingStatus()
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
// State
const [patterns, setPatterns] = useState([])
@ -483,7 +483,6 @@ export const Patterns = () => {
return (
<div className="max-w-4xl xl:pl-4">
<LoadingStatus />
<p className="text-center md:text-right">
<Link className="btn btn-primary capitalize w-full md:w-auto" href="/new/pattern">
<PlusIcon />

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
@ -18,7 +19,7 @@ export const PlatformSettings = ({ platform }) => {
const { account, setAccount } = useAccount()
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [platformId, setPlatformId] = useState(account.data[platform] || '')
@ -37,7 +38,6 @@ export const PlatformSettings = ({ platform }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<StringInput
id={`account-${platform}`}
label={t(platform === 'website' ? 'account:websiteTitle' : 'account:platformTitle', {

View file

@ -1,9 +1,10 @@
// Dependencies
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
@ -14,7 +15,7 @@ export const ReloadAccount = ({ title = false }) => {
const { setAccount } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// Helper method to reload account
const reload = async () => {
@ -28,7 +29,6 @@ export const ReloadAccount = ({ title = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
{title ? <h2>{t('reloadMsg1')}</h2> : null}
<p>{t('reloadMsg2')}</p>
<button className="btn btn-primary capitalize w-full my-2" onClick={reload}>

View file

@ -1,9 +1,10 @@
// Dependencies
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -15,7 +16,7 @@ export const RemoveAccount = () => {
const { signOut } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// Helper method to export account
const removeAccount = async () => {
@ -29,7 +30,6 @@ export const RemoveAccount = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
<Popout warning>
<h3>{t('noWayBack')}</h3>
<button className="btn btn-error capitalize w-full my-2" onClick={removeAccount}>

View file

@ -1,9 +1,10 @@
// Dependencies
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { BackToAccountButton } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
@ -15,7 +16,7 @@ export const RestrictAccount = () => {
const { signOut } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// Helper method to export account
const restrictAccount = async () => {
@ -29,7 +30,6 @@ export const RestrictAccount = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
<Popout warning>
<h5>{t('proceedWithCaution')}</h5>
<p className="text-lg">{t('restrictWarning')}</p>

View file

@ -1,10 +1,9 @@
// Dependencies
import { useState, useEffect, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { measurements } from 'config/measurements.mjs'
import { measurements as designMeasurements } from 'shared/prebuild/data/design-measurements.mjs'
import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs'
import { siteConfig } from 'site/site.config.mjs'
import { isDegreeMeasurement } from 'config/measurements.mjs'
import {
shortDate,
cloudflareImageUrl,
@ -15,11 +14,13 @@ import {
} from 'shared/utils.mjs'
import orderBy from 'lodash.orderby'
// Hooks
import { useState, useEffect, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
import { ModalContext } from 'shared/context/modal-context.mjs'
// Components
import { Popout } from 'shared/components/popout/index.mjs'
@ -46,7 +47,6 @@ import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
import Markdown from 'react-markdown'
import Timeago from 'react-timeago'
import { DisplayRow } from './shared.mjs'
import { isDegreeMeasurement } from 'config/measurements.mjs'
import { DynamicOrgDocs } from 'shared/components/dynamic-docs/org.mjs'
import {
StringInput,
@ -62,7 +62,7 @@ export const ns = [inputNs, 'account', 'patterns', 'status', 'measurements', 'se
export const NewSet = () => {
// Hooks
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const { t } = useTranslation(ns)
const router = useRouter()
@ -82,7 +82,6 @@ export const NewSet = () => {
return (
<div className="max-w-xl">
<LoadingStatus />
<h5>{t('name')}</h5>
<p>{t('setNameDesc')}</p>
<input
@ -189,7 +188,7 @@ export const MsetCard = ({
export const Mset = ({ id, publicOnly = false }) => {
// Hooks
const { account, control } = useAccount()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
@ -295,7 +294,6 @@ export const Mset = ({ id, publicOnly = false }) => {
const heading = (
<>
<LoadingStatus />
<div className="flex flex-wrap md:flex-nowrap flex-row gap-2 w-full">
<div className="w-full md:w-96 shrink-0">
<MsetCard set={mset} control={control} />
@ -647,7 +645,7 @@ export const Sets = () => {
const { control } = useAccount()
const backend = useBackend()
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus, LoadingProgress } = useLoadingStatus()
const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext)
// State
const [sets, setSets] = useState([])
@ -702,7 +700,6 @@ export const Sets = () => {
return (
<div className="max-w-7xl xl:pl-4">
<LoadingStatus />
<p className="text-center md:text-right">
<Link
className="btn btn-primary capitalize w-full md:w-auto"

View file

@ -133,44 +133,3 @@ export const DisplayRow = ({ title, children, keyWidth = 'w-24' }) => (
<div className="grow">{children}</div>
</div>
)
/*
// Hooks
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
// Components
import { Spinner } from 'shared/components/spinner.mjs'
import Link from 'next/link'
export const ContinueButton = ({ btnProps = {}, link = false }) => {
// Hooks
const { t } = useTranslation(['account'])
let classes = 'btn-primary btn mt-8 capitalize w-full'
const children = (
<span className="flex flex-row items-center gap-2">
{loading ? (
<>
<Spinner />
<span>{t('processing')}</span>
</>
) : (
<span>{t('continue')}</span>
)}
</span>
)
return link ? (
<Link className={classes} tabIndex="-1" {...btnProps}>
{children}
</Link>
) : (
<button className={classes} tabIndex="-1" role="button" {...btnProps}>
{children}
</button>
)
}
*/

View file

@ -1,10 +1,11 @@
// Dependencies
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { OkIcon, NoIcon } from 'shared/components/icons.mjs'
@ -12,13 +13,13 @@ import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { StringInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'shared/components/dynamic-docs/org.mjs'
export const ns = ['account', 'toast']
export const ns = ['account', 'status']
export const UsernameSettings = ({ welcome = false }) => {
// Hooks
const { account, setAccount } = useAccount()
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns)
const [username, setUsername] = useState(account.username)
const [available, setAvailable] = useState(true)
@ -52,7 +53,6 @@ export const UsernameSettings = ({ welcome = false }) => {
return (
<div className="max-w-xl">
<LoadingStatus />
<StringInput
id="account-username"
label={t('usernameTitle')}

View file

@ -1,33 +1,36 @@
import { useState, useEffect } from 'react'
// Depdendencies
import { cloudflareConfig } from 'shared/config/cloudflare.mjs'
import { freeSewingConfig } from 'shared/config/freesewing.config.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState, useEffect, useContext } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Components
import Link from 'next/link'
import Markdown from 'react-markdown'
import { Json } from 'shared/components/json.mjs'
import Markdown from 'react-markdown'
import { AccountRole } from 'shared/components/account/role.mjs'
import { AccountStatus } from 'shared/components/account/status.mjs'
import { Loading } from 'shared/components/spinner.mjs'
import { freeSewingConfig } from 'shared/config/freesewing.config.mjs'
const roles = ['user', 'curator', 'bughunter', 'support', 'admin']
export const ImpersonateButton = ({ userId }) => {
const toast = useToast()
const backend = useBackend()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { impersonate } = useAccount()
if (!userId) return null
const impersonateUser = async () => {
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.adminImpersonateUser(userId)
if (result.success) {
impersonate(result.data)
toast.for.settingsSaved()
} else toast.for.backendError()
setLoadingStatus([true, 'status:settingsSaved', true, true])
} else setLoadingStatus([true, 'status:backendError', true, false])
}
return (
@ -132,7 +135,7 @@ export const User = ({ user }) => (
export const ManageUser = ({ userId }) => {
// Hooks
const backend = useBackend()
const toast = useToast()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [user, setUser] = useState({})
@ -147,11 +150,12 @@ export const ManageUser = ({ userId }) => {
}, [userId])
const updateUser = async (data) => {
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.adminUpdateUser({ id: userId, data })
if (result.success) {
toast.for.settingsSaved()
setLoadingStatus([true, 'status:settingsSaved', true, true])
setUser(result.data.user)
} else toast.for.backendError()
} else setLoadingStatus([true, 'status:backendError', true, false])
}
return user.id ? (

View file

@ -0,0 +1,72 @@
// Dependencies
import { horFlexClasses, notEmpty } from 'shared/utils.mjs'
// Hooks
import { useContext, useState } from 'react'
import { useTranslation } from 'next-i18next'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Context
import { ModalContext } from 'shared/context/modal-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
import { BookmarkIcon } from 'shared/components/icons.mjs'
import { StringInput } from 'shared/components/inputs.mjs'
export const ns = 'account'
export const CreateBookmark = ({ type, title, slug }) => {
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const [name, setName] = useState(title)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { setModal } = useContext(ModalContext)
const url = i18n.language === 'en' ? `/${slug}` : `/${lang}/${slug}`
const bookmark = async (evt) => {
evt.stopPropagation()
setLoadingStatus([true, 'status:contactingBackend'])
const result = await backend.createBookmark({ type, title, url })
if (result.success) {
setLoadingStatus([true, 'status:nailedIt', true, true])
setModal(false)
} else setLoadingStatus([true, 'backendError', true, false])
}
return (
<>
<h2>{t('account:bookmarkThisPage')}</h2>
<StringInput
label={t('account:title')}
current={name}
update={setName}
valid={notEmpty}
labelBL={url}
/>
<button className="btn btn-primary w-full mt-4" onClick={bookmark}>
<span>{t('account:bookmarkThisPage')}</span>
</button>
</>
)
}
export const BookmarkButton = ({ slug, type, title }) => {
const { t } = useTranslation('account')
const { setModal } = useContext(ModalContext)
return (
<button
className={`btn btn-secondary btn-outline ${horFlexClasses}`}
onClick={() =>
setModal(
<ModalWrapper flex="col" justify="top lg:justify-center" slideFrom="right">
<CreateBookmark {...{ type, title, slug }} />
</ModalWrapper>
)
}
>
<BookmarkIcon />
<span>{t('account:bookmarkThisPage')}</span>
</button>
)
}

View file

@ -2,14 +2,14 @@
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { Spinner } from 'shared/components/spinner.mjs'
import Link from 'next/link'
export const ContinueButton = ({ btnProps = {}, link = false }) => {
// Context
const { loading } = useContext(LoadingContext)
const { loading } = useContext(LoadingStatusContext)
// Hooks
const { t } = useTranslation(['account'])

View file

@ -2,12 +2,12 @@
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { Spinner } from 'shared/components/spinner.mjs'
export const SaveSettingsButton = ({ btnProps = {}, welcome = false, label = false }) => {
const { loading } = useContext(LoadingContext)
const { loading } = useContext(LoadingStatusContext)
const { t } = useTranslation(['account'])
let classes = 'btn mt-4 capitalize '
if (welcome) {

View file

@ -7,9 +7,9 @@ import { shortDate, cloudflareImageUrl, capitalize } from 'shared/utils.mjs'
// Hooks
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Context
import { ModalContext } from 'shared/context/modal-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { DisplayRow } from './account/shared.mjs'
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
@ -135,7 +135,7 @@ const ShowCuratedSet = ({ cset }) => {
export const CuratedSet = ({ id }) => {
// Hooks
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend()
// State
@ -158,7 +158,6 @@ export const CuratedSet = ({ id }) => {
return (
<div className="max-w-2xl">
<LoadingStatus />
<ShowCuratedSet cset={cset} />
</div>
)
@ -168,7 +167,7 @@ export const CuratedSet = ({ id }) => {
export const CuratedSets = () => {
// Hooks
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [sets, setSets] = useState([])
@ -191,7 +190,6 @@ export const CuratedSets = () => {
return (
<div className="max-w-7xl xl:pl-4">
<LoadingStatus />
<SetLineup sets={Object.values(sets)} onClick={setSelected} />
{selected && <ShowCuratedSet cset={sets[selected]} />}
</div>

View file

@ -3,12 +3,12 @@ import { cloudflareImageUrl } from 'shared/utils.mjs'
import { collection } from 'shared/hooks/use-design.mjs'
// Context
import { ModalContext } from 'shared/context/modal-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState, useCallback, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useDropzone } from 'react-dropzone'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import Markdown from 'react-markdown'
import { ResetIcon, DocsIcon, UploadIcon } from 'shared/components/icons.mjs'
@ -278,7 +278,7 @@ export const ImageInput = ({
}) => {
const { t } = useTranslation(ns)
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [url, setUrl] = useState(false)
const [uploadedId, setUploadedId] = useState(false)
@ -316,7 +316,6 @@ export const ImageInput = ({
if (current)
return (
<FormControl label={label} docs={docs}>
<LoadingStatus />
<div
className="bg-base-100 w-full h-36 mb-2 mx-auto flex flex-col items-center text-center justify-center"
style={{
@ -340,7 +339,6 @@ export const ImageInput = ({
return (
<FormControl label={label} docs={docs} forId={id}>
<LoadingStatus />
<div
{...getRootProps()}
className={`

View file

@ -1,13 +1,19 @@
import { useState, useEffect } from 'react'
import { siteConfig } from 'site/site.config.mjs'
import { horFlexClasses } from 'shared/utils.mjs'
// List of authors
import { authors as allAuthors } from 'config/authors.mjs'
import { docUpdates } from 'site/prebuild/doc-updates.mjs'
// Components
import { PageLink } from 'shared/components/link.mjs'
import { TimeAgo } from 'shared/components/timeago/index.mjs'
// Hooks
import { useTranslation } from 'next-i18next'
import { EditIcon } from 'shared/components/icons.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
// Components
import { PageLink } from 'shared/components/link.mjs'
import { TimeAgo } from 'shared/components/timeago/index.mjs'
import { BookmarkButton } from 'shared/components/bookmarks.mjs'
export const ns = 'account'
const PersonList = ({ list }) =>
list ? (
@ -54,11 +60,19 @@ const CreditsList = ({ updates, frontmatter, locale, t }) => (
)
export const MdxMetaData = ({ frontmatter, locale, slug }) => {
const { t } = useTranslation('docs')
const { control } = useAccount()
const { t, i18n } = useTranslation('docs')
const [localControl, setLocalControl] = useState(1)
// Prevent hydration issues
useEffect(() => {
setLocalControl(control)
}, [])
const updates = docUpdates[slug] || {}
frontmatter.maintainers = ['joostdecock']
locale = 'fr'
locale = i18n.language
/*
* FIXME
@ -70,13 +84,18 @@ export const MdxMetaData = ({ frontmatter, locale, slug }) => {
return (
<div className="hidden xl:block mb-4">
{localControl > 2 && (
<div className="flex flex-col gap-2 max-w-xs">
<a
href={`https://github.dev/freesewing/freesewing/blob/develop/markdown/${siteConfig.tld}/${slug}/en.md`}
className="btn btn-success flex flex-row justify-between items-center w-full px-4 bg-gradient-to-r from-primary to-accent mb-4 hover:from-accent hover:to-accent"
className={`btn btn-secondary btn-outline ${horFlexClasses}`}
>
<EditIcon />
<span>{t('editThisPage')}</span>
</a>
<BookmarkButton slug={slug} title={frontmatter.title} type="doc" />
</div>
)}
<div
className={`
mdx mdx-toc text-base-content text-base

View file

@ -4,8 +4,8 @@ import { useState, useContext, useEffect } from 'react'
import { useTranslation } from 'next-i18next'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
import { NavigationContext } from 'shared/context/navigation-context.mjs'
// Components
import Markdown from 'react-markdown'
@ -27,11 +27,12 @@ import { Link, PageLink } from 'shared/components/link.mjs'
import { Popout } from 'shared/components/popout/index.mjs'
import { EditRow } from 'shared/components/account/patterns.mjs'
export const ns = [...ns404, 'toast']
export const ns = ns404
export const ManagePattern = ({ id = false }) => {
// Context
const { addPages } = useContext(NavigationContext)
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [pattern, setPattern] = useState({})
@ -42,7 +43,6 @@ export const ManagePattern = ({ id = false }) => {
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { language } = i18n
const toast = useToast()
// async effect helper
const loadPattern = async () => {
@ -82,7 +82,7 @@ export const ManagePattern = ({ id = false }) => {
if (result.success) {
if (result.data.pattern) {
setPattern(result.data.pattern)
toast.for.settingsSaved()
setLoadingStatus([true, 'settingsSaved', true, true])
}
}
}
@ -125,17 +125,13 @@ export const ManagePattern = ({ id = false }) => {
<>
<h2>{t('update')}</h2>
{/* Name is always shown */}
<EditRow title={t('name')} field="name" {...{ pattern, backend, t, toast, refresh }}>
<EditRow title={t('name')} field="name" {...{ pattern, backend, t, refresh }}>
{pattern.name}
</EditRow>
{/* img: Control level determines whether or not to show this */}
{pattern.id && account.control >= conf.account.patterns.img ? (
<EditRow
title={t('image')}
field="img"
{...{ pattern, backend, t, toast, refresh }}
>
<EditRow title={t('image')} field="img" {...{ pattern, backend, t, refresh }}>
<img
src={pattern.img}
className="w-10 mask mask-squircle bg-neutral aspect-square"
@ -145,11 +141,7 @@ export const ManagePattern = ({ id = false }) => {
{/* notes: Control level determines whether or not to show this */}
{account.control >= conf.account.patterns.notes ? (
<EditRow
title={t('notes')}
field="notes"
{...{ pattern, backend, t, toast, refresh }}
>
<EditRow title={t('notes')} field="notes" {...{ pattern, backend, t, refresh }}>
<Markdown>{pattern.notes}</Markdown>
</EditRow>
) : null}

View file

@ -1,10 +1,10 @@
// Hooks
import { useContext } from 'react'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
export const Ribbon = () => {
const { loading } = useContext(LoadingContext)
const { loading } = useContext(LoadingStatusContext)
return (
<div

View file

@ -1,10 +1,11 @@
// Dependencies
import { cloudflareImageUrl, nsMerge } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useTranslation } from 'next-i18next'
import { useEffect, useState } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { useRouter } from 'next/router'
// Components
import { AuthWrapper } from 'shared/components/wrappers/auth/index.mjs'
@ -20,7 +21,7 @@ export const CsetSubmission = ({ id }) => {
// Hooks
const { t } = useTranslation(ns)
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const router = useRouter()
const [submission, setSubmission] = useState(false)
@ -57,7 +58,6 @@ export const CsetSubmission = ({ id }) => {
return (
<div className="max-w-2xl">
<LoadingStatus />
<DisplayRow title={t('account:name')} keyWidth="w-48">
{submission.name}
</DisplayRow>

View file

@ -1,8 +1,9 @@
import { freeSewingConfig as config } from 'shared/config/freesewing.config.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useTranslation } from 'next-i18next'
import { useState, Fragment } from 'react'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Components
@ -118,7 +119,7 @@ const SupportType = ({ type, active, t, update }) => (
export const SupportForm = () => {
const { t } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const { account } = useAccount()
const backend = useBackend()
@ -212,7 +213,6 @@ export const SupportForm = () => {
return (
<div className="w-full max-w-4xl mx-auto">
<LoadingStatus />
<SupportType type={type} active={true} update={() => setType(false)} t={t} />
<StringInput
id="support-title"

View file

@ -1,8 +1,9 @@
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState } from 'react'
import { useState, useContext } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useTranslation } from 'next-i18next'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useRouter } from 'next/router'
// Components
@ -24,7 +25,7 @@ const DarkLink = ({ href, txt }) => (
export const Migrate = () => {
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus, loading } = useLoadingStatus()
const { loading, setLoadingStatus } = useContext(LoadingStatusContext)
const { setAccount, setSeenUser, setToken } = useAccount()
const router = useRouter()
@ -61,14 +62,12 @@ export const Migrate = () => {
if (result === 'success')
return (
<>
<LoadingStatus />
<FreeSewingAnimation />
</>
)
if (result === 'exists')
return (
<>
<LoadingStatus />
<h2 className="text-inherit">{t('signup:v3UserAlreadyExists')}</h2>
<Robot pose="shrug" className="m-auto w-56 text-inherit" embed />
<Link href="/signin" className="btn btn-primary w-full my-4">
@ -87,7 +86,6 @@ export const Migrate = () => {
if (result === 'failed')
return (
<>
<LoadingStatus />
<h2 className="text-inherit">{t('signup:noWorkie')}</h2>
<Robot pose="ohno" className="m-auto w-56 text-inherit" embed />
<Link href="/signup" className="btn btn-primary w-full my-4">
@ -106,7 +104,6 @@ export const Migrate = () => {
return (
<>
<LoadingStatus />
<h2 className="text-inherit">{t('signup:migrateV2')}</h2>
<p className="text-inherit">{t('migrateV2Desc')}</p>
<div className="text-base-content">

View file

@ -1,10 +1,11 @@
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState, useEffect } from 'react'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useTranslation } from 'next-i18next'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useRouter } from 'next/router'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { horFlexClasses, horFlexClassesNoSm, capitalize } from 'shared/utils.mjs'
// Components
import Link from 'next/link'
@ -28,7 +29,7 @@ export const SignIn = () => {
const { t, i18n } = useTranslation(ns)
const backend = useBackend()
const router = useRouter()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
@ -117,7 +118,6 @@ export const SignIn = () => {
if (magicLinkSent)
return (
<>
<LoadingStatus />
<h1 className="text-inherit text-3xl lg:text-5xl mb-4 pb-0 text-center">
{t('susi:emailSent')}
</h1>
@ -138,7 +138,6 @@ export const SignIn = () => {
return (
<>
<LoadingStatus />
<h2>{seenBefore ? t('susi:welcomeBackName', { name: seenUser }) : t('susi:welcome')}</h2>
<p>{t('susi:signInToThing', { thing: 'FreeSewing' })}:</p>
{!seenBefore && (

View file

@ -2,8 +2,8 @@
import { useState, useContext } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useTranslation } from 'next-i18next'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
import { ModalContext } from 'shared/context/modal-context.mjs'
// Dependencies
import { validateEmail, validateTld, horFlexClasses, horFlexClassesNoSm } from 'shared/utils.mjs'
@ -32,7 +32,7 @@ export const SignUp = () => {
const backend = useBackend()
const { t, i18n } = useTranslation(ns)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [email, setEmail] = useState('')
const [emailValid, setEmailValid] = useState(false)
@ -98,7 +98,6 @@ export const SignUp = () => {
return (
<div className="w-full">
<LoadingStatus />
<h2 className="text-inherit">
{result ? (
result === 'success' ? (

View file

@ -1,22 +1,26 @@
// Dependencies
import yaml from 'js-yaml'
import { validateSettings } from './settings-validator.mjs'
import { capitalize } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useEffect, useState, useRef, useMemo } from 'react'
import { useTranslation } from 'next-i18next'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Components
import { CloseIcon } from 'shared/components/icons.mjs'
import { capitalize } from 'shared/utils.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
export const ns = ['wbedit']
export const ns = []
/** a view for editing the gist as yaml */
export const EditView = ({ settings, setSettings, design, Design }) => {
const inputRef = useRef(null)
const { setLoadingStatus } = useContext(LoadingStatusContext)
const [error, setError] = useState(false)
const [success, setSuccess] = useState(false)
const { t } = useTranslation(ns)
const patternConfig = useMemo(() => new Design().getConfig(), [Design])
const toast = useToast()
// parse the settings to yaml and set them as the value on the textArea
useEffect(() => {
@ -29,6 +33,7 @@ export const EditView = ({ settings, setSettings, design, Design }) => {
setSuccess(false)
try {
setLoadingStatus([true, 'status:contactingBackend'])
// parse back to json
const editedAsJson = yaml.load(inputRef.current.value)
@ -43,7 +48,7 @@ export const EditView = ({ settings, setSettings, design, Design }) => {
// save regardless
setSettings(editedAsJson)
setSuccess(true)
if (validation.valid) toast.success(t('success'))
if (validation.valid) setLoadingStatus([true, 'status:settingsSaved', true, true])
} catch (e) {
console.log(e)
setError(e.message)

View file

@ -1,14 +1,17 @@
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { Popout } from 'shared/components/popout/index.mjs'
import { WebLink } from 'shared/components/link.mjs'
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Dependencies
import {
exportTypes,
handleExport,
ns as exportNs,
} from 'shared/components/workbench/exporting/export-handler.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Components
import { Popout } from 'shared/components/popout/index.mjs'
import { WebLink } from 'shared/components/link.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
export const ns = ['exporting', exportNs]
@ -16,8 +19,10 @@ export const ns = ['exporting', exportNs]
export const ExportView = ({ settings, ui, design, Design }) => {
const [link, setLink] = useState(false)
const [format, setFormat] = useState(false)
const { startLoading, stopLoading } = useContext(LoadingContext)
const toast = useToast()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const startLoading = () => setLoadingStatus([true, 'exporting'])
const stopLoading = () => setLoadingStatus([true, 'status:nailedIt', true, true])
const { t } = useTranslation(ns)
const doExport = (format) => {
@ -38,7 +43,7 @@ export const ExportView = ({ settings, ui, design, Design }) => {
}
},
onError: (e) => {
if (e.data?.error) toast.error(e.data.error.message)
if (e.data?.error) setLoadingStatus([true, e.data.error.message, true, false])
},
})
}

View file

@ -5,7 +5,8 @@ import { ns as authNs } from 'shared/components/wrappers/auth/index.mjs'
import { designMeasurements, horFlexClasses } from 'shared/utils.mjs'
// Hooks
import { useTranslation } from 'next-i18next'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import {
UserSetPicker,
@ -24,7 +25,7 @@ const iconClasses = { className: 'w-8 h-8 md:w-10 md:h-10 lg:w-12 lg:h-12 shrink
export const MeasiesView = ({ design, Design, settings, update, missingMeasurements, setView }) => {
const { t } = useTranslation(['workbench'])
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
const loadMeasurements = (set) => {
update.settings([
@ -37,7 +38,6 @@ export const MeasiesView = ({ design, Design, settings, update, missingMeasureme
return (
<div className="max-w-7xl mt-8 mx-auto px-4">
<LoadingStatus />
<h2>{t('account:measurements')}</h2>
{missingMeasurements &&
settings.measurements &&

View file

@ -1,18 +1,21 @@
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { pagesPlugin } from 'shared/plugins/plugin-layout-part.mjs'
// Dependencies
import { nsMerge } from 'shared/utils.mjs'
import {
handleExport,
ns as exportNs,
} from 'shared/components/workbench/exporting/export-handler.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { pagesPlugin } from 'shared/plugins/plugin-layout-part.mjs'
import get from 'lodash.get'
import { defaultPrintSettings, printSettingsPath } from './config.mjs'
// Hooks
import { useContext } from 'react'
import { useTranslation } from 'next-i18next'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { MovablePattern } from 'shared/components/workbench/pattern/movable/index.mjs'
import { PrintMenu, ns as menuNs } from './menu.mjs'
import { defaultPrintSettings, printSettingsPath } from './config.mjs'
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
import { nsMerge } from 'shared/utils.mjs'
export const ns = nsMerge(menuNs, wrapperNs, exportNs, 'print', 'status')
@ -30,8 +33,7 @@ export const PrintView = ({
Design,
}) => {
const { t } = useTranslation(ns)
const loading = useContext(LoadingContext)
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { loading, setLoadingStatus } = useContext(LoadingStatusContext)
const defaultSettings = defaultPrintSettings(settings.units)
// add the pages plugin to the draft
@ -74,7 +76,6 @@ export const PrintView = ({
return (
<>
<LoadingStatus />
<PatternWithMenu
noHeader
{...{

View file

@ -1,12 +1,13 @@
// Dependencies
import { capitalize, shortDate, notEmpty, horFlexClassesNoSm } from 'shared/utils.mjs'
import yaml from 'js-yaml'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useState } from 'react'
import { useTranslation } from 'next-i18next'
import { useRouter } from 'next/router'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
// Components
import { AuthWrapper } from 'shared/components/wrappers/auth/index.mjs'
import { StringInput, MarkdownInput } from 'shared/components/inputs.mjs'
@ -22,7 +23,7 @@ export const SaveView = ({ design, settings }) => {
const { t } = useTranslation(ns)
const backend = useBackend()
const router = useRouter()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// State
const [name, setName] = useState(`${capitalize(design)} / ${shortDate(router.locale)}`)
@ -80,7 +81,6 @@ export const SaveView = ({ design, settings }) => {
return (
<AuthWrapper>
<LoadingStatus />
<div className="m-auto mt-8 max-w-2xl px-4">
<h2>{t('workbench:savePattern')}</h2>
{savedId && (

View file

@ -1,8 +1,14 @@
// Dependencies
import { capitalize, shortDate } from 'shared/utils.mjs'
// Hooks
import { useContext, useMemo } from 'react'
import { PanZoomContext } from 'shared/components/workbench/pattern/pan-zoom-context.mjs'
import { useMobileAction } from 'shared/context/mobile-menubar-context.mjs'
import { useTranslation } from 'next-i18next'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Components
import { PanZoomContext } from 'shared/components/workbench/pattern/pan-zoom-context.mjs'
import {
PaperlessIcon,
SaIcon,
@ -17,8 +23,6 @@ import {
ZoomOutIcon,
} from 'shared/components/icons.mjs'
import { shownHeaderSelector } from 'shared/components/wrappers/header.mjs'
import { useLoadingStatus } from 'shared/hooks/use-loading-status.mjs'
import { capitalize, shortDate } from 'shared/utils.mjs'
export const ns = ['common', 'core-settings', 'ui-settings']
@ -73,7 +77,7 @@ export const ViewHeader = ({ update, settings, ui, control, account, design, set
const { t, i18n } = useTranslation(ns)
const { zoomFunctions, zoomed } = useContext(PanZoomContext)
const backend = useBackend()
const { setLoadingStatus, LoadingStatus } = useLoadingStatus()
const { setLoadingStatus } = useContext(LoadingStatusContext)
// make the zoom buttons so we can pass them to the mobile menubar
const headerZoomButtons = useMemo(
@ -127,7 +131,6 @@ export const ViewHeader = ({ update, settings, ui, control, account, design, set
'lg:top-24'
)} transition-[top] duration-300 ease-in-out`}
>
<LoadingStatus />
<div className="hidden lg:flex flex-row flex-wrap gap-4 py-4 pt-8 w-full bg-neutral text-neutral-content items-center justify-center">
{headerZoomButtons}
<Spacer />

View file

@ -1,14 +1,14 @@
import { ModalContextProvider } from 'shared/context/modal-context.mjs'
import { LoadingContextProvider } from 'shared/context/loading-context.mjs'
import { LoadingStatusContextProvider } from 'shared/context/loading-status-context.mjs'
import { NavigationContextProvider } from 'shared/context/navigation-context.mjs'
import { MobileMenubarContextProvider } from 'shared/context/mobile-menubar-context.mjs'
export const ContextWrapper = ({ children }) => (
<ModalContextProvider>
<LoadingContextProvider>
<LoadingStatusContextProvider>
<NavigationContextProvider>
<MobileMenubarContextProvider>{children}</MobileMenubarContextProvider>
</NavigationContextProvider>
</LoadingContextProvider>
</LoadingStatusContextProvider>
</ModalContextProvider>
)

View file

@ -1,10 +1,11 @@
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useContext } from 'react'
import { LoadingContext } from 'shared/context/loading-context.mjs'
import { Ribbon } from 'shared/components/ribbon.mjs'
export const HeaderWrapper = ({ show, children }) => {
const { loading } = useContext(LoadingContext)
const { loading } = useContext(LoadingStatusContext)
return (
<header
className={`

View file

@ -1,6 +1,8 @@
// Dependencies
import React, { useState, useEffect, useContext } from 'react'
import { nsMerge } from 'shared/utils.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
// Hooks
import { useTheme } from 'shared/hooks/use-theme.mjs'
// Components
@ -11,7 +13,7 @@ import { DefaultLayout, ns as defaultLayoutNs } from 'site/components/layouts/de
import { Feeds } from 'site/components/feeds.mjs'
import { ModalContext } from 'shared/context/modal-context.mjs'
export const ns = nsMerge(layoutNs, defaultLayoutNs, 'common')
export const ns = nsMerge(layoutNs, defaultLayoutNs, 'status')
/* This component should wrap all page content */
export const PageWrapper = (props) => {
@ -32,6 +34,7 @@ export const PageWrapper = (props) => {
* Contexts
*/
const { modalContent } = useContext(ModalContext)
const { LoadingStatus } = useContext(LoadingStatusContext)
/*
* This forces a re-render upon initial bootstrap of the app
@ -59,6 +62,7 @@ export const PageWrapper = (props) => {
data-theme={currentTheme} // This facilitates CSS selectors
key={currentTheme} // This forces the data-theme update
>
<LoadingStatus />
<Feeds />
<LayoutWrapper {...childProps}>
{Layout ? <Layout {...childProps}>{children}</Layout> : children}

View file

@ -1,24 +0,0 @@
import React, { useState } from 'react'
export const LoadingContext = React.createContext(false)
export const LoadingContextProvider = ({ children }) => {
function stopLoading() {
__setLoading({ ...__loading, loading: false })
}
function startLoading() {
__setLoading({ ...__loading, loading: true })
}
function setLoading(loading) {
__setLoading({ ...__loading, loading })
}
const [__loading, __setLoading] = useState({
setLoading,
startLoading,
stopLoading,
loading: false,
})
return <LoadingContext.Provider value={__loading}>{children}</LoadingContext.Provider>
}

View file

@ -1,10 +1,12 @@
import { useState, useEffect } from 'react'
import { useState, useEffect, createContext } from 'react'
import { Spinner } from 'shared/components/spinner.mjs'
import { OkIcon, WarningIcon } from 'shared/components/icons.mjs'
import { useTranslation } from 'next-i18next'
export const ns = ['status']
export const LoadingStatusContext = createContext([false])
/*
* Timeout in seconds before the loading status dissapears
*/
@ -20,12 +22,9 @@ const LoadingStatus = ({ loadingStatus }) => {
if (loadingStatus[2]) {
if (timer) clearTimeout(timer)
setTimer(
window.setTimeout(
() => {
window.setTimeout(() => {
setFade('opacity-0')
},
timeout * 1000 - 350
)
}, timeout * 1000 - 350)
)
}
}, [loadingStatus[2]])
@ -66,7 +65,7 @@ const LoadingProgress = ({ val = 0, max = 1, msg }) => (
</div>
)
export const useLoadingStatus = () => {
export const LoadingStatusContextProvider = ({ children }) => {
/*
* LoadingStatus should hold an array with 1 to 4 elements:
* 0 => Show loading status or not (true or false)
@ -74,11 +73,18 @@ export const useLoadingStatus = () => {
* 2 => Set this to true to make the loadingStatus dissapear after 2 seconds
* 3 => Set this to true to show success, false to show error (only when 2 is true)
*/
const [loadingStatus, setLoadingStatus] = useState([false])
const [timer, setTimer] = useState(false)
const [__loadingStatus, __setLoadingStatus] = useState({
status: [false],
setLoadingStatus,
loading: false,
LoadingStatus: () => <LoadingStatus loadingStatus={[false]} />,
LoadingProgress,
})
useEffect(() => {
if (loadingStatus[2]) {
if (__loadingStatus.status[2]) {
if (timer) clearTimeout(timer)
setTimer(
window.setTimeout(() => {
@ -86,12 +92,20 @@ export const useLoadingStatus = () => {
}, timeout * 1000)
)
}
}, [loadingStatus[2]])
}, [__loadingStatus.status[2]])
return {
setLoadingStatus,
loading: loadingStatus[0],
LoadingStatus: () => <LoadingStatus loadingStatus={loadingStatus} />,
LoadingProgress,
function setLoadingStatus(newStatus) {
__setLoadingStatus({
...__loadingStatus,
status: newStatus,
loading: newStatus[0] || false,
LoadingStatus: () => <LoadingStatus loadingStatus={newStatus} />,
})
}
return (
<LoadingStatusContext.Provider value={__loadingStatus}>
{children}
</LoadingStatusContext.Provider>
)
}

View file

@ -1,54 +0,0 @@
import { useTranslation } from 'next-i18next'
import toastMethod from 'react-hot-toast'
import { OkIcon, NoIcon, TipIcon, WarningIcon, ChatIcon } from 'shared/components/icons.mjs'
const icons = {
success: <OkIcon className="w-6 h-6 text-success" />,
error: <NoIcon className="w-6 h-6 text-error" />,
info: <TipIcon className="w-6 h-6 text-info" />,
warning: <WarningIcon className="w-6 h-6 text-warning" />,
accent: <ChatIcon className="w-6 h-6 text-accent" />,
}
const Toast = ({ type = 'info', children }) => (
<div className={`w-64 alert shadow bg-base-100 p-0`}>
<div
className={`w-full m-0 bg-${type} p-4 border bg-opacity-30 rounded-lg flex flex-row items-center`}
>
{icons[type]}
<div>{children}</div>
</div>
</div>
)
/* Custom toast methods */
const toastMethods = (t) => ({
info: (children) => toastMethod.custom(<Toast type="info">{children}</Toast>),
warning: (children) => toastMethod.custom(<Toast type="warning">{children}</Toast>),
error: (children) => toastMethod.custom(<Toast type="error">{children}</Toast>),
accent: (children) => toastMethod.custom(<Toast type="accent">{children}</Toast>),
success: (children) => toastMethod.custom(<Toast type="success">{children}</Toast>),
for: {
settingsSaved: () =>
toastMethod.custom(
<Toast type="success">
<span>{t('settingsSaved')}</span>
</Toast>
),
backendError: () =>
toastMethod.custom(
<Toast type="error">
<span>{t('backendError')} ¯\_()_/¯</span>
</Toast>
),
},
})
/*
* The toast hook
*/
export function useToast() {
const { t } = useTranslation(['toast'])
return toastMethods(t)
}

View file

@ -22,3 +22,4 @@ toc: Table of contents
credits: Credits
contentsBy: Contents by
translators: Translators
title: Title