feat: Created home page
1
.gitignore
vendored
|
@ -53,6 +53,7 @@ sites/org/authors.json
|
|||
sites/org/showcase-tags.mjs
|
||||
sites/org/design-examples.mjs
|
||||
sites/org/docs/designs/*.mdx
|
||||
sites/org/recent-blog-posts.mjs
|
||||
|
||||
# sde auto-generated content
|
||||
sites/sde/public/android-chrome-192x192.png
|
||||
|
|
|
@ -101,6 +101,7 @@ packageJson:
|
|||
"./components/Null": "./components/Null/index.mjs"
|
||||
"./components/Number": "./components/Number/index.mjs"
|
||||
"./components/Pattern": "./components/Pattern/index.mjs"
|
||||
"./components/Patrons": "./components/Patrons/index.mjs"
|
||||
"./components/Popout": "./components/Popout/index.mjs"
|
||||
"./components/Role": "./components/Role/index.mjs"
|
||||
"./components/SignIn": "./components/SignIn/index.mjs"
|
||||
|
|
|
@ -55,12 +55,27 @@ export const SuccessLink = ({
|
|||
</a>
|
||||
)
|
||||
|
||||
export const CardLink = ({ href, title, Icon, children, Link }) => {
|
||||
export const CardLink = ({
|
||||
href,
|
||||
title,
|
||||
icon,
|
||||
children,
|
||||
Link,
|
||||
className = 'tw-bg-base-200 tw-text-base-content',
|
||||
}) => {
|
||||
if (!Link) Link = BaseLink
|
||||
|
||||
return (
|
||||
<Link className="">
|
||||
{title}
|
||||
<Link
|
||||
href={href}
|
||||
className={`tw-px-8 tw-py-10 tw-rounded-lg tw-block ${className}
|
||||
hover:tw-bg-secondary hover:tw-bg-opacity-10 tw-shadow-lg
|
||||
tw-transition-color tw-duration-300 grow hover:tw-no-underline hover:tw-text-base-content`}
|
||||
>
|
||||
<h2 className="tw-mb-4 tw-text-inherit tw-flex tw-flex-row tw-gap-4 tw-justify-between tw-items-center">
|
||||
{title}
|
||||
<span className="tw-shrink-0">{icon}</span>
|
||||
</h2>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
|
|
309
packages/react/components/Patrons/index.mjs
Normal file
|
@ -26,7 +26,7 @@ import { EmailInput } from '@freesewing/react/components/Input'
|
|||
import { IconButton } from '@freesewing/react/components/Button'
|
||||
//import { Robot } from 'shared/components/robot/index.mjs'
|
||||
|
||||
export const SignUp = () => {
|
||||
export const SignUp = ({ embed = false }) => {
|
||||
// State
|
||||
const [email, setEmail] = useState('')
|
||||
const [emailValid, setEmailValid] = useState(false)
|
||||
|
@ -56,22 +56,22 @@ export const SignUp = () => {
|
|||
if (status === 201 && body.result === 'created') setResult('success')
|
||||
else {
|
||||
setModal(
|
||||
<ModalWrapper bg="base-100 lg:bg-base-300">
|
||||
<div className="bg-base-100 rounded-lg p-4 lg:px-8 max-w-xl lg:shadow-lg">
|
||||
<ModalWrapper bg="tw-base-100 lg:tw-bg-base-300">
|
||||
<div className="tw-bg-base-100 tw-rounded-lg tw-p-4 lg:tw-px-8 tw-max-w-xl lg:tw-shadow-lg">
|
||||
<h3>An error occured while trying to process your request</h3>
|
||||
<p className="text-lg">
|
||||
<p className="tw-text-lg">
|
||||
Unfortunately, we cannot recover from this error, we need a human being to look into
|
||||
this.
|
||||
</p>
|
||||
<p className="text-lg">
|
||||
<p className="tw-text-lg">
|
||||
Feel free to try again, or reach out to support so we can assist you.
|
||||
</p>
|
||||
<div className="flex flex-row gap-4 items-center justify-center p-8 flex-wrap">
|
||||
<div className="tw-flex tw-flex-row tw-gap-4 tw-items-center tw-justify-center tw-p-8 tw-flex-wrap">
|
||||
<IconButton onClick={() => setResult(false)}>
|
||||
<LeftIcon />
|
||||
Back
|
||||
</IconButton>
|
||||
<IconButton href="/support" className="daisy-btn-outline">
|
||||
<IconButton href="/support" className="tw-daisy-btn-outline">
|
||||
<HelpIcon />
|
||||
Contact support
|
||||
</IconButton>
|
||||
|
@ -90,10 +90,13 @@ export const SignUp = () => {
|
|||
window.location.href = result.data.authUrl
|
||||
}
|
||||
}
|
||||
const Heading = embed
|
||||
? ({ children }) => <h2 className="tw-text-inherit">{children}</h2>
|
||||
: ({ children }) => <h1 className="tw-text-inherit">{children}</h1>
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<h1 className="text-inherit">
|
||||
<div className="tw-w-full">
|
||||
<Heading className="tw-text-inherit">
|
||||
{result ? (
|
||||
result === 'success' ? (
|
||||
<span>Now check your inbox</span>
|
||||
|
@ -103,23 +106,23 @@ export const SignUp = () => {
|
|||
) : (
|
||||
<span>Create a FreeSewing account</span>
|
||||
)}
|
||||
</h1>
|
||||
</Heading>
|
||||
|
||||
{result ? (
|
||||
result === 'success' ? (
|
||||
<>
|
||||
<p className="text-inherit text-lg">
|
||||
<p className="tw-text-inherit tw-text-lg">
|
||||
Go check your inbox for an email from <b>FreeSewing.org</b>
|
||||
</p>
|
||||
<p className="text-inherit text-lg">
|
||||
<p className="tw-text-inherit tw-text-lg">
|
||||
Click your personal signup link in that email to create your FreeSewing account.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-2">
|
||||
<IconButton onClick={() => setResult(false)}>
|
||||
<LeftIcon />
|
||||
Back
|
||||
</IconButton>
|
||||
<IconButton href="/support" className="daisy-btn-outline">
|
||||
<IconButton href="/support" className="tw-daisy-btn-outline">
|
||||
<HelpIcon />
|
||||
Contact support
|
||||
</IconButton>
|
||||
|
@ -128,18 +131,18 @@ export const SignUp = () => {
|
|||
) : (
|
||||
<>
|
||||
robot here
|
||||
<p className="text-inherit text-lg">
|
||||
<p className="tw-text-inherit tw-text-lg">
|
||||
Unfortunately, we cannot recover from this error, we need a human being to look into
|
||||
this.
|
||||
</p>
|
||||
<p className="text-inherit text-lg">
|
||||
<p className="tw-text-inherit tw-text-lg">
|
||||
Feel free to try again, or reach out to support so we can assist you.
|
||||
</p>
|
||||
<div className="flex flex-row gap-4 items-center justify-center p-8">
|
||||
<button className="btn btn-ghost" onClick={() => setResult(false)}>
|
||||
<div className="tw-flex tw-flex-row tw-gap-4 tw-items-center tw-justify-center tw-p-8">
|
||||
<button className="tw-daisy-btn tw-daisy-btn-ghost" onClick={() => setResult(false)}>
|
||||
Back
|
||||
</button>
|
||||
<Link href="/support" className="btn btn-ghost">
|
||||
<Link href="/support" className="tw-daisy-btn tw-daisy-btn-ghost">
|
||||
Contact support
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -147,7 +150,7 @@ export const SignUp = () => {
|
|||
)
|
||||
) : (
|
||||
<>
|
||||
<p className="text-inherit">To receive a sign-up link, enter your email address</p>
|
||||
<p className="tw-text-inherit">To receive a sign-up link, enter your email address</p>
|
||||
<form onSubmit={signupHandler}>
|
||||
<EmailInput
|
||||
id="signup-email"
|
||||
|
@ -161,7 +164,7 @@ export const SignUp = () => {
|
|||
<IconButton
|
||||
onClick={signupHandler}
|
||||
btnProps={{ type: 'submit' }}
|
||||
className="lg:w-full grow"
|
||||
className="lg:tw-w-full tw-grow tw-mt-2"
|
||||
>
|
||||
<EmailIcon />
|
||||
Email me a sign-up link
|
||||
|
@ -169,7 +172,7 @@ export const SignUp = () => {
|
|||
</form>
|
||||
{showAll ? (
|
||||
<>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-1 items-center">
|
||||
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-1 tw-items-center tw-mt-1">
|
||||
{['Google', 'GitHub'].map((provider) => (
|
||||
<IconButton
|
||||
key={provider}
|
||||
|
@ -182,22 +185,22 @@ export const SignUp = () => {
|
|||
</IconButton>
|
||||
))}
|
||||
</div>
|
||||
<IconButton color="neutral" href="/signin" className="daisy-btn-lg">
|
||||
<span className="hidden md:block">
|
||||
<KeyIcon className="h-10 w-10" />
|
||||
<IconButton color="neutral" href="/signin" className="tw-daisy-btn-lg tw-mt-1">
|
||||
<span className="tw-hidden md:tw-block">
|
||||
<KeyIcon className="tw-h-10 tw-w-10" />
|
||||
</span>
|
||||
Sign in here
|
||||
</IconButton>
|
||||
<div className="flex flex-row justify-center mt-2">
|
||||
<div className="tw-flex tw-flex-row tw-justify-center tw-mt-2">
|
||||
<IconButton color="ghost" onClick={() => setShowAll(false)}>
|
||||
<DownIcon className="w-6 h-6 rotate-180" />
|
||||
<DownIcon className="tw-w-6 tw-h-6 tw-rotate-180" />
|
||||
Fewer options
|
||||
<DownIcon className="w-6 h-6 rotate-180" />
|
||||
<DownIcon className="tw-w-6 tw-h-6 tw-rotate-180" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex flex-row justify-center mt-2">
|
||||
<div className="tw-flex tw-flex-row tw-justify-center tw-mt-2">
|
||||
<IconButton color="ghost" onClick={() => setShowAll(true)}>
|
||||
<DownIcon />
|
||||
More options
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
"./components/Null": "./components/Null/index.mjs",
|
||||
"./components/Number": "./components/Number/index.mjs",
|
||||
"./components/Pattern": "./components/Pattern/index.mjs",
|
||||
"./components/Patrons": "./components/Patrons/index.mjs",
|
||||
"./components/Popout": "./components/Popout/index.mjs",
|
||||
"./components/Role": "./components/Role/index.mjs",
|
||||
"./components/SignIn": "./components/SignIn/index.mjs",
|
||||
|
|
|
@ -268,65 +268,41 @@ const config = {
|
|||
{ to: '/showcase/', label: '📷 Showcase', position: 'left' },
|
||||
{ to: '/blog/', label: '📰 Blog', position: 'left' },
|
||||
{ to: '/new/', label: '➕ New...', position: 'right' },
|
||||
{ to: '/account/', label: '📰 Account', position: 'right' },
|
||||
{ to: '/account/', label: '🔒 Account', position: 'right' },
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
style: 'light',
|
||||
links: [
|
||||
{
|
||||
title: 'Docs',
|
||||
title: 'Sections',
|
||||
items: [
|
||||
{ label: 'FreeSewing designs', to: '/docs/designs/' },
|
||||
{ label: 'About FreeSewing', to: '/docs/about/' },
|
||||
{ label: 'Measurements we use', to: '/docs/measurements/' },
|
||||
{ label: 'Sewing terminology', to: '/docs/sewing/' },
|
||||
{ label: 'FreeSewing Designs', to: '/designs/' },
|
||||
{ label: 'FreeSewing Showcase', to: '/showcase/' },
|
||||
{ label: 'FreeSewing Blog', to: '/blog/' },
|
||||
{ label: 'FreeSewing Editor', to: '/editor/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Help & Support',
|
||||
items: [
|
||||
{
|
||||
label: 'Discord',
|
||||
href: 'https://discord.freesewing.org/',
|
||||
},
|
||||
{
|
||||
label: 'GitHub Issues',
|
||||
href: 'https://github.com/freesewing/freesewing/issues',
|
||||
},
|
||||
{
|
||||
label: 'GitHub Discussions',
|
||||
href: 'https://github.com/freesewing/freesewing/discussions',
|
||||
},
|
||||
{
|
||||
label: 'All Support Options',
|
||||
href: 'https://freesewing.org/support',
|
||||
},
|
||||
{ label: 'About FreeSewing', to: '/docs/about/' },
|
||||
{ label: 'Getting Started', to: '/docs/about/guide/' },
|
||||
{ label: 'Frequently Asked Questions', href: '/docs/about/faq/' },
|
||||
{ label: 'Need Help?', href: '/support' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'More',
|
||||
items: [
|
||||
{
|
||||
label: 'FreeSewing.org',
|
||||
to: 'https://freesewing.org/',
|
||||
},
|
||||
{
|
||||
label: 'Blog',
|
||||
to: 'https://freesewing.org/blog/',
|
||||
},
|
||||
{
|
||||
label: 'Showcase',
|
||||
to: 'https://freesewing.org/showccase/',
|
||||
},
|
||||
{
|
||||
label: 'Code on GitHub',
|
||||
href: 'https://github.com/freesewing/freesewing',
|
||||
},
|
||||
{ label: 'FreeSewing.dev', to: 'https://freesewing.dev/' },
|
||||
{ label: 'FreeSewing.social', to: 'https://freesewing.social/' },
|
||||
{ label: 'Code on GitHub', to: 'https://github.com/freesewing/freesewing' },
|
||||
{ label: 'FreeSewing Revenue Pledge 💜', href: '/docs/about/pledge/' },
|
||||
],
|
||||
},
|
||||
],
|
||||
copyright: `<a href="https://freesewing.org/">FreeSewing</a> is brought to you by <a href="https://github.com/joostdecock">Joost De Cock</a> and <a href="https://github.com/freesewing/freesewing/blob/develop/CONTRIBUTORS.md">contributors</a> with the financial support of <a href="https://freesewing.org/patrons/join">our patrons</a>`,
|
||||
copyright: `<a href="https://freesewing.org/">FreeSewing</a> is brought to you by <a href="https://github.com/joostdecock">Joost De Cock</a> and <a href="https://github.com/freesewing/freesewing/blob/develop/CONTRIBUTORS.md">contributors</a> with the financial support of <a href="/patrons/join">our patrons</a>`,
|
||||
},
|
||||
prism: {
|
||||
theme: prismThemes.dracula,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import fs from 'fs'
|
||||
import { glob } from 'glob'
|
||||
import matter from 'gray-matter'
|
||||
import { orderBy } from '../../../packages/utils/src/index.mjs'
|
||||
|
||||
const loadExamplesTagsAndAuthors = async () => {
|
||||
const lists = {
|
||||
|
@ -12,6 +13,7 @@ const loadExamplesTagsAndAuthors = async () => {
|
|||
const tags = []
|
||||
const authors = []
|
||||
const examples = {}
|
||||
const recentBlogPosts = []
|
||||
for (const type of Object.keys(lists)) {
|
||||
for (const file of lists[type]) {
|
||||
const content = await fs.readFileSync(file, 'utf-8')
|
||||
|
@ -32,7 +34,12 @@ const loadExamplesTagsAndAuthors = async () => {
|
|||
if (typeof examples[tag] === 'undefined') examples[tag] = []
|
||||
examples[tag].push({ title: data.data.title, id: file.split('/')[1] })
|
||||
}
|
||||
}
|
||||
} else if (type === 'blog')
|
||||
recentBlogPosts.push({
|
||||
title: data.data.title,
|
||||
slug: file.split('/')[1],
|
||||
date: new Date(data.data.date).getTime(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +47,7 @@ const loadExamplesTagsAndAuthors = async () => {
|
|||
authors: [...new Set(authors.sort())], // Make them unique
|
||||
tags: [...new Set(tags.sort())], // Make them unique
|
||||
examples,
|
||||
recentBlogPosts: orderBy(recentBlogPosts, 'date', 'desc').slice(0, 2),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +77,7 @@ const loadUser = async (id) => {
|
|||
|
||||
async function prebuild() {
|
||||
const all = {}
|
||||
const { authors, examples, tags } = await loadExamplesTagsAndAuthors()
|
||||
const { authors, examples, tags, recentBlogPosts } = await loadExamplesTagsAndAuthors()
|
||||
for (const author of authors) {
|
||||
const user = await loadUser(author)
|
||||
if (user.profile.id) all[user.profile.id] = userAsAuthor(user)
|
||||
|
@ -80,6 +88,10 @@ async function prebuild() {
|
|||
`export const tags = ${JSON.stringify([...new Set(tags.sort())])}`
|
||||
)
|
||||
fs.writeFileSync(`./design-examples.mjs`, `export const examples = ${JSON.stringify(examples)}`)
|
||||
fs.writeFileSync(
|
||||
`./recent-blog-posts.mjs`,
|
||||
`export const recentBlogPosts = ${JSON.stringify(recentBlogPosts, 0, 2)}`
|
||||
)
|
||||
}
|
||||
|
||||
prebuild()
|
||||
|
|
|
@ -1,84 +1,386 @@
|
|||
// Dependencies
|
||||
import { recentBlogPosts } from '@site/recent-blog-posts.mjs'
|
||||
// Hooks
|
||||
import { useState, useEffect } from 'react'
|
||||
// Components
|
||||
import Link from '@docusaurus/Link'
|
||||
import { DocusaurusPage } from '@freesewing/react/components/Docusaurus'
|
||||
import Layout from '@theme/Layout'
|
||||
import MDXContent from '@theme/MDXContent'
|
||||
import {
|
||||
ChatIcon,
|
||||
DesignIcon,
|
||||
DocsIcon,
|
||||
FreeSewingIcon,
|
||||
HelpIcon,
|
||||
NewsletterIcon,
|
||||
NoIcon,
|
||||
OkIcon,
|
||||
ShowcaseIcon,
|
||||
} from '@freesewing/react/components/Icon'
|
||||
import { SignUp } from '@freesewing/react/components/SignUp'
|
||||
import {
|
||||
HortensiaFront,
|
||||
HiFront,
|
||||
TeaganFront,
|
||||
AaronFront,
|
||||
AlbertFront,
|
||||
BruceBack,
|
||||
BruceFront,
|
||||
SimonBack,
|
||||
SimonFront,
|
||||
WahidBack,
|
||||
WahidFront,
|
||||
} from '@freesewing/react/components/LineDrawing'
|
||||
import { BlogPostTeaser } from '@site/src/theme/BlogPostItems/index.js'
|
||||
import { CardLink } from '@freesewing/react/components/Link'
|
||||
import { PleaseSubscribe } from '@freesewing/react/components/Patrons'
|
||||
|
||||
const styles = {
|
||||
top: {
|
||||
margin: 'auto',
|
||||
textAlign: 'center',
|
||||
paddingTop: '2rem',
|
||||
},
|
||||
logo: {
|
||||
maxWidth: '140px',
|
||||
},
|
||||
cards: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
maxWidth: '1600px',
|
||||
margin: 'auto',
|
||||
padding: '1rem',
|
||||
gap: '1.5rem',
|
||||
justifyContent: 'center',
|
||||
marginBottom: '3rem',
|
||||
},
|
||||
card: {
|
||||
width: '100%',
|
||||
maxWidth: '600px',
|
||||
boxShadow: '1px 1px 5px #0004',
|
||||
borderRadius: '0.5rem',
|
||||
padding: '1rem 1.5rem',
|
||||
backgroundColor: 'var(--ifm-footer-background-color)',
|
||||
},
|
||||
cardheading: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
cardicon: {
|
||||
fontSize: '2rem',
|
||||
},
|
||||
cardp: {
|
||||
fontSize: '1.15rem',
|
||||
},
|
||||
}
|
||||
|
||||
const Card = ({ title, icon, children, href }) => (
|
||||
<a style={styles.card} href={href}>
|
||||
<h3 style={styles.cardheading}>
|
||||
<span>{title}</span>
|
||||
<span style={styles.cardicon}>{icon}</span>
|
||||
</h3>
|
||||
const Card = ({ title, children, icon }) => (
|
||||
<div className={`tw-px-8 tw-bg-primary/5 tw-py-10 tw-rounded-lg tw-block tw-shadow-lg tw-grow`}>
|
||||
<h2 className="tw-mb-4 tw-text-inherit tw-flex tw-flex-row tw-gap-4 tw-justify-between tw-items-center tw-font-medium">
|
||||
{title}
|
||||
{icon}
|
||||
</h2>
|
||||
{children}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
|
||||
const meta = {
|
||||
title: 'Free Bespoke Sewing Patterns',
|
||||
description:
|
||||
'FreeSewing is open source software to generate bespoke sewing ' +
|
||||
'patterns, loved by home sewers and fashion entrepreneurs alike.',
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout
|
||||
title={`FreeSewing documentation for developers and contributors`}
|
||||
description="FreeSewing is an open source Javascript library for parametric sewing patterns"
|
||||
>
|
||||
<MDXContent>
|
||||
<div style={styles.top}>
|
||||
<h1>Fixme: Build home page</h1>
|
||||
<DocusaurusPage DocusaurusLayout={Layout} {...meta} Layout={false}>
|
||||
<div className="tw-max-w-7xl tw-mx-auto tw-my-12 tw-px-4">
|
||||
<div className="tw-text-center">
|
||||
<FreeSewingIcon className="tw-w-48 tw-h-48 tw-mx-auto tw-pr-3" />
|
||||
<h1 className="tw-font-black tw-text-5xl lg:tw-text-7xl tw-tracking-tighter tw-mb-0 tw-pb-0">
|
||||
FreeSewing
|
||||
</h1>
|
||||
<h2 className="tw-text-xl lg:tw-text-3xl tw-font-medium tw-tracking-tighter tw-mt-0 tw-pt-0">
|
||||
Free Bespoke Sewing Patterns
|
||||
</h2>
|
||||
</div>
|
||||
<div style={styles.cards}>
|
||||
<Card title="FreeSewing Designs" icon="🤓" href="/docs/designs/">
|
||||
<p style={styles.cardp}>Documentation for all our designs.</p>
|
||||
|
||||
<div className="tw-flex tw-flex-col tw-gap-8 md:tw-grid md:tw-grid-cols-2 md:tw-gap-4 tw-mt-12 md:tw-mt-20 md:tw-px-4">
|
||||
<Card
|
||||
title="What is FreeSewing?"
|
||||
icon={<OkIcon className="tw-w-12 tw-h-12 tw-text-success" stroke={4} />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-lg tw-mb-4">
|
||||
FreeSewing is open source software to generate bespoke sewing patterns, loved by home
|
||||
sewers and fashion entrepreneurs alike.
|
||||
</p>
|
||||
<p className="tw-font-medium tw-text-lg tw-mb-4">
|
||||
Industry sizing is a bunch of lies. Join the slow fashion revolution and enjoy clothes
|
||||
that fit you.
|
||||
</p>
|
||||
<p className="tw-font-medium tw-text-lg">
|
||||
Speaking of revolution, we do not tolerate nazis here.
|
||||
</p>
|
||||
</Card>
|
||||
<Card title="About FreeSewing" icon="👕" href="/docs/about/">
|
||||
<p style={styles.cardp}>Documentation about FreeSewing.org and how to use it.</p>
|
||||
</Card>
|
||||
<Card title="Measurements we use" icon="🚀" href="/docs/measurements/">
|
||||
<p style={styles.cardp}>Documentation for all the measurements we use.</p>
|
||||
</Card>
|
||||
<Card title="Sewing terminology" icon="🧑🤝🧑" href="/docs/sewing/">
|
||||
<p style={styles.cardp}>Documentation for various terms that are used in sewing.</p>
|
||||
<Card
|
||||
title="What is FreeSewing not?"
|
||||
icon={<NoIcon className="tw-w-12 tw-h-12 tw-text-error" stroke={3} />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-lg tw-mb-4">
|
||||
FreeSewing is not a company. We do not sell anything. We do not have staff or
|
||||
employees. We do not have an office. We do not get paid.
|
||||
</p>
|
||||
<p className="tw-font-medium tw-text-lg">
|
||||
Our website does not contain any advertising. We do not track you. We do not sell your
|
||||
personal data, or use it to train AI algorithms. We do not violate your privacy.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
</MDXContent>
|
||||
</Layout>
|
||||
|
||||
<div className="tw-text-center tw-mt-20 md:tw-mt-20">
|
||||
<HowDoesItWorkAnimation />
|
||||
</div>
|
||||
|
||||
<div className="tw-p-1 tw--mx-4 tw-bg-primary tw-bg-opacity-10 tw-mt-12 tw-rounded-none md:tw-rounded-lg lg:tw-rounded-xl md:tw-shadow-lg md:tw-mx-4 tw-p-8 lg:tw-px-12 md:tw-py-0">
|
||||
<div className="tw-flex tw-flex-col md:tw-gap-8 lg:tw-gap-12 md:tw-flex md:tw-flex-row tw-m-auto">
|
||||
<div className="tw--mx-4 md:tw-mx-0 md:tw-pt-8 tw-pb-8 lg:tw-py-12 tw-grow tw-m-auto tw-max-w-prose">
|
||||
<SignUp embed />
|
||||
</div>
|
||||
<div className="tw--mx-4 md:tw-mx-0 md:tw-mt-0 tw-pt-0 md:tw-pt-8 tw-pb-8 lg:tw-py-12 tw-max-w-prose tw-m-auto tw-m-auto">
|
||||
<h2 className="tw-text-inherit tw-mb-4 tw-hidden md:tw-block">Reasons to join</h2>
|
||||
<ul>
|
||||
{[0, 1, 2, 3].map((i) => (
|
||||
<li className="tw-flex tw-flex-row tw-gap-2 tw-my-2" key={i}>
|
||||
<OkIcon stroke={4} /> {reasonsToJoin[i]}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="tw-grid tw-grid-cols-1 tw-gap-2 lg:tw-grid-cols-2 tw-max-w-7xl tw-my-16">
|
||||
{recentBlogPosts.map((post) => (
|
||||
<BlogPostTeaser
|
||||
key={post.slug}
|
||||
post={{
|
||||
content: {
|
||||
metadata: {
|
||||
permalink: `/blog/${post.slug}`,
|
||||
title: post.title,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="tw-flex tw-flex-col md:tw-grid md:tw-grid-cols-2 tw-gap-4 tw-max-w-7xl tw-m-auto tw-mb-24">
|
||||
<CardLink
|
||||
Link={Link}
|
||||
href="/designs"
|
||||
title="Designs"
|
||||
icon={<DesignIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
Browse our collection of designs, and turn them into sewing patterns that are
|
||||
made-to-measure just for you.
|
||||
</p>
|
||||
</CardLink>
|
||||
<CardLink
|
||||
Link={Link}
|
||||
href="/showcase"
|
||||
title="Showcase"
|
||||
icon={<ShowcaseIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
Get inspiration from the FreeSewing community, and see how others have applied their
|
||||
creativity to our designs.
|
||||
</p>
|
||||
</CardLink>
|
||||
<CardLink
|
||||
Link={Link}
|
||||
href="/docs/about/guide"
|
||||
title="Getting Started"
|
||||
icon={<DocsIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
FreeSewing.org is unlike any sewing pattern website you know. Read this short guide to
|
||||
get the most our of our platform.
|
||||
</p>
|
||||
</CardLink>
|
||||
<CardLink
|
||||
Link={Link}
|
||||
href="/docs/about/faq"
|
||||
title="Frequently Asked Questions"
|
||||
icon={<HelpIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
Some of the questions that come up often when people discover our platform are
|
||||
answered here.
|
||||
</p>
|
||||
</CardLink>
|
||||
</div>
|
||||
|
||||
<div className="lg:px-4 max-w-7xl mx-auto">
|
||||
<PleaseSubscribe />
|
||||
</div>
|
||||
|
||||
<div className="tw-flex tw-flex-col md:tw-grid md:tw-grid-cols-2 tw-gap-4 tw-max-w-7xl tw-m-auto tw-mb-24">
|
||||
<CardLink
|
||||
href="/newsletter"
|
||||
title="FreeSewing Newsletter"
|
||||
icon={<NewsletterIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
Subscribe to our newsletter and once every 3 months you'll receive an email from us
|
||||
with honest wholesome content. No tracking, no ads, no nonsense.
|
||||
</p>
|
||||
</CardLink>
|
||||
<CardLink
|
||||
href="/support"
|
||||
title="Need Help?"
|
||||
icon={<ChatIcon className="tw-w-12 tw-h-12 tw-shrink-0" />}
|
||||
>
|
||||
<p className="tw-font-medium tw-text-inherit tw-italic tw-text-lg">
|
||||
While we are all volunteers, we have a good track record of helping people. So don't
|
||||
be shy to reach out.
|
||||
</p>
|
||||
</CardLink>
|
||||
</div>
|
||||
</div>
|
||||
</DocusaurusPage>
|
||||
)
|
||||
}
|
||||
|
||||
const HowDoesItWorkAnimation = () => {
|
||||
const [step, setStep] = useState(0)
|
||||
const [halfStep, setHalfStep] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (step > 6) setStep(0)
|
||||
else setStep(step + 1)
|
||||
if (halfStep > 7) setHalfStep(0)
|
||||
else setHalfStep(halfStep + 0.5)
|
||||
}, 800)
|
||||
}, [step])
|
||||
|
||||
return (
|
||||
<div className="tw-flex tw-flex-col md:tw-grid md:tw-grid-cols-3 tw-my-12">
|
||||
<div className="tw-relative tw-w-full">
|
||||
<div className="tw-relative tw-h-72 md:tw-h-96 tw-overflow-hidden">
|
||||
{slides.map((i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`tw-duration-700 tw-ease-in-out tw-transition-all ${
|
||||
step === i ? 'tw-opacity-1' : 'tw-opacity-0'
|
||||
} tw-absolute tw-top-0 tw-text-center tw-w-full`}
|
||||
>
|
||||
<div className="tw-w-full tw-flex tw-flex-row tw-items-center tw-h-72 md:tw-h-96 tw-w-full tw-justify-center">
|
||||
{lineDrawings[i]}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Nr nr={1} />
|
||||
<Title txt="Pick Any Design" />
|
||||
</div>
|
||||
<div className="tw-relative tw-w-full">
|
||||
<div className="tw-relative tw-h-72 md:tw-h-96 tw-overflow-hidden">
|
||||
{slides.map((i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`tw-duration-700 tw-ease-in-out tw-transition-all ${
|
||||
Math.floor(halfStep) === i ? 'tw-opacity-1' : 'tw-opacity-0'
|
||||
} tw-absolute tw-top-0 tw-text-center tw-w-full`}
|
||||
>
|
||||
<div className="tw-w-full tw-flex tw-flex-row tw-items-center tw-h-72 md:tw-h-96 tw-w-full tw-justify-center">
|
||||
<img
|
||||
src={`/img/models/model-${i}.png`}
|
||||
className="tw-h-72 md:tw-h-96 tw-shrink-0 tw-px-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Nr nr={2} />
|
||||
<Title txt="Add a set of measurements" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="tw-relative tw-w-full">
|
||||
<div className="tw-relative tw-h-96 tw-overflow-hidden">
|
||||
<div className="tw-w-full tw-flex tw-flex-row tw-items-center tw-h-72 md:tw-h-96 tw-w-full tw-justify-center">
|
||||
<Pattern key={step} i={step} />
|
||||
</div>
|
||||
<Nr nr={3} />
|
||||
<Title txt="Customize your pattern" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const reasonsToJoin = [
|
||||
'Generate bespoke sewing patterns.',
|
||||
'Store your patterns & measurements sets.',
|
||||
'Share your creations with the community.',
|
||||
'Open source. No ads. No nonsense.',
|
||||
]
|
||||
|
||||
const lineDrawings = [
|
||||
<AaronFront key={1} className="tw-h-72 md:tw-h-96" />,
|
||||
<HiFront key={2} className="tw-h-72 md:tw-h-96" />,
|
||||
<TeaganFront key={3} className="tw-h-72 md:tw-h-96" />,
|
||||
<WahidFront key={4} className="tw-h-72 md:tw-h-96" />,
|
||||
<AlbertFront key={5} className="tw-h-72 md:tw-h-96" />,
|
||||
<BruceFront key={6} className="tw-h-72 md:tw-h-96" />,
|
||||
<SimonFront key={7} className="tw-h-72 md:tw-h-96" />,
|
||||
<HortensiaFront key={8} className="tw-h-72 md:tw-h-96" />,
|
||||
]
|
||||
|
||||
const patternTweaks = [
|
||||
<path
|
||||
key={1}
|
||||
d="M 0,121.4 L 0,705.1 L 253.46,705.1 C 253.46,474.02 281.12,307.05 281.12,307.05 C 187.15,307.05 128.12,163.24 163.07,19.43 L 119.46,8.83 C 92.11,121.4 92.11,121.4 0,121.4 z"
|
||||
/>,
|
||||
<path
|
||||
key={2}
|
||||
d="M 0,121.4 L 0,705.1 L 253.46,705.1 C 253.46,481 279.96,321 279.96,321 C 184.87,321 126.42,170.22 163.07,19.43 L 119.46,8.83 C 92.11,121.4 92.11,121.4 0,121.4 z"
|
||||
/>,
|
||||
<path
|
||||
key={3}
|
||||
d="M 0,121.4 L 0,705.1 L 253.46,705.1 C 253.46,481 273.47,321 273.47,321 C 181.62,321 126.42,170.22 163.07,19.43 L 119.46,8.83 C 92.11,121.4 92.11,121.4 0,121.4 z"
|
||||
/>,
|
||||
<path
|
||||
key={4}
|
||||
d="M 0,121.4 L 0,742.92 L 253.46,742.92 C 253.46,481 273.47,321 273.47,321 C 181.62,321 126.42,170.22 163.07,19.43 L 119.46,8.83 C 92.11,121.4 92.11,121.4 0,121.4 z"
|
||||
/>,
|
||||
<path
|
||||
key={5}
|
||||
d="M 0,121.4 L 0,742.92 L 253.46,742.92 C 253.46,481 273.47,321 273.47,321 C 181.62,321 126.42,170.22 163.07,19.43 L 119.46,8.83 C 95.69,106.65 80.04,121.4 0,121.4 z"
|
||||
/>,
|
||||
<path
|
||||
key={6}
|
||||
d="M 0,152.02 L 0,742.92 L 253.46,742.92 C 253.46,481 273.47,321 273.47,321 C 181.62,321 126.42,170.22 163.07,19.43 L 119.46,8.83 C 89.22,133.26 73.57,152.02 0,152.02 z"
|
||||
/>,
|
||||
<path
|
||||
key={7}
|
||||
d="M 0,152.02 L 0,742.92 L 253.46,742.92 C 253.46,481 273.47,321 273.47,321 C 183.55,321 130.16,170.66 166.7,20.31 L 123.1,9.71 C 93.04,133.38 76.92,152.02 0,152.02 z"
|
||||
/>,
|
||||
<path
|
||||
key={8}
|
||||
d="M 0,152.02 L 0,742.92 L 253.46,742.92 C 253.46,481 273.47,321 273.47,321 C 181.55,321 126.27,170.2 162.92,19.39 L 126.88,10.63 C 97.02,133.5 80.4,152.02 0,152.02 z"
|
||||
/>,
|
||||
]
|
||||
|
||||
const Pattern = ({ i }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="-300 -20 850 850"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="tw-fill-primary tw-h-72 md:tw-h-96"
|
||||
strokeWidth="4"
|
||||
fillOpacity="0.25"
|
||||
>
|
||||
{patternTweaks[i]}
|
||||
</svg>
|
||||
)
|
||||
|
||||
const Nr = ({ nr }) => (
|
||||
<div className="tw-absolute tw-top-8 tw-w-full tw--ml-20">
|
||||
<span className="tw-bg-primary tw-text-primary-content tw-font-bold tw-rounded-full tw-w-12 tw-h-12 tw-flex tw-items-center tw-justify-center tw-align-center tw-m-auto tw-text-3xl">
|
||||
{nr}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
const Title = ({ txt }) => {
|
||||
const shadow = `var(--ifm-background-color)`
|
||||
|
||||
return (
|
||||
<div className="tw-absolute tw-top-28 tw-left-0 tw-w-full">
|
||||
<h3
|
||||
className="tw-text-2xl tw--rotate-12 tw-w-48 tw-text-center tw-m-auto"
|
||||
style={{
|
||||
textShadow: `1px 1px 1px ${shadow}, -1px -1px 1px ${shadow}, -1px 1px 1px ${shadow}, 1px -1px 1px ${shadow}`,
|
||||
}}
|
||||
>
|
||||
{txt}
|
||||
</h3>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const slides = [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
const RecentBlogPosts = () => (
|
||||
<div>
|
||||
{recentBlogPosts.map((post) => (
|
||||
<p key={post.slug}>{post.title}</p>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
|
24
sites/org/src/pages/patrons/index.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Components
|
||||
import Layout from '@theme/Layout'
|
||||
import { DocusaurusPage } from '@freesewing/react/components/Docusaurus'
|
||||
import { PleaseSubscribe } from '@freesewing/react/components/Patrons'
|
||||
|
||||
const meta = {
|
||||
title: 'Join the FreeSewing Patrons',
|
||||
description:
|
||||
'If you think FreeSewing is worthwhile, and if you can spare ' +
|
||||
'a few coins each month without hardship, please support our work.',
|
||||
}
|
||||
|
||||
export default function PatronsPage() {
|
||||
return (
|
||||
<DocusaurusPage DocusaurusLayout={Layout} {...meta} Layout={false}>
|
||||
<div className="tw-max-w-7xl tw-mx-auto tw-my-12 tw-px-4">
|
||||
<h1>Join the FreeSewing Patrons</h1>
|
||||
<div className="tw--mx-4">
|
||||
<PleaseSubscribe />
|
||||
</div>
|
||||
</div>
|
||||
</DocusaurusPage>
|
||||
)
|
||||
}
|
24
sites/org/src/pages/patrons/join.mjs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Components
|
||||
import Layout from '@theme/Layout'
|
||||
import { DocusaurusPage } from '@freesewing/react/components/Docusaurus'
|
||||
import { PleaseSubscribe } from '@freesewing/react/components/Patrons'
|
||||
|
||||
const meta = {
|
||||
title: 'Join the FreeSewing Patrons',
|
||||
description:
|
||||
'If you think FreeSewing is worthwhile, and if you can spare ' +
|
||||
'a few coins each month without hardship, please support our work.',
|
||||
}
|
||||
|
||||
export default function PatronsPage() {
|
||||
return (
|
||||
<DocusaurusPage DocusaurusLayout={Layout} {...meta} Layout={false}>
|
||||
<div className="tw-max-w-7xl tw-mx-auto tw-my-12 tw-px-4">
|
||||
<h1>Join the FreeSewing Patrons</h1>
|
||||
<div className="tw--mx-4">
|
||||
<PleaseSubscribe />
|
||||
</div>
|
||||
</div>
|
||||
</DocusaurusPage>
|
||||
)
|
||||
}
|
|
@ -38,7 +38,7 @@ const BlogPostHeader = ({ type }) => {
|
|||
]}
|
||||
/>
|
||||
<h1>
|
||||
<span className="block text-sm capitalize">{type}:</span>
|
||||
<span className="tw-block tw-text-sm tw-capitalize">{type}:</span>
|
||||
{metadata.title}
|
||||
</h1>
|
||||
<BlogPostItemHeaderInfo />
|
||||
|
|
|
@ -13,9 +13,9 @@ const textShadow = {
|
|||
|
||||
const teaserClasses = `tw-absolute tw-bottom-4 tw-right-0 tw-ml-3
|
||||
tw-rounded-l md:tw-rounded-l-lg tw-bg-neutral tw-bg-opacity-80 tw-p-1 tw-px-4 tw-font-medium
|
||||
tw-text-neutral-content tw-text-right tw-text-sm md:tw-text-lg`
|
||||
tw-text-neutral-content tw-text-right tw-text-sm md:tw-text-lg lg:tw-text-xl`
|
||||
|
||||
const BlogPostTeaser = ({ post }) => (
|
||||
export const BlogPostTeaser = ({ post }) => (
|
||||
<Link
|
||||
className="tw-aspect-video tw-relative tw-shadow tw-rounded-lg"
|
||||
href={post.content.metadata.permalink}
|
||||
|
|
BIN
sites/org/static/img/models/model-0.png
Normal file
After Width: | Height: | Size: 267 KiB |
BIN
sites/org/static/img/models/model-1.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
sites/org/static/img/models/model-2.png
Normal file
After Width: | Height: | Size: 271 KiB |
BIN
sites/org/static/img/models/model-3.png
Normal file
After Width: | Height: | Size: 188 KiB |
BIN
sites/org/static/img/models/model-4.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
sites/org/static/img/models/model-5.png
Normal file
After Width: | Height: | Size: 261 KiB |
BIN
sites/org/static/img/models/model-6.png
Normal file
After Width: | Height: | Size: 288 KiB |
BIN
sites/org/static/img/models/model-7.png
Normal file
After Width: | Height: | Size: 227 KiB |