Skip to content

Commit

Permalink
Merge pull request #909 from vorth/zometool-products
Browse files Browse the repository at this point in the history
added zometool-covering-products web component
  • Loading branch information
vorth authored Aug 12, 2024
2 parents 42a865c + 8be0155 commit f6f9f00
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 1 deletion.
2 changes: 1 addition & 1 deletion online/serve/app/test/cases/zometool-model/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ <h1>Zometool Model Demo</h1>
</zometool-instructions>

<zometool-parts-required></zometool-parts-required>
<zometool-covering-products>Products list here</zometool-covering-products>
<zometool-covering-products>Supporting Products:</zometool-covering-products>

</div>
<!-- ^^^^^^^ ----- This is the portion you will enter as content HTML for the page -->
Expand Down
2 changes: 2 additions & 0 deletions online/src/wc/zometool/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { instructionsCSS } from "./zometool.css.js";
import { urlViewerCSS } from "../../viewer/urlviewer.css.js";

import { ZometoolPartsElement } from './parts-list.jsx';
import { ZometoolProductsElement } from './products-list.jsx';
import { normalizeBOM } from './bom.js';

const debug = false;
Expand Down Expand Up @@ -205,5 +206,6 @@ class ZometoolInstructionsElement extends HTMLElement

customElements.define( "zometool-instructions", ZometoolInstructionsElement );
customElements.define( "zometool-parts-required", ZometoolPartsElement );
customElements.define( "zometool-covering-products", ZometoolProductsElement );


138 changes: 138 additions & 0 deletions online/src/wc/zometool/products-list.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { createSignal } from "solid-js";
import { render } from "solid-js/web";

import { Link } from "@kobalte/core/link";

import { instructionsCSS } from "./zometool.css.js";

const debug = false;

const product_catalog_url = 'https://zometool.github.io/vzome-sharing/metadata/zometool-products.json';
const parts_catalog_url = 'https://zometool.github.io/vzome-sharing/metadata/zometool-parts.json';

const fetchJSON = url => fetch( url ) .then( response => response.text() ) .then( text => JSON.parse( text ) );
const productsPromise = fetchJSON( product_catalog_url );
const partsPromise = fetchJSON( parts_catalog_url );

const findProducts = ( bom, parts, products ) =>
{
const productCoversBom = ( product, bom ) =>
bom .reduce( (covers, part) => covers && product.bom[ part.partNum ] >= part.count, true );

const result = [];
Object.entries( products ) .map( ([ code, product ]) => {
if ( productCoversBom( product, bom ) )
result .push( { name: product.label, url: product.url } );
} );
return result;
}

const productUrl = url => new URL( url, 'https://zometool.com' );

const ZometoolProducts = props =>
{
const [ matchingProducts, setMatchingProducts ] = createSignal( [] );

Promise.all( [ productsPromise, partsPromise ] )
.then( ([ products, parts ]) => {
setMatchingProducts( findProducts( props.bom, parts, products ) );
} );

return (
<div class='zometool-products-table'>
<ul>
<For each={matchingProducts()} >
{ ( { name, url } ) =>
<li class='matched-product'>
<div class='product-name'>{name}</div>
<Link class="link" href={productUrl(url)} target="_blank" rel="noopener">View Product</Link>
</li>
}
</For>
</ul>
</div>
);
}

const renderComponent = ( container, bom ) =>
{
const bindComponent = () =>
{
return (
<ZometoolProducts bom={bom}>
</ZometoolProducts>
);
}

// Apply external override styles to the shadow dom
// const linkElem = document.createElement("link");
// linkElem .setAttribute("rel", "stylesheet");
// linkElem .setAttribute("href", "./zometool-styles.css");
// container .appendChild( linkElem );

render( bindComponent, container );
}

// TODO: this is almost identical to ZometoolPartsElement... make a superclass
export class ZometoolProductsElement extends HTMLElement
{
#instructionsId;
#instructions;

constructor()
{
super();

debug && console.log( 'ZometoolProductsElement constructed' );
}

connectedCallback()
{
if ( !! this.#instructionsId ) {
this.#instructions = document .querySelector( `#${this.#instructionsId}` );
if ( ! this.#instructions ) {
console.error( `No zometool-instructions with id "${this.#instructionsId}" found.` );
} else if ( this.#instructions .getParts === undefined ) {
console.error( `Element with id "${this.#instructionsId}" is not a zometool-instructions.` );
return;
}
}
if ( ! this.#instructions ) {
this.#instructions = document .querySelector( 'zometool-instructions' );
}
if ( ! this.#instructions ) {
console.error( `No zometool-instructions found.` );
return;
}

this.#instructions .addEventListener( "zometool-instructions-loaded", (e) => {
debug && console.log( JSON.stringify( e.detail ) );

this .appendChild( document.createElement("style") ).textContent = instructionsCSS;
const container = document.createElement("div");
container .classList .add( 'zometool-products-container' );
this .appendChild( container );

renderComponent( container, e.detail )
} );

debug && console.log( 'ZometoolProductsElement connected' );
}

static get observedAttributes()
{
return [ "instructions" ];
}

attributeChangedCallback( attributeName, _oldValue, _newValue )
{
debug && console.log( 'ZometoolProductsElement attribute changed' );
switch (attributeName) {

case "instructions":
this.#instructionsId = _newValue;
break;
}
}
}

5 changes: 5 additions & 0 deletions online/src/wc/zometool/zometool.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,9 @@ export const instructionsCSS = `
grid-template-rows: min-content 1fr 90px;
}
.matched-product {
min-width: 250px;
display: flex;
justify-content: space-between;
}
`;

0 comments on commit f6f9f00

Please sign in to comment.