Skip to content

Commit

Permalink
host multiple projects under the same docs (#5)
Browse files Browse the repository at this point in the history
* very experimental foray into allowing different docs sites to live on the same site
- moved all archetype related content to */archetype
- created trailhead configurator (some issues to address)

todo
- figure out site wide nav as a tier above projects
- write new trailhead docs for testing
- clean up the trailhead configurator to not be as "hacky", potentially re-use the archetype component with the /trailhead config imported?
- learn more js/react stuff

* docs with multiple projects

* merged with multisite_testing (hopefully without breaking rogerlz changes :))

* armchair projects

* Sharketype and npm upgrade

* space

* fixed link to archetype configurator in /docs/archetype/page.md

* Add link to usermods repo

* collapse subs and blanks for github

* collapse subs and blanks for github

* npm update

* added quicklink to main page, added trailhead description to trailhead landing page

---------

Co-authored-by: maz0r <[email protected]>
Co-authored-by: Derpimus <[email protected]>
  • Loading branch information
3 people authored Apr 5, 2024
1 parent f649c16 commit 15c3d87
Show file tree
Hide file tree
Showing 219 changed files with 2,230 additions and 1,518 deletions.
3 changes: 2 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const nextConfig = {
output: 'export',
images: { unoptimized: true },
pageExtensions: ['js', 'jsx', 'md', 'ts', 'tsx'],
assetPrefix: 'https://docs.armchairheavyindustries.com',
assetPrefix: '/',
// assetPrefix: 'https://docs.armchairheavyindustries.com',
};

export default withSearch(
Expand Down
1,928 changes: 1,079 additions & 849 deletions package-lock.json

Large diffs are not rendered by default.

File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { DocsHeader } from '@/components/DocsHeader';
import { Prose } from '@/components/Prose';
import { PrevNextLinks } from '@/components/PrevNextLinks';
import { Archetype } from '@/app/configurator/config';
import { Archetype } from '@/app/configurator/archetype/config';
import clsx from 'clsx';
import { Fragment, useEffect, useState } from 'react';
import { downloadZip } from 'client-zip';
Expand Down
95 changes: 95 additions & 0 deletions src/app/configurator/trailhead/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
export const Trailhead = {
order: [
'rail',
],

components: {
carriage: {
label: 'Rail Size',
options: {
ninetwentytwentyplastic: {
label: '9MM 2020 extrusion',
files: {
generic: {
left_b: 'STLs/9mm/2020%209mm%20Trailhead%20-%20XY%20Joint%20-%20Left%20Bottom',
left_t: 'STLs/9mm/2020%209mm%20Trailhead%20-%20XY%20Joint%20-%20Left%20Top',
right_b: 'STLs/9mm/2020%209mm%20Trailhead%20-%20XY%20Joint%20-%20Right%20Bottom',
right_t: 'STLs/9mm/2020%209mm%20Trailhead%20-%20XY%20Joint%20-%20Right%20Top',
plate: '',
},
}
},
sixfifteenfifteenplastic: {
label: '6MM 1515 extrusion',
files: {
generic: {
left_b: 'STLs/6mm/1515 6mm Trailhead - XY Joint - Left Bottom',
left_t: 'STLs/6mm/1515 6mm Trailhead - XY Joint - Left Top',
right_b: 'STLs/6mm/1515 6mm Trailhead - XY Joint - Right Bottom',
right_t: 'STLs/6mm/1515 6mm Trailhead - XY Joint - Right Top',
plate: '',
},
},
},
sixtwentytwentyplastic: {
label: '6mm 2020 extrusion',
files: {
generic: {
left_b: 'STLs/6mm/2020 6mm Trailhead - XY Joint - Left Bottom',
left_t: 'STLs/6mm/2020 6mm Trailhead - XY Joint - Left Top',
right_b: 'STLs/6mm/2020 6mm Trailhead - XY Joint - Right Bottom',
right_t: 'STLs/6mm/2020 6mm Trailhead - XY Joint - Right Top',
plate: '',
},
},
},
},
mods: {
plated_92020: {
label: '9mm 2020 extrusion Plated',
files: {
ninetwentytwentyplastic: {
generic: {
left_b: 'STLs/9mm/plated/2020 9mm Trailhead - XY Joint - Left Bottom - Plated',
left_t: 'STLs/9mm/plated/2020 9mm Trailhead - XY Joint - Left Top - Plated',
right_b: 'STLs/9mm/plated/2020 9mm Trailhead - XY Joint - Right Bottom - Plated',
right_t: 'STLs/9mm/plated/2020 9mm Trailhead - XY Joint - Right Top - Plated',
plate: 'DXF/trailhead_plate[x2].dxf',
},
}
}
},
plated_62020: {
label: '6mm 2020 extrusion Plated',
files: {
sixtwentytwentyplastic: {
generic: {
left_b: 'STLs/6mm/plated/2020-xyj-left-lower-plated',
left_t: 'STLs/6mm/plated/2020-xyj-left-upper-plated',
right_b: 'STLs/6mm/plated/2020-xyj-right-lower-plated',
right_t: 'STLs/6mm/plated/2020-xyj-right-upper-plated',
plate: 'DXF/trailhead_plate[x2].dxf',
},
}
}
},
plated_61515: {
label: '6mm 1515 extrusion Plated',
files: {
sixfifteenfifteenplastic: {
generic: {
left_b: 'STLs/6mm/plated/1515-xyj-left-lower-plated',
right_b: 'STLs/6mm/plated/1515-xyj-right-lower-plated',
left_t: '',
right_t: '',
plate: 'DXF/trailhead_plate[x2].dxf',
},
}
}
},
}
}
}
};

export default { Trailhead };
247 changes: 247 additions & 0 deletions src/app/configurator/trailhead/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
'use client';

import { DocsHeader } from '@/components/DocsHeader';
import { Prose } from '@/components/Prose';
import { PrevNextLinks } from '@/components/PrevNextLinks';
import { Trailhead } from '@/app/configurator/trailhead/config';
import clsx from 'clsx';
import { Fragment, useEffect, useState } from 'react';
import { downloadZip } from 'client-zip';

const isset = (object, property) => Object.prototype.hasOwnProperty.call(object || {}, property)
// @todo just remove the numeric lengths and use the strings

const BASE_URI = 'https://raw.githubusercontent.com/Armchair-Heavy-Industries/Trailhead-XY-Joints/main/'


const getSelectedFiles = (selections, mods) => {
const files = []

Object.keys(selections).forEach((type) => {
const definition = Trailhead.components[type].options[selections[type]];
const selected = selections[type];

if (isset(definition.files, 'generic')) {
const generics = definition.files.generic

// check for mods
Object.keys(definition.files.generic).forEach((component_type) => {
if (isset(mods, type) && mods[type] !== null && isset(Trailhead.components[type].mods[mods[type]].files[selected].generic, component_type)) {
generics[component_type] = Trailhead.components[type].mods[mods[type]].files[selected].generic[component_type]
}
})

// condense to just a list of strings
Object.keys(generics).forEach((key) => {
if (generics[key] !== '') {
files.push(generics[key]);
}
});
}
})

return files;
}

const downloadBlob = (blob, name) => {
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = name;
link.click();
link.remove();
URL.revokeObjectURL(link.href);
};

const download = async (files) => {
const downloads = files.map((file) => {
const extension = file.split('.').pop();
console.warn(extension);
if (extension === 'dxf') {
// Use a different fetch method for .dxf files
console.warn(`found dxf ${file}`);
return fetch(`${BASE_URI}/${file}`);
} else {
// Use the existing fetch method for .stl files
return fetch(`${BASE_URI}/${file}.stl`);
}
});
const responses = await Promise.all(downloads);

if (responses.some((res) => !res.ok)) {
throw new Error('Some files failed to download');
}

const blob = await downloadZip(responses).blob();
downloadBlob(blob, 'trailhead.zip');
}

export default function Page() {
const [selections, setSelections] = useState({});
const [mods, setMods] = useState({});

const defaultStateClass = 'bg-gray-700';
const defaultStateHoverClass = 'hover:bg-gray-800';
const selectedItemClass = 'bg-indigo-600';
const disabledStateClass = 'bg-gray-400';



// remove/unselect invalid components
useEffect(
() => {
Object.keys(selections).forEach((type) => {
Object.keys(Trailhead.components[type].options).forEach((component_name) => {
const selector = document.querySelector(`#${component_name}`);

if (selector && selector.disabled && selections[type] === component_name) {
delete selections[type];

setSelections(selections);
selector.classList.remove(selectedItemClass)
selector.classList.add(defaultStateClass)
}
})
})
},
[selections]
)

// remove mods if irrelevant
useEffect(
() => {
Object.keys(selections).forEach((type) => {
Object.keys(Trailhead.components[type].mods).forEach((mod_name) => {
Object.keys(Trailhead.components[type].mods[mod_name].files).forEach((component_override) => {
if (selections[type] !== component_override) {
setMods((m) => {
delete m[type];

return m;
})
}
})
})
})
},
[selections]
)

return (
<>
<div className="min-w-0 max-w-2xl flex-auto px-4 py-16 lg:max-w-none lg:pl-8 lg:pr-0 xl:px-16">
<article>
<DocsHeader title="Choose your own adventure" />

<Prose>
{Object.keys(Trailhead.components).map((name) => (
<div key={name}>
<h2>{Trailhead.components[name].label}</h2>

<div className={clsx('grid grid-cols-2 gap-4')}>
{Object.keys(Trailhead.components[name].options).map((component_name) => (
<button
id={component_name}
key={component_name}
data-component={name}
value={component_name}
className={clsx(
'rounded-md px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm',
selections[name] === component_name ? selectedItemClass : `${defaultStateClass} ${defaultStateHoverClass}`,
)}
onClick={() => {
setSelections({
...selections,
[name]: component_name
});


}}
>
{Trailhead.components[name].options[component_name].label}
</button>
))}
</div>

<div
className={clsx('flex gap-4')}
>
{Object.keys(Trailhead.components[name].mods).map((mod_name, idx) => (
<Fragment key={idx}>
{idx === 0 ?
<div
className={clsx(
// if there is a mod with the selected components name, show it
{ 'hidden': !isset(Trailhead.components[name].mods[mod_name].files, selections[name]) }
)}
>
<label className={clsx('cursor-pointer')}>
<input
type='radio'
key={`${idx}_none`}
name={`${name}_mods`}
className={clsx('rounded-md bg-white/10 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-white/20 mr-2')}
checked={!isset(mods, name) || mods[name] === null}
onChange={() => setMods({ [name]: null })}
/>
No Mod
</label>
</div>
: null
}
<div
className={clsx(
// if there is a mod with the selected components name, show it
{ 'hidden': !isset(Trailhead.components[name].mods[mod_name].files, selections[name]) }
)}
>
<label className={clsx('cursor-pointer')}>
<input
type='radio'
key={idx}
value={mod_name}
name={`${name}_mods`}
className={clsx('rounded-md bg-white/10 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-white/20 mr-2')}
checked={mods[name] === mod_name || false}
onChange={() => setMods({ [name]: mod_name })}
/>
{Trailhead.components[name].mods[mod_name].label}
</label>
</div>
</Fragment>
))}
</div>
</div>
))}
</Prose>
</article>

<div className={clsx('flex mt-8 gap-4')}>
<button
type="button"
disabled={Object.keys(selections).length !== Object.keys(Trailhead.components).length}
className={clsx(
'rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm',
'disabled:cursor-not-allowed disabled:bg-indigo-800 bg-indigo-500 hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500'
)}
onClick={() => { download(getSelectedFiles(selections, mods)) }}
>
Download
</button>
<button
type="button"
disabled={Object.keys(selections).length === 0}
className={clsx(
'rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm',
'disabled:cursor-not-allowed disabled:bg-gray-400 bg-gray-700 hover:bg-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-700'
)}
onClick={() => { setSelections({}); setMods({}); }}
>
Reset
</button>
</div>

<PrevNextLinks />
</div>
</>
)
}
File renamed without changes.
Loading

0 comments on commit 15c3d87

Please sign in to comment.