wip(fs.dev): Work on navigation menu
This commit is contained in:
parent
bd2d5a49f2
commit
092c81f535
11 changed files with 2241 additions and 1957 deletions
|
@ -16,16 +16,17 @@
|
|||
"@mdx-js/react": "^2.0.0-rc.2",
|
||||
"@mdx-js/runtime": "next",
|
||||
"daisyui": "^1.16.2",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"next": "latest",
|
||||
"react-swipeable": "^6.2.0",
|
||||
"lodash.orderby": "^4.6.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-jargon": "^2.19.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"js-yaml": "^4.1.0",
|
||||
"postcss": "^8.4.4",
|
||||
"tailwindcss": "^3.0.1"
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
export const posts = {
|
||||
"blog/welcome-to-our-dev-blog": {
|
||||
"welcome-to-our-dev-blog": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eaceb44f0f4957dbc9d64b",
|
||||
|
@ -86,7 +86,7 @@ export const posts = {
|
|||
"id": "60eaceb44f0f4957dbc9d64b",
|
||||
"intro": "The internet is plastered with abandoned or dormant blogs, so starting another one is perhaps madness, but hear me out:"
|
||||
},
|
||||
"blog/project-2022": {
|
||||
"project-2022": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb151cdb32b45d5c4d6d96",
|
||||
|
@ -173,7 +173,7 @@ export const posts = {
|
|||
"id": "60eb151cdb32b45d5c4d6d96",
|
||||
"intro": "During my summer break I wanted to look into migrating the FreeSewing websites (freesewing.org and freesewing.dev) from GatbsyJS to NextJS ."
|
||||
},
|
||||
"blog/tailwind-css-project-2022": {
|
||||
"tailwind-css-project-2022": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb1836db32b45d5c4d6d99",
|
||||
|
@ -260,7 +260,7 @@ export const posts = {
|
|||
"id": "60eb1836db32b45d5c4d6d99",
|
||||
"intro": "Building a website that is supposed to do something essentially boils down to two things:"
|
||||
},
|
||||
"blog/daisyui-components-themes": {
|
||||
"daisyui-components-themes": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb1d41db32b45d5c4d6d9c",
|
||||
|
@ -347,7 +347,7 @@ export const posts = {
|
|||
"id": "60eb1d41db32b45d5c4d6d9c",
|
||||
"intro": "Since we're changing pretty much everything in project 2022 anyway, we might as well try to reduce our bundle size by removing our dependency on Material UI , the React component framework that implements Google's material design."
|
||||
},
|
||||
"blog/shared-frontend-code-monorepo": {
|
||||
"shared-frontend-code-monorepo": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb237cdb32b45d5c4d6d9f",
|
||||
|
@ -434,7 +434,7 @@ export const posts = {
|
|||
"id": "60eb237cdb32b45d5c4d6d9f",
|
||||
"intro": "Up until now, our websites each live in their own repository. This makes sharing code and content somewhat more involved, and situation that we currently handle as follows:"
|
||||
},
|
||||
"blog/improved-search-keyboard": {
|
||||
"improved-search-keyboard": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb2759db32b45d5c4d6da2",
|
||||
|
@ -521,7 +521,7 @@ export const posts = {
|
|||
"id": "60eb2759db32b45d5c4d6da2",
|
||||
"intro": "Since we've got a ton of documentation, good search is a crucial aspect of our websites."
|
||||
},
|
||||
"blog/strapi-headless-cms": {
|
||||
"strapi-headless-cms": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60eb2e11db32b45d5c4d6da5",
|
||||
|
@ -608,7 +608,7 @@ export const posts = {
|
|||
"id": "60eb2e11db32b45d5c4d6da5",
|
||||
"intro": "As things are now, all of FreeSewing's content is contained in our markdown repository ."
|
||||
},
|
||||
"blog/layout-blocks-overview": {
|
||||
"layout-blocks-overview": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60f0616ddb32b45d5c4d6dac",
|
||||
|
@ -695,7 +695,7 @@ export const posts = {
|
|||
"id": "60f0616ddb32b45d5c4d6dac",
|
||||
"intro": "I wanted to do a quick write-up of the main layout blocks of our websites. So let's have a look:"
|
||||
},
|
||||
"blog/freesewing-v3-seems-inevitable": {
|
||||
"freesewing-v3-seems-inevitable": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "60f2e2ef2f81c03239366844",
|
||||
|
@ -793,7 +793,7 @@ export const posts = {
|
|||
"id": "60f2e2ef2f81c03239366844",
|
||||
"intro": "I just made a bunch of breaking changes in @freesewing/i18n and it made me realize that if/when we get around to merging my work back into our monorepo, there's going to be too many changes not to bump the major version."
|
||||
},
|
||||
"blog/migration-to-strapi": {
|
||||
"migration-to-strapi": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "612785b5fca7f36c6a727a6b",
|
||||
|
@ -890,7 +890,7 @@ export const posts = {
|
|||
"id": "612785b5fca7f36c6a727a6b",
|
||||
"intro": "Effective immediately, all blog and showcase posts on freesewing.org are backed by our Strapi instance , rather than our markdown repository . That markdown repository has been archived, and the markdown content that are not blog or showcase posts (predominantly documentation) has been moved into our monorepo ."
|
||||
},
|
||||
"blog/pattern-docs-option-sampling": {
|
||||
"pattern-docs-option-sampling": {
|
||||
"dev": true,
|
||||
"localizations": [],
|
||||
"_id": "6128ccacfca7f36c6a727a70",
|
||||
|
|
|
@ -4,12 +4,84 @@ import nav from 'site/prebuild/navigation.js'
|
|||
import Link from 'next/link'
|
||||
import orderBy from 'lodash.orderby'
|
||||
|
||||
// TODO: Clean this up after restructuring markdown content
|
||||
const hide = ['contributors', 'developers', 'editors', 'translators']
|
||||
|
||||
// Don't show children for blog and showcase posts
|
||||
const keepClosed = ['blog', 'showcase', ]
|
||||
|
||||
const linkClasses = {className: 'hover:text-underline color-primary'}
|
||||
// TODO: For now we force tailwind to pickup these styles
|
||||
// At some point this should 'just work' though, but let's not worry about it now
|
||||
const force = <p className="w-6 mr-3"/>
|
||||
|
||||
// Component for the collapse toggle
|
||||
const Chevron = ({w=8, m=1}) => <svg
|
||||
className={`fill-current opacity-75 w-${w} h-${w} mr-${m} details-toggle`}
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path d="M12.95 10.707l.707-.707L8 4.343 6.586 5.757 10.828 10l-4.242 4.243L8 15.657l4.95-4.95z"/>
|
||||
</svg>
|
||||
|
||||
const TopLevel = ({ icon, title, nav, current }) => (
|
||||
// Helper method to filter out the real children
|
||||
const currentChildren = current => Object.values(current)
|
||||
.filter(entry => (typeof entry === 'object'))
|
||||
|
||||
// Component that renders a sublevel of navigation
|
||||
const SubLevel = ({ nodes={} }) => (
|
||||
<ul className='list-inside'>
|
||||
{currentChildren(nodes).map(child => (Object.keys(child).length > 4)
|
||||
? (
|
||||
<li>
|
||||
<details key={child.__slug}>
|
||||
<summary className={`
|
||||
flex flex-row gap-4 font-bold
|
||||
hover:cursor-row-resize
|
||||
hover:bg-base-200
|
||||
p-1
|
||||
px-2
|
||||
text-primary
|
||||
`}>
|
||||
<Link href={child.__slug}>
|
||||
<a title={child.__title} className={`
|
||||
grow
|
||||
text-primary
|
||||
color-primary
|
||||
hover:cursor-pointer
|
||||
hover:underline
|
||||
hover:decoration-secondary
|
||||
hover:decoration-2
|
||||
`}>
|
||||
{ child?.__linktitle || child.__title }
|
||||
</a>
|
||||
</Link>
|
||||
<Chevron w={6} m={3}/>
|
||||
</summary>
|
||||
<SubLevel nodes={child} />
|
||||
</details>
|
||||
</li>
|
||||
) : (
|
||||
<li className='text-primary pl-2 font-bold'>
|
||||
<div className={`
|
||||
p-1
|
||||
text-primary
|
||||
color-primary
|
||||
hover:cursor-pointer
|
||||
hover:underline
|
||||
hover:decoration-secondary
|
||||
hover:decoration-2
|
||||
`}>
|
||||
<Link href={child.__slug} title={child.__title}>
|
||||
{child.__linktitle}
|
||||
</Link>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
|
||||
// Component that renders a toplevel of navigation
|
||||
const TopLevel = ({ icon, title, nav, current, slug, showChildren=false }) => (
|
||||
<details className='p-2' open={((keepClosed.indexOf(current._slug) === -1) ? 1 : 0)}>
|
||||
<summary className={`
|
||||
flex flex-row uppercase gap-4 font-bold text-lg
|
||||
|
@ -19,45 +91,40 @@ const TopLevel = ({ icon, title, nav, current }) => (
|
|||
text-primary
|
||||
`}>
|
||||
{icon}
|
||||
<Link
|
||||
href={`/${current._slug}/`}
|
||||
className='hover:cursor-pointer'
|
||||
>
|
||||
{/* Wrapping this in a div because tailwind doesn't pick up
|
||||
classes on the next js Link component */}
|
||||
<div className={`
|
||||
grow
|
||||
hover:cursor-pointer hover:text-underline
|
||||
hover:underline
|
||||
hover:decoration-secondary
|
||||
hover:decoration-4
|
||||
`}>
|
||||
<Link href={`/${current._slug}/`}>
|
||||
{title}
|
||||
</Link>
|
||||
</summary>
|
||||
<div className='pl-4'>
|
||||
<ul>
|
||||
{orderBy(Object.values(current._children), ['order', 'title'], ['asc', 'asc']).map(item => {
|
||||
console.log(item)
|
||||
const target = item._slug ? get(nav, item._slug.split('/')) : '/'
|
||||
return (
|
||||
<li key={item._slug}>
|
||||
{ item?._linktitle || item._title }
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
{showChildren && <Chevron />}
|
||||
</summary>
|
||||
{showChildren && <SubLevel nodes={current} />}
|
||||
</details>
|
||||
)
|
||||
|
||||
// TODO: Get rid of this when markdown has been restructured
|
||||
const remove = ['contributors', 'developers', 'editors', 'translators']
|
||||
const Navigation = ({ nav, app }) => {
|
||||
console.log(nav.en)
|
||||
const output = []
|
||||
for (const key of Object.keys(nav[app.language]).sort()) {
|
||||
if (
|
||||
key.slice(0,1) !== '_' &&
|
||||
remove.indexOf(key) === -1
|
||||
) output.push(<TopLevel
|
||||
if (hide.indexOf(key) === -1) output.push(<TopLevel
|
||||
icon={<Icon icon={key}/>}
|
||||
title={key}
|
||||
slug={key}
|
||||
key={key}
|
||||
showChildren={keepClosed.indexOf(key) === -1}
|
||||
nav={nav[app.language]}
|
||||
current={nav[app.language][key]}
|
||||
/>
|
||||
)
|
||||
current={orderBy(nav[app.language][key], ['order', 'title'], ['asc', 'asc'])}
|
||||
/>)
|
||||
}
|
||||
|
||||
return output
|
||||
|
|
|
@ -7,9 +7,10 @@ import remarkParser from 'remark-parse'
|
|||
import remarkCompiler from 'remark-stringify'
|
||||
import remarkFrontmatter from 'remark-frontmatter'
|
||||
import remarkFrontmatterExtractor from 'remark-extract-frontmatter'
|
||||
import remarkMdx from 'remark-mdx'
|
||||
import vfileReporter from 'vfile-reporter'
|
||||
import { readSync } from 'to-vfile'
|
||||
import yaml from 'yaml'
|
||||
import yaml from 'js-yaml'
|
||||
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
||||
|
||||
|
||||
|
@ -59,13 +60,24 @@ const fileToSlug = (file, site, lang) => (file.slice(-6) === `/${lang}.md`)
|
|||
*
|
||||
* - file: the full path to the file
|
||||
*/
|
||||
const mdxMetaInfo = async file => await unified()
|
||||
const mdxMetaInfo = async file => {
|
||||
let result
|
||||
try {
|
||||
result = await unified()
|
||||
.use(remarkMdx)
|
||||
.use(remarkIntroPlugin)
|
||||
.use(remarkParser)
|
||||
.use(remarkCompiler)
|
||||
.use(remarkFrontmatter)
|
||||
.use(remarkFrontmatterExtractor, { yaml: yaml.parse })
|
||||
.use(remarkFrontmatterExtractor, { yaml: yaml.load })
|
||||
.process(readSync(file))
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/*
|
||||
* Main method that does what needs doing
|
||||
|
@ -94,14 +106,21 @@ export const prebuildMdx = async(site) => {
|
|||
const slug = fileToSlug(file, site, lang)
|
||||
if (slug) {
|
||||
const meta = await mdxMetaInfo(file)
|
||||
if (meta) {
|
||||
if (meta?.data?.title && meta?.data?.title) {
|
||||
pages[lang][slug] = {
|
||||
...meta.data,
|
||||
title: meta.data.title,
|
||||
intro: meta.data.intro,
|
||||
order: meta.data.order
|
||||
? meta.data.order+meta.data.title
|
||||
: meta.data.title,
|
||||
slug,
|
||||
order: meta?.data?.order
|
||||
? `${meta.data.order}${meta.data.title}`
|
||||
: meta.data.title
|
||||
}
|
||||
} else {
|
||||
console.log('Failed to extract title & intro from:', slug)
|
||||
console.log(meta.messages, null ,2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,38 +19,38 @@ export const prebuildNavigation = (mdxPages, strapiPosts, site) => {
|
|||
for (const [slug, page] of Object.entries(mdxPages[lang])) {
|
||||
const chunks = slug.split('/')
|
||||
set(nav, [lang, ...chunks], {
|
||||
_title: page.title,
|
||||
_linktitle: page.linktitle || page.title,
|
||||
_slug: slug,
|
||||
_order: page.order,
|
||||
_children: {}
|
||||
__title: page.title,
|
||||
__linktitle: page.linktitle || page.title,
|
||||
__slug: slug,
|
||||
__order: page.order,
|
||||
//__children: {}
|
||||
})
|
||||
const children = get(nav, [lang, ...chunks.slice(0, -1), '_children'], {})
|
||||
children[page.order || slug] = slug
|
||||
set(nav, [lang, ...chunks.slice(0, -1), '_children'], children)
|
||||
//const children = get(nav, [lang, ...chunks.slice(0, -1), '_children'], {})
|
||||
//children[page.order || slug] = slug
|
||||
//set(nav, [lang, ...chunks.slice(0, -1), '_children'], children)
|
||||
}
|
||||
|
||||
// Handle strapi content
|
||||
for (const type in strapiPosts[lang]) {
|
||||
set(nav, [lang, type], {
|
||||
_title: type,
|
||||
_linktitle: type,
|
||||
_slug: type,
|
||||
_order: type,
|
||||
_children: {}
|
||||
__title: type,
|
||||
__linktitle: type,
|
||||
__slug: type,
|
||||
__order: type,
|
||||
//__children: {}
|
||||
})
|
||||
for (const [slug, page] of Object.entries(strapiPosts[lang][type])) {
|
||||
const chunks = slug.split('/')
|
||||
set(nav, [lang, type, ...chunks], {
|
||||
_title: page.title,
|
||||
_linktitle: page.linktitle,
|
||||
_slug: slug,
|
||||
_order: (future - new Date(page.date).getTime()) / 100000,
|
||||
_children: {}
|
||||
__title: page.title,
|
||||
__linktitle: page.linktitle,
|
||||
__slug: type + '/' + slug,
|
||||
__order: (future - new Date(page.date).getTime()) / 100000,
|
||||
//__children: {}
|
||||
})
|
||||
const children = get(nav, [lang, type, '_children'], {})
|
||||
children[page.date+slug] = slug
|
||||
set(nav, [lang, type, '_children'], children)
|
||||
//const children = get(nav, [lang, type, '_children'], {})
|
||||
//children[page.date+slug] = slug
|
||||
//set(nav, [lang, type, '_children'], children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ export const remarkIntroPlugin = () => {
|
|||
const visitor = (node) => {
|
||||
const intro = extractFirstParagraph(node)
|
||||
if (hasFrontmatter(node)) {
|
||||
node.children[0].value += `\nintro: "${intro}"`
|
||||
node.children[0].value += `\nintro: "${intro}"\n`
|
||||
//console.log(node.children[0])
|
||||
} else {
|
||||
node.children.unshift({
|
||||
type: 'yaml',
|
||||
|
|
|
@ -46,8 +46,8 @@ const getPosts = async (type, site, lang) => {
|
|||
}
|
||||
const posts = {}
|
||||
for (const post of res.data) {
|
||||
const intro = await postIntro(post.body)
|
||||
posts[`${type}/${post.slug}`] = { ...post, intro: intro.data.intro }
|
||||
const intro = await postIntro(`---\n---\n\n${post.body}`)
|
||||
posts[post.slug] = { ...post, intro: intro.data.intro }
|
||||
}
|
||||
|
||||
return posts
|
||||
|
|
|
@ -2,3 +2,22 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
details { user-select: none; }
|
||||
details > summary > svg.details-toggle {
|
||||
transform: rotate(90deg);
|
||||
opacity: 0.4;
|
||||
}
|
||||
details[open] > summary > svg.details-toggle {
|
||||
transform: rotate(-90deg);
|
||||
opacity: 0.8;
|
||||
}
|
||||
details[open] summary ~ * { animation: ease-opacity-t-b .5s ease}
|
||||
summary { cursor: pointer; }
|
||||
svg.details-toggle { transition: all 0.2s ease-out; }
|
||||
|
||||
/* TO JE TO - TO JE TAJ */
|
||||
summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -12460,7 +12460,7 @@ js-yaml@3.14.1, js-yaml@^3.13.1, js-yaml@^3.14.0:
|
|||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
js-yaml@4.1.0, js-yaml@^4.0.0:
|
||||
js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue