refactor: Restructure data files into component-specific and common directories, add new UI components, and update project documentation.
This commit is contained in:
19
website/package-lock.json
generated
19
website/package-lock.json
generated
@@ -69,7 +69,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1427,7 +1426,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
@@ -1467,7 +1465,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -1932,7 +1929,6 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -2696,7 +2692,6 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -3908,7 +3903,6 @@
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
@@ -4673,7 +4667,6 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -4889,7 +4882,6 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -5699,7 +5691,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -5845,13 +5836,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/unzipper": {
|
||||
"version": "0.10.14",
|
||||
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz",
|
||||
@@ -5958,7 +5942,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
|
||||
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -6050,7 +6033,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -6233,7 +6215,6 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz",
|
||||
"integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
12
website/src/components/Footer.jsx
Normal file
12
website/src/components/Footer.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="w-full py-8 mt-12 border-t border-gray-200 dark:border-gray-700">
|
||||
<div className="max-w-4xl mx-auto px-4 text-center">
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Disclaimer: The OSSM Configurator is an independent open-source project.
|
||||
We are not directly associated with the vendors listed, but their contributions to open source are deeply appreciated and reciprocated.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import partsData from '../data/index.js';
|
||||
import Footer from './Footer';
|
||||
|
||||
export default function MainPage({ onSelectBuildType }) {
|
||||
const handleSelect = (buildType) => {
|
||||
@@ -6,8 +6,8 @@ export default function MainPage({ onSelectBuildType }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-8">
|
||||
<div className="max-w-4xl mx-auto px-4">
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-8 flex flex-col">
|
||||
<div className="max-w-4xl mx-auto px-4 flex-grow">
|
||||
{/* Header */}
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
@@ -23,7 +23,7 @@ export default function MainPage({ onSelectBuildType }) {
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-6 text-center">
|
||||
Select Your Build Type
|
||||
</h2>
|
||||
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{/* New Build - RAD Kit */}
|
||||
<button
|
||||
@@ -120,6 +120,7 @@ export default function MainPage({ onSelectBuildType }) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import OptionsStep from './steps/OptionsStep';
|
||||
import RemoteStep from './steps/RemoteStep';
|
||||
import ToyMountStep from './steps/ToyMountStep';
|
||||
import BOMSummary from './BOMSummary';
|
||||
import Footer from './Footer';
|
||||
|
||||
const steps = [
|
||||
{ id: 'motor', name: 'Motor', component: MotorStep },
|
||||
@@ -87,7 +88,7 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
// Power Supply step - require power supply selection
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (currentStep < filteredSteps.length - 1) {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}
|
||||
@@ -104,17 +105,17 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
if (stepIndex <= currentStep) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// In upgrade mode, no validation needed
|
||||
if (buildType === 'upgrade') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// In RAD Kit mode, all steps are pre-selected, so navigation is always allowed
|
||||
if (buildType === 'rad-kit') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Check if required steps are completed before jumping ahead
|
||||
if (stepIndex > 0 && !config.motor) {
|
||||
return false; // Can't skip motor step
|
||||
@@ -122,7 +123,7 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
if (stepIndex > 1 && !config.powerSupply) {
|
||||
return false; // Can't skip power supply step
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -137,7 +138,7 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
if (buildType === 'upgrade') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (currentStep === 0 && !config.motor) {
|
||||
return false; // Motor step - require motor selection
|
||||
}
|
||||
@@ -158,8 +159,8 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
}, [buildType, currentStep]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-8">
|
||||
<div className="max-w-4xl mx-auto px-4">
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-8 flex flex-col">
|
||||
<div className="max-w-4xl mx-auto px-4 flex-grow w-full">
|
||||
{/* Back Button */}
|
||||
{onBackToMain && (
|
||||
<div className="mb-4">
|
||||
@@ -191,7 +192,7 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
OSSM Configurator
|
||||
</h1>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
{buildType === 'upgrade'
|
||||
{buildType === 'upgrade'
|
||||
? 'Select upgrade components and modifications'
|
||||
: 'Configure your Open Source Sex Machine'}
|
||||
</p>
|
||||
@@ -212,17 +213,15 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
{/* Circle */}
|
||||
<button
|
||||
onClick={() => goToStep(index)}
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center font-semibold flex-shrink-0 z-10 ${
|
||||
index === currentStep
|
||||
? 'bg-blue-600 dark:bg-blue-500 text-white'
|
||||
: index < currentStep
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center font-semibold flex-shrink-0 z-10 ${index === currentStep
|
||||
? 'bg-blue-600 dark:bg-blue-500 text-white'
|
||||
: index < currentStep
|
||||
? 'bg-green-500 dark:bg-green-600 text-white'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-500 dark:text-gray-400'
|
||||
} ${
|
||||
index <= currentStep
|
||||
} ${index <= currentStep
|
||||
? 'cursor-pointer hover:opacity-80'
|
||||
: 'cursor-not-allowed'
|
||||
}`}
|
||||
}`}
|
||||
disabled={!canNavigateToStep(index)}
|
||||
>
|
||||
{index < currentStep ? '✓' : index + 1}
|
||||
@@ -230,10 +229,9 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
{/* Connecting line to the right */}
|
||||
{index < filteredSteps.length - 1 && (
|
||||
<div
|
||||
className={`absolute top-5 left-1/2 h-1 ${
|
||||
index < currentStep ? 'bg-green-500 dark:bg-green-600' : 'bg-gray-200 dark:bg-gray-700'
|
||||
}`}
|
||||
style={{
|
||||
className={`absolute top-5 left-1/2 h-1 ${index < currentStep ? 'bg-green-500 dark:bg-green-600' : 'bg-gray-200 dark:bg-gray-700'
|
||||
}`}
|
||||
style={{
|
||||
width: 'calc(100% - 40px)',
|
||||
marginLeft: '20px'
|
||||
}}
|
||||
@@ -242,11 +240,10 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
{/* Text label */}
|
||||
<button
|
||||
onClick={() => goToStep(index)}
|
||||
className={`mt-2 text-sm font-medium text-center ${
|
||||
index <= currentStep
|
||||
? 'text-blue-600 dark:text-blue-400 cursor-pointer hover:text-blue-800 dark:hover:text-blue-300'
|
||||
: 'text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
}`}
|
||||
className={`mt-2 text-sm font-medium text-center ${index <= currentStep
|
||||
? 'text-blue-600 dark:text-blue-400 cursor-pointer hover:text-blue-800 dark:hover:text-blue-300'
|
||||
: 'text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
}`}
|
||||
disabled={!canNavigateToStep(index)}
|
||||
>
|
||||
{step.name}
|
||||
@@ -273,11 +270,10 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
<button
|
||||
onClick={prevStep}
|
||||
disabled={currentStep === 0}
|
||||
className={`px-6 py-2 rounded-lg font-medium ${
|
||||
currentStep === 0
|
||||
? 'bg-gray-200 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
: 'bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-600'
|
||||
}`}
|
||||
className={`px-6 py-2 rounded-lg font-medium ${currentStep === 0
|
||||
? 'bg-gray-200 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
: 'bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-600'
|
||||
}`}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
@@ -285,11 +281,10 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
<button
|
||||
onClick={nextStep}
|
||||
disabled={!canProceedToNextStep()}
|
||||
className={`px-6 py-2 rounded-lg font-medium ${
|
||||
canProceedToNextStep()
|
||||
? 'bg-blue-600 dark:bg-blue-500 text-white hover:bg-blue-700 dark:hover:bg-blue-600'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
}`}
|
||||
className={`px-6 py-2 rounded-lg font-medium ${canProceedToNextStep()
|
||||
? 'bg-blue-600 dark:bg-blue-500 text-white hover:bg-blue-700 dark:hover:bg-blue-600'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
@@ -297,6 +292,7 @@ export default function Wizard({ buildType = 'self-source', initialConfig, updat
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
const updates = {
|
||||
remoteType: remoteId,
|
||||
};
|
||||
|
||||
|
||||
// Reset PCB selection when switching remotes
|
||||
if (remoteId === 'ossm-remote-radr') {
|
||||
// RADR only available from RAD
|
||||
@@ -41,10 +41,10 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
} else {
|
||||
updates.remotePCB = null;
|
||||
}
|
||||
|
||||
|
||||
// Clear knob selection when switching remotes
|
||||
updates.remoteKnob = null;
|
||||
|
||||
|
||||
updateConfig(updates);
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
const getAvailableKnobs = () => {
|
||||
const remoteSystem = getSelectedRemoteSystem();
|
||||
if (!remoteSystem || !remoteSystem.knobs) return [];
|
||||
|
||||
|
||||
return remoteSystem.knobs.map((knob) => ({
|
||||
id: knob.id,
|
||||
name: knob.name,
|
||||
@@ -88,11 +88,10 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
<button
|
||||
key={remote.id}
|
||||
onClick={() => handleRemoteSelect(remote.id)}
|
||||
className={`p-4 border-2 rounded-lg text-left transition-all w-full ${
|
||||
isSelected
|
||||
className={`p-4 border-2 rounded-lg text-left transition-all w-full ${isSelected
|
||||
? 'border-blue-600 dark:border-blue-500 bg-blue-50 dark:bg-blue-900/30'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700/50'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
{imagePath && (
|
||||
<div className="mb-3 flex justify-center">
|
||||
@@ -147,21 +146,19 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
onClick={() => handlePCBSelect('rad')}
|
||||
className={`px-4 py-2 border-2 rounded-lg transition-all ${
|
||||
selectedRemotePCB === 'rad'
|
||||
className={`px-4 py-2 border-2 rounded-lg transition-all ${selectedRemotePCB === 'rad'
|
||||
? 'border-blue-600 dark:border-blue-500 bg-blue-50 dark:bg-blue-900/30 text-blue-900 dark:text-blue-300 font-medium'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
Purchase from RAD
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handlePCBSelect('pcbway')}
|
||||
className={`px-4 py-2 border-2 rounded-lg transition-all ${
|
||||
selectedRemotePCB === 'pcbway'
|
||||
className={`px-4 py-2 border-2 rounded-lg transition-all ${selectedRemotePCB === 'pcbway'
|
||||
? 'border-blue-600 dark:border-blue-500 bg-blue-50 dark:bg-blue-900/30 text-blue-900 dark:text-blue-300 font-medium'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
Self-source with PCBWay
|
||||
</button>
|
||||
@@ -177,11 +174,10 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
<button
|
||||
key={knob.id}
|
||||
onClick={() => handleKnobSelect(knob)}
|
||||
className={`p-4 border-2 rounded-lg text-left transition-all w-full ${
|
||||
isSelected
|
||||
className={`p-4 border-2 rounded-lg text-left transition-all w-full ${isSelected
|
||||
? 'border-blue-600 dark:border-blue-500 bg-blue-50 dark:bg-blue-900/30'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700/50'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div className="flex-1">
|
||||
@@ -243,7 +239,7 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
|
||||
{/* Remote Selection */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-semibold mb-3">Remote System</h3>
|
||||
<h3 className="text-lg font-semibold mb-3 text-gray-900 dark:text-white">Remote System</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{availableRemotesFiltered.map((remote) => renderRemoteCard(remote))}
|
||||
</div>
|
||||
@@ -285,9 +281,8 @@ export default function RemoteStep({ config, updateConfig, buildType }) {
|
||||
)}
|
||||
</div>
|
||||
<svg
|
||||
className={`w-4 h-4 text-gray-500 dark:text-gray-400 transition-transform ${
|
||||
expandedKnobs ? 'transform rotate-180' : ''
|
||||
}`}
|
||||
className={`w-4 h-4 text-gray-500 dark:text-gray-400 transition-transform ${expandedKnobs ? 'transform rotate-180' : ''
|
||||
}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - Actuator - Body - Bottom.stl",
|
||||
"checksum_sha256": "e7abdb99a7e9b9e7408a7b04a7dd50e42cc74510ea2969016a45a2a1387dcde3",
|
||||
"last_checked": "2026-01-07T01:21:02.027595+00:00",
|
||||
"last_checked": "2026-01-07T06:30:14.604915+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
},
|
||||
@@ -39,7 +39,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - Actuator - Body - Middle.stl",
|
||||
"checksum_sha256": "ce6fb769378636c287af788ce42bdab1f2185dcffba929a0c72598742793b48a",
|
||||
"last_checked": "2026-01-07T01:21:03.531342+00:00",
|
||||
"last_checked": "2026-01-07T06:30:22.906540+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
},
|
||||
@@ -51,6 +51,9 @@
|
||||
"timeEstimate": "1h3m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"Condition": {
|
||||
"cover.id": "standard-cover"
|
||||
},
|
||||
"filePath": "OSSM - Actuator Body Cover.stl",
|
||||
"url": "https://github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Actuator/OSSM%20-%20Actuator%20-%20Body%20-%20Cover.stl?raw=true",
|
||||
"vendor": {
|
||||
@@ -59,7 +62,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - Actuator - Body - Cover.stl",
|
||||
"checksum_sha256": "bbabc742d2f1753d1b4e21e42c197aec31a4a083b5c634e6e825cec69d4e3258",
|
||||
"last_checked": "2026-01-07T01:21:02.767604+00:00",
|
||||
"last_checked": "2026-01-07T06:30:18.689516+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
},
|
||||
@@ -99,7 +102,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - 24mm Clamping Thread - Belt Clamp.stl",
|
||||
"checksum_sha256": "457a71bc09cb53f12026fd829bec8fa5b04fdead0788822935780f42c90b9a7a",
|
||||
"last_checked": "2026-01-07T01:20:58.945151+00:00",
|
||||
"last_checked": "2026-01-07T06:30:08.525159+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
},
|
||||
@@ -119,7 +122,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - 24mm Clamping Thread - End Effector.stl",
|
||||
"checksum_sha256": "4860947b201e2e773b295d33bba09423ae40b4adeef3605d62687f2d40277de1",
|
||||
"last_checked": "2026-01-07T01:20:59.854476+00:00",
|
||||
"last_checked": "2026-01-07T06:30:09.547007+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
},
|
||||
@@ -139,7 +142,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Actuator/OSSM - 24mm Nut - 5 Sided.stl",
|
||||
"checksum_sha256": "38630c70b2fb929bba9a705dabf5bbd7b49ec882963e042b7108dc74284dd6ff",
|
||||
"last_checked": "2026-01-07T01:21:00.555525+00:00",
|
||||
"last_checked": "2026-01-07T06:30:10.564924+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@
|
||||
"timeEstimate": "2h10m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"Condition": {
|
||||
"motor.id": "57AIM30"
|
||||
},
|
||||
"filePath": "OSSM - Base - PitClamp Mini - 57AIM30 V1.1.stl",
|
||||
"url": "https://github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Mounting/OSSM%20-%20Mounting%20Ring%20-%20PitClamp%20Mini%20-%2057AIM%20V1.1.stl?raw=true",
|
||||
"vendor": {
|
||||
@@ -71,6 +74,9 @@
|
||||
"timeEstimate": "2h10m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"Condition": {
|
||||
"motor.id": "42AIM30"
|
||||
},
|
||||
"filePath": "OSSM - Base - PitClamp Mini - 42AIM30 V1.1.stl",
|
||||
"url": "https://github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Mounting/Non-standard/OSSM%20-%20Mounting%20Ring%20-%20PitClamp%20Mini%20-%2042AIM%20V1.1.stl?raw=true",
|
||||
"vendor": {
|
||||
@@ -91,6 +97,9 @@
|
||||
"timeEstimate": "2h10m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"Condition": {
|
||||
"motor.id": "iHSV57"
|
||||
},
|
||||
"filePath": "OSSM - Base - PitClamp Mini - iHSV57 V1.1.stl",
|
||||
"url": "https://github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Mounting/Non-standard/OSSM%20-%20Mounting%20Ring%20-%20PitClamp%20Mini%20-%20iHSV57.stl?raw=true",
|
||||
"vendor": {
|
||||
@@ -185,6 +194,9 @@
|
||||
"timeEstimate": "5h8m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"replaces": [
|
||||
"ossm-actuator-body-middle"
|
||||
],
|
||||
"filePath": "OSSM - Actuator Body Middle Pivot.stl",
|
||||
"url": "https://github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Actuator/Non-standard/OSSM%20-%20Actuator%20-%20Body%20-%20Middle%20Pivot.stl?raw=true",
|
||||
"vendor": {
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Stand/OSSM - Stand - 3030 Extrusion Base - Handle Spacer.stl",
|
||||
"checksum_sha256": "55ede7dff60a31d68159b352b5f2c63792b7a0dbe9d543a43681c3e52d229115",
|
||||
"last_checked": "2026-01-07T01:20:58.324330+00:00",
|
||||
"last_checked": "2026-01-07T06:30:07.525364+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@
|
||||
"pinned_sha": "52537c0896eaef83fd9771dcc633903c7aa6a8ab",
|
||||
"pinned_raw_url": "https://raw.githubusercontent.com/KinkyMakers/OSSM-hardware/52537c0896eaef83fd9771dcc633903c7aa6a8ab/Printed Parts/Stand/OSSM - Stand - 3030 Extrusion Base - Extrusion Cap.stl",
|
||||
"checksum_sha256": "56fa9bb318cdeadc6d1698a1e6cef9371e58b0bc9c7729985bf639d8da2f25da",
|
||||
"last_checked": "2026-01-07T01:21:01.205246+00:00",
|
||||
"last_checked": "2026-01-07T06:30:11.578686+00:00",
|
||||
"status": "up-to-date"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
{
|
||||
"toyMounts": {
|
||||
"category": "Toy Mounts",
|
||||
"type": "mod",
|
||||
"printedParts": [
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-24mm-threaded",
|
||||
"name": "Toy Mount Flange Base 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 46.26,
|
||||
"timeEstimate": "1h48m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-24mm-threaded.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-dildo-ring-2.5in ",
|
||||
"name": "Toy Mount Flange Base Dildo Ring 2.5in",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-dildo-ring-2_5in.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-dildo-ring-2in",
|
||||
"name": "Toy Mount Flange Base Dildo Ring 2in",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-dildo-ring-2in.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-double-double-24mm-threaded",
|
||||
"name": "Toy Mount Double Double 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-double-double-24mm-threaded.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-double-double-rail-mounted",
|
||||
"name": "Toy Mount Double Double Rail Mounted",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-double-double-rail-mounted.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-base-plate-24mm-threaded",
|
||||
"name": "Toy Mount Sucson Mount Base Plate 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-base-plate-24mm-threaded.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-ring-insert-55mm",
|
||||
"name": "Toy Mount Sucson Mount Ring Insert 55mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-ring-insert-55mm.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-threaded-ring",
|
||||
"name": "Toy Mount Sucson Mount Threaded Ring",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-threaded-ring.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-tie-down-and-suction-plate-110mm",
|
||||
"name": "Toy Mount Tie Down and Suction Plate 110mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-tie-down-and-suction-plate-110mm.stl"
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-tie-down-and-suction-plate-135mm",
|
||||
"name": "Toy Mount Tie Down and Suction Plate 135mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-tie-down-and-suction-plate-135mm.stl"
|
||||
}
|
||||
],
|
||||
"hardwareParts": [
|
||||
{
|
||||
"id": "toy-mount-hardware",
|
||||
"required": true,
|
||||
"relatedParts": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
14
website/src/data/components/toyMounts/index.js
Normal file
14
website/src/data/components/toyMounts/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import ossm from './ossm.json';
|
||||
|
||||
const rawParts = [ossm];
|
||||
|
||||
const mergedToyMounts = {
|
||||
category: "Toy Mounts",
|
||||
type: "mod",
|
||||
printedParts: rawParts.flatMap(v => v.printedParts || []),
|
||||
hardwareParts: rawParts.flatMap(v => v.hardwareParts || [])
|
||||
};
|
||||
|
||||
export default {
|
||||
toyMounts: mergedToyMounts
|
||||
};
|
||||
211
website/src/data/components/toyMounts/ossm.json
Normal file
211
website/src/data/components/toyMounts/ossm.json
Normal file
@@ -0,0 +1,211 @@
|
||||
{
|
||||
"printedParts": [
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-24mm-threaded",
|
||||
"name": "Toy Mount Flange Base 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 46.26,
|
||||
"timeEstimate": "1h48m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-24mm-threaded.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Flange%20Base%2024mm%20Threaded.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-flange-base-24mm-threaded",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Flange Base 24mm Threaded.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-dildo-ring-2.5in ",
|
||||
"name": "Toy Mount Flange Base Dildo Ring 2.5in",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-dildo-ring-2_5in.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Flange%20Base%20Dildo%20Ring%202.5in.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-flange-base-dildo-ring-2.5in ",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Flange Base Dildo Ring 2.5in.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-flange-base-dildo-ring-2in",
|
||||
"name": "Toy Mount Flange Base Dildo Ring 2in",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-flange-base-dildo-ring-2in.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Flange%20Base%20Dildo%20Ring%202in.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-flange-base-dildo-ring-2in",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Flange Base Dildo Ring 2in.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-double-double-24mm-threaded",
|
||||
"name": "Toy Mount Double Double 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-double-double-24mm-threaded.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Double%20Double%2024mm%20Threaded.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-double-double-24mm-threaded",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Double Double 24mm Threaded.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-double-double-rail-mounted",
|
||||
"name": "Toy Mount Double Double Rail Mounted",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-double-double-rail-mounted.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Double%20Double%20Rail%20Mounted.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-double-double-rail-mounted",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Double Double Rail Mounted.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-base-plate-24mm-threaded",
|
||||
"name": "Toy Mount Sucson Mount Base Plate 24mm Threaded",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-base-plate-24mm-threaded.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Sucson%20Mount%20Base%20Plate%2024mm%20Threaded.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-sucson-mount-base-plate-24mm-threaded",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Sucson Mount Base Plate 24mm Threaded.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-ring-insert-55mm",
|
||||
"name": "Toy Mount Sucson Mount Ring Insert 55mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "primary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-ring-insert-55mm.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Sucson%20Mount%20Ring%20Insert%2055mm.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-sucson-mount-ring-insert-55mm",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Sucson Mount Ring Insert 55mm.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-sucson-mount-threaded-ring",
|
||||
"name": "Toy Mount Sucson Mount Threaded Ring",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-sucson-mount-threaded-ring.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Sucson%20Mount%20Threaded%20Ring.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-sucson-mount-threaded-ring",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Sucson Mount Threaded Ring.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-tie-down-and-suction-plate-110mm",
|
||||
"name": "Toy Mount Tie Down and Suction Plate 110mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-tie-down-and-suction-plate-110mm.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Tie%20Down%20and%20Suction%20Plate%20110mm.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-tie-down-and-suction-plate-110mm",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Tie Down and Suction Plate 110mm.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ossm-toy-mount-tie-down-and-suction-plate-135mm",
|
||||
"name": "Toy Mount Tie Down and Suction Plate 135mm",
|
||||
"description": "Toy mount system",
|
||||
"filamentEstimate": 15.24,
|
||||
"timeEstimate": "55m",
|
||||
"colour": "secondary",
|
||||
"required": true,
|
||||
"filePath": "ossm-toy-mount-tie-down-and-suction-plate-135mm.stl",
|
||||
"url": "https://action.github.com/KinkyMakers/OSSM-hardware/blob/main/Printed%20Parts/Toy%20Mounts/OSSM%20-%20Toy%20Mount%20Tie%20Down%20and%20Suction%20Plate%20135mm.stl?raw=true",
|
||||
"vendor": {
|
||||
"manifest_id": "ossm-toy-mount-tie-down-and-suction-plate-135mm",
|
||||
"local_path": "vendor/KinkyMakers-OSSM-hardware/Printed Parts/Toy Mounts/OSSM - Toy Mount Tie Down and Suction Plate 135mm.stl",
|
||||
"pinned_sha": null,
|
||||
"pinned_raw_url": null,
|
||||
"checksum_sha256": null,
|
||||
"last_checked": null,
|
||||
"status": "pending"
|
||||
}
|
||||
}
|
||||
],
|
||||
"hardwareParts": [
|
||||
{
|
||||
"id": "toy-mount-hardware",
|
||||
"required": true,
|
||||
"relatedParts": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import motors from './motors.json';
|
||||
import powerSupplies from './powerSupplies.json';
|
||||
import optionsData from './options.json';
|
||||
import colors from './colors.json';
|
||||
import hardwareData from './hardware.json';
|
||||
import motors from './components/motors.json';
|
||||
import powerSupplies from './components/powerSupplies.json';
|
||||
import optionsData from './config/options.json';
|
||||
import colors from './common/colors.json';
|
||||
import hardwareData from './common/hardware.json';
|
||||
import actuatorComponents from './components/actuator.json';
|
||||
import standComponents from './components/stand.json';
|
||||
import mountingComponents from './components/mounting.json';
|
||||
import toyMountsComponents from './components/toyMounts.json';
|
||||
import toyMountsComponents from './components/toyMounts/index.js';
|
||||
import remoteComponents from './components/remote.json';
|
||||
import pcbComponents from './components/pcb.json';
|
||||
|
||||
@@ -21,10 +21,10 @@ Object.values(hardwareData).forEach((category) => {
|
||||
// Function to resolve hardware references (IDs) to full hardware definitions
|
||||
const resolveHardwareReferences = (components) => {
|
||||
const resolvedComponents = {};
|
||||
|
||||
|
||||
Object.entries(components).forEach(([componentKey, component]) => {
|
||||
resolvedComponents[componentKey] = { ...component };
|
||||
|
||||
|
||||
// Resolve hardwareParts if they exist
|
||||
if (component.hardwareParts) {
|
||||
resolvedComponents[componentKey].hardwareParts = component.hardwareParts.map((hw) => {
|
||||
@@ -51,7 +51,7 @@ const resolveHardwareReferences = (components) => {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Also resolve hardwareParts in systems
|
||||
if (component.systems) {
|
||||
resolvedComponents[componentKey].systems = {};
|
||||
@@ -82,7 +82,7 @@ const resolveHardwareReferences = (components) => {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return resolvedComponents;
|
||||
};
|
||||
|
||||
@@ -133,7 +133,7 @@ const convertComponentPartsToOptions = (componentIds, componentData) => {
|
||||
});
|
||||
return allKnobs;
|
||||
}
|
||||
|
||||
|
||||
// New structure: systems with printedParts and hardwareParts (for hinges, etc.)
|
||||
return componentIds
|
||||
.map((systemId) => {
|
||||
@@ -142,12 +142,12 @@ const convertComponentPartsToOptions = (componentIds, componentData) => {
|
||||
console.warn(`Component system not found: ${systemId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Calculate total filament estimate from printed parts
|
||||
const totalFilament = (system.printedParts || system.bodyParts)?.reduce((sum, part) => {
|
||||
return sum + (part.filamentEstimate || 0);
|
||||
}, 0) || 0;
|
||||
|
||||
|
||||
return {
|
||||
id: systemId,
|
||||
name: system.name,
|
||||
@@ -176,7 +176,7 @@ const convertComponentPartsToOptions = (componentIds, componentData) => {
|
||||
console.warn(`Component part not found: ${componentId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
id: part.id,
|
||||
name: part.name,
|
||||
@@ -196,24 +196,24 @@ const convertComponentPartsToOptions = (componentIds, componentData) => {
|
||||
// Merge component options into options
|
||||
const processOptions = (options, componentsData) => {
|
||||
const processedOptions = { ...options };
|
||||
|
||||
|
||||
// Process each option category
|
||||
Object.keys(processedOptions).forEach((optionKey) => {
|
||||
const optionCategory = processedOptions[optionKey];
|
||||
if (!optionCategory || !optionCategory.sections) return;
|
||||
|
||||
|
||||
const sections = { ...optionCategory.sections };
|
||||
const categoryUseComponents = optionCategory.useComponents;
|
||||
|
||||
|
||||
// Convert component parts to options format for each section
|
||||
Object.keys(sections).forEach((sectionKey) => {
|
||||
const section = sections[sectionKey];
|
||||
|
||||
|
||||
// Check if section has componentIds to process
|
||||
if (section.componentIds !== undefined) {
|
||||
// Determine which component category to use
|
||||
const componentKey = section.useComponents || categoryUseComponents;
|
||||
|
||||
|
||||
if (componentKey) {
|
||||
const componentData = componentsData[componentKey];
|
||||
const options = convertComponentPartsToOptions(section.componentIds, componentData);
|
||||
@@ -224,19 +224,19 @@ const processOptions = (options, componentsData) => {
|
||||
console.warn(`No useComponents specified for ${optionKey}.${sectionKey}`);
|
||||
section.options = [];
|
||||
}
|
||||
|
||||
|
||||
// Clean up temporary properties
|
||||
delete section.componentIds;
|
||||
delete section.useComponents;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
processedOptions[optionKey].sections = sections;
|
||||
if (categoryUseComponents) {
|
||||
delete processedOptions[optionKey].useComponents;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return processedOptions;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ import ExcelJS from 'exceljs';
|
||||
// Generate markdown overview
|
||||
export const generateMarkdownOverview = (config, printedParts, hardwareParts, filamentTotals, totalTime, total) => {
|
||||
const md = [];
|
||||
|
||||
|
||||
md.push('# OSSM Build Configuration');
|
||||
md.push(`\n**Generated:** ${new Date().toLocaleString()}\n`);
|
||||
|
||||
|
||||
// Motor
|
||||
if (config.motor) {
|
||||
md.push(`## Motor: ${config.motor.name}`);
|
||||
@@ -15,38 +15,38 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
md.push(`- **Wattage:** ${config.motor.wattage}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Power Supply
|
||||
if (config.powerSupply) {
|
||||
md.push(`## Power Supply: ${config.powerSupply.name}`);
|
||||
md.push(`- **Price:** ${config.powerSupply.price}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Colors
|
||||
md.push(`## Colors`);
|
||||
md.push(`- **Primary:** ${config.primaryColor || 'Not selected'}`);
|
||||
md.push(`- **Accent:** ${config.accentColor || 'Not selected'}`);
|
||||
md.push('');
|
||||
|
||||
|
||||
// Mount
|
||||
if (config.mount) {
|
||||
md.push(`## Mount: ${config.mount.name}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Cover
|
||||
if (config.cover) {
|
||||
md.push(`## Cover: ${config.cover.name}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// PCB Mount
|
||||
if (config.pcbMount) {
|
||||
md.push(`## PCB Mount: ${config.pcbMount.name}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Stand Options
|
||||
if (config.standHinge || config.standFeet || config.standCrossbarSupports?.length > 0) {
|
||||
md.push(`## Stand Options`);
|
||||
@@ -57,7 +57,7 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
}
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Remote
|
||||
if (config.remote || config.remoteKnob) {
|
||||
md.push(`## Remote`);
|
||||
@@ -65,7 +65,7 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
if (config.remoteKnob) md.push(`- **Knob:** ${config.remoteKnob.name}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Filament Summary
|
||||
if (filamentTotals.total > 0) {
|
||||
md.push(`## Filament Summary`);
|
||||
@@ -75,12 +75,12 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
md.push(`- **Estimated Print Time:** ${totalTime}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Print Parts Summary
|
||||
if (printedParts.length > 0) {
|
||||
md.push(`## Printed Parts Summary`);
|
||||
md.push(`- **Total Parts:** ${printedParts.length}`);
|
||||
|
||||
|
||||
// Group by category
|
||||
const partsByCategory = {};
|
||||
printedParts.forEach(part => {
|
||||
@@ -90,7 +90,7 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
}
|
||||
partsByCategory[category].push(part);
|
||||
});
|
||||
|
||||
|
||||
Object.entries(partsByCategory).forEach(([category, parts]) => {
|
||||
md.push(`### ${category} (${parts.length} parts)`);
|
||||
parts.forEach(part => {
|
||||
@@ -99,31 +99,31 @@ export const generateMarkdownOverview = (config, printedParts, hardwareParts, fi
|
||||
});
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Hardware Summary
|
||||
if (hardwareParts.length > 0) {
|
||||
md.push(`## Hardware Summary`);
|
||||
md.push(`- **Total Items:** ${hardwareParts.length}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
// Cost Summary
|
||||
if (total > 0) {
|
||||
md.push(`## Estimated Cost`);
|
||||
md.push(`- **Total:** $${total.toFixed(2)}`);
|
||||
md.push('');
|
||||
}
|
||||
|
||||
|
||||
return md.join('\n');
|
||||
};
|
||||
|
||||
// Generate Excel BOM with purchase links
|
||||
export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
const rows = [];
|
||||
|
||||
|
||||
// Header
|
||||
rows.push(['Item', 'Name', 'Quantity', 'Price', 'Link', 'Category', 'Type']);
|
||||
|
||||
|
||||
// Add motor
|
||||
if (config.motor) {
|
||||
const motorLinks = config.motor.links || [];
|
||||
@@ -138,7 +138,7 @@ export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
'Hardware'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Add power supply
|
||||
if (config.powerSupply) {
|
||||
const psuLinks = config.powerSupply.links || [];
|
||||
@@ -153,7 +153,7 @@ export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
'Hardware'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Add hardware parts
|
||||
hardwareParts.forEach(hw => {
|
||||
const links = hw.links || [];
|
||||
@@ -168,7 +168,7 @@ export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
'Hardware'
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// Add printed parts (for reference, not purchase)
|
||||
printedParts.forEach(part => {
|
||||
rows.push([
|
||||
@@ -181,14 +181,14 @@ export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
'Printed Part'
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// Create workbook and worksheet
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet('BOM');
|
||||
|
||||
|
||||
// Add rows
|
||||
worksheet.addRows(rows);
|
||||
|
||||
|
||||
// Set column widths
|
||||
worksheet.columns = [
|
||||
{ width: 30 }, // Item
|
||||
@@ -199,42 +199,42 @@ export const generateExcelBOM = (hardwareParts, printedParts, config) => {
|
||||
{ width: 20 }, // Category
|
||||
{ width: 15 } // Type
|
||||
];
|
||||
|
||||
|
||||
return workbook;
|
||||
};
|
||||
|
||||
// Generate Excel Print List with completion tracker
|
||||
export const generateExcelPrintList = (printedParts, filamentTotals) => {
|
||||
const rows = [];
|
||||
|
||||
|
||||
// Header
|
||||
rows.push(['Part Name', 'Category', 'Color', 'Quantity', 'Filament (g)', 'Print Time', 'Status', 'Completed']);
|
||||
|
||||
|
||||
// Group parts by category and color
|
||||
const partsByCategoryColor = {};
|
||||
printedParts.forEach(part => {
|
||||
const category = part.category || 'Other';
|
||||
const color = part.colour === 'primary' ? 'Primary' : part.colour === 'secondary' ? 'Accent' : 'Other';
|
||||
const key = `${category}_${color}`;
|
||||
|
||||
|
||||
if (!partsByCategoryColor[key]) {
|
||||
partsByCategoryColor[key] = [];
|
||||
}
|
||||
partsByCategoryColor[key].push(part);
|
||||
});
|
||||
|
||||
|
||||
// Sort by category, then color
|
||||
const sortedKeys = Object.keys(partsByCategoryColor).sort();
|
||||
|
||||
|
||||
sortedKeys.forEach(key => {
|
||||
const parts = partsByCategoryColor[key];
|
||||
const [category, color] = key.split('_');
|
||||
|
||||
|
||||
parts.forEach(part => {
|
||||
const filament = typeof part.filamentEstimate === 'number'
|
||||
? part.filamentEstimate
|
||||
const filament = typeof part.filamentEstimate === 'number'
|
||||
? part.filamentEstimate
|
||||
: parseFloat(part.filamentEstimate?.replace('~', '').replace('g', '')) || 0;
|
||||
|
||||
|
||||
rows.push([
|
||||
part.name || part.id || '',
|
||||
category,
|
||||
@@ -247,18 +247,18 @@ export const generateExcelPrintList = (printedParts, filamentTotals) => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Add summary row
|
||||
rows.push([]);
|
||||
rows.push(['TOTAL', '', '', printedParts.length, filamentTotals.total.toFixed(2), '', '', '']);
|
||||
|
||||
|
||||
// Create workbook and worksheet
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet('Print List');
|
||||
|
||||
|
||||
// Add rows
|
||||
worksheet.addRows(rows);
|
||||
|
||||
|
||||
// Set column widths
|
||||
worksheet.columns = [
|
||||
{ width: 40 }, // Part Name
|
||||
@@ -270,18 +270,18 @@ export const generateExcelPrintList = (printedParts, filamentTotals) => {
|
||||
{ width: 15 }, // Status
|
||||
{ width: 12 } // Completed
|
||||
];
|
||||
|
||||
|
||||
// Create a summary sheet with progress calculation
|
||||
const summaryWorksheet = workbook.addWorksheet('Summary');
|
||||
|
||||
|
||||
// Add summary rows
|
||||
summaryWorksheet.getCell('A1').value = 'Print Progress Summary';
|
||||
summaryWorksheet.getCell('A3').value = 'Total Parts';
|
||||
summaryWorksheet.getCell('B3').value = printedParts.length;
|
||||
summaryWorksheet.getCell('A4').value = 'Completed Parts';
|
||||
summaryWorksheet.getCell('B4').formula = `COUNTIF('Print List'.H:H,"✓")`;
|
||||
summaryWorksheet.getCell('B4').value = { formula: `COUNTIF('Print List'.H:H,"✓")` };
|
||||
summaryWorksheet.getCell('A5').value = 'Progress %';
|
||||
summaryWorksheet.getCell('B5').formula = `IF(B3>0, (B4/B3)*100, 0)`;
|
||||
summaryWorksheet.getCell('B5').value = { formula: `IF(B3>0, (B4/B3)*100, 0)` };
|
||||
summaryWorksheet.getCell('A7').value = 'Filament Summary';
|
||||
summaryWorksheet.getCell('A8').value = 'Total Filament (g)';
|
||||
summaryWorksheet.getCell('B8').value = filamentTotals.total.toFixed(2);
|
||||
@@ -289,12 +289,12 @@ export const generateExcelPrintList = (printedParts, filamentTotals) => {
|
||||
summaryWorksheet.getCell('B9').value = filamentTotals.primary.toFixed(2);
|
||||
summaryWorksheet.getCell('A10').value = 'Accent Color (g)';
|
||||
summaryWorksheet.getCell('B10').value = (filamentTotals.secondary || 0).toFixed(2);
|
||||
|
||||
|
||||
// Set column widths for summary sheet
|
||||
summaryWorksheet.columns = [
|
||||
{ width: 25 },
|
||||
{ width: 15 }
|
||||
];
|
||||
|
||||
|
||||
return workbook;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user