This commit is contained in:
lovebird 2025-03-16 15:06:56 +01:00
parent 194c3a9a16
commit c3e1b1ff66
10 changed files with 518 additions and 179 deletions

View File

@ -45,15 +45,6 @@
"handling": 2
}
},
"manufacturing": {
"type": "object",
"properties": {
"lead_time": {
"type": "number"
}
},
"additionalProperties": false
},
"replaced_by": {
"type": "string"
},
@ -145,9 +136,6 @@
"name": {
"type": "string"
},
"flags": {
"type": "number"
},
"edrawings": {
"type": "string"
},
@ -184,12 +172,28 @@
},
"default": []
},
"manufacturing": {
"type": "object",
"properties": {
"lead_time": {
"type": "number"
}
},
"additionalProperties": false
},
"showDimensions": {
"type": "boolean"
},
"showParts": {
"type": "boolean"
},
"Preview3d": {
"type": "boolean"
},
"flags": {
"type": "number",
"default": 0
},
"slug": {
"type": "string"
},
@ -358,84 +362,236 @@
}
}
},
"Preview3d": {
"type": "boolean"
},
"howto_categories": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"components": {
"type": "array",
"items": {
"type": "object",
"properties": {
"cart_id": {
"$ref": "#/definitions/projects/properties/cart_id"
},
"code": {
"$ref": "#/definitions/projects/properties/code"
},
"price": {
"$ref": "#/definitions/projects/properties/price"
},
"cscartCats": {
"$ref": "#/definitions/projects/properties/cscartCats"
},
"cscartId": {
"$ref": "#/definitions/projects/properties/cscartId"
},
"vendorId": {
"$ref": "#/definitions/projects/properties/vendorId"
},
"shipping": {
"$ref": "#/definitions/projects/properties/shipping"
},
"replaced_by": {
"$ref": "#/definitions/projects/properties/replaced_by"
},
"alternatives": {
"$ref": "#/definitions/projects/properties/alternatives"
},
"used_by": {
"$ref": "#/definitions/projects/properties/used_by"
},
"image": {
"$ref": "#/definitions/projects/properties/image"
},
"name": {
"$ref": "#/definitions/projects/properties/name"
},
"edrawings": {
"$ref": "#/definitions/projects/properties/edrawings"
},
"cad": {
"$ref": "#/definitions/projects/properties/cad"
},
"manufacturing": {
"$ref": "#/definitions/projects/properties/manufacturing"
},
"showDimensions": {
"$ref": "#/definitions/projects/properties/showDimensions"
},
"showParts": {
"$ref": "#/definitions/projects/properties/showParts"
},
"Preview3d": {
"$ref": "#/definitions/projects/properties/Preview3d"
},
"flags": {
"$ref": "#/definitions/projects/properties/flags"
},
"slug": {
"$ref": "#/definitions/projects/properties/slug"
},
"keywords": {
"$ref": "#/definitions/projects/properties/keywords"
},
"meta_keywords": {
"$ref": "#/definitions/projects/properties/meta_keywords"
},
"version": {
"$ref": "#/definitions/projects/properties/version"
},
"versions": {
"$ref": "#/definitions/projects/properties/versions"
},
"status": {
"$ref": "#/definitions/projects/properties/status"
},
"authors": {
"$ref": "#/definitions/projects/properties/authors"
},
"assets": {
"$ref": "#/definitions/projects/properties/assets"
},
"resources": {
"$ref": "#/definitions/projects/properties/resources"
},
"tests": {
"$ref": "#/definitions/projects/properties/tests"
},
"download": {
"$ref": "#/definitions/projects/properties/download"
},
"gallery": {
"$ref": "#/definitions/projects/properties/gallery"
},
"components": {
"$ref": "#/definitions/projects/properties/components"
},
"howto_categories": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"steps": {},
"sourceLanguage": {
"type": "string"
},
"category": {
"type": "string"
},
"product_dimensions": {
"type": "string"
},
"production": {
"type": "object",
"properties": {
"fusion-folder": {
"type": "string"
},
"nc-folder": {
"type": "string"
},
"cam": {
"type": "array",
"items": {
"$ref": "#/definitions/projects/properties/authors/items"
}
}
},
"required": [
"fusion-folder",
"nc-folder",
"cam"
],
"additionalProperties": false
},
"score": {
"type": "number"
},
"body": {
"type": "string"
},
"features": {
"type": "string"
},
"highlights": {
"type": "string"
},
"specs": {
"type": "string"
},
"license": {
"type": "string"
},
"readme": {
"type": "string"
},
"shared": {
"type": "string"
}
}
]
},
"required": [
"code",
"name",
"manufacturing",
"slug",
"category"
],
"additionalProperties": true
},
"default": []
},
"howto_categories": {
"$ref": "#/definitions/projects/properties/components/items/properties/howto_categories"
},
"steps": {
"$ref": "#/definitions/projects/properties/components/items/properties/steps"
},
"steps": {},
"sourceLanguage": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/sourceLanguage"
},
"category": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/category"
},
"product_dimensions": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/product_dimensions"
},
"production": {
"type": "object",
"properties": {
"fusion-folder": {
"type": "string"
},
"nc-folder": {
"type": "string"
},
"cam": {
"type": "array",
"items": {
"$ref": "#/definitions/projects/properties/authors/items"
}
}
},
"required": [
"fusion-folder",
"nc-folder",
"cam"
],
"additionalProperties": false
"$ref": "#/definitions/projects/properties/components/items/properties/production"
},
"score": {
"type": "number"
"$ref": "#/definitions/projects/properties/components/items/properties/score"
},
"body": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/body"
},
"features": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/features"
},
"highlights": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/highlights"
},
"specs": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/specs"
},
"license": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/license"
},
"readme": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/readme"
},
"shared": {
"type": "string"
"$ref": "#/definitions/projects/properties/components/items/properties/shared"
}
},
"required": [
"code",
"manufacturing",
"name",
"manufacturing",
"slug",
"category"
],

View File

@ -45,15 +45,6 @@
"handling": 2
}
},
"manufacturing": {
"type": "object",
"properties": {
"lead_time": {
"type": "number"
}
},
"additionalProperties": false
},
"replaced_by": {
"type": "string"
},
@ -145,9 +136,6 @@
"name": {
"type": "string"
},
"flags": {
"type": "number"
},
"edrawings": {
"type": "string"
},
@ -184,12 +172,28 @@
},
"default": []
},
"manufacturing": {
"type": "object",
"properties": {
"lead_time": {
"type": "number"
}
},
"additionalProperties": false
},
"showDimensions": {
"type": "boolean"
},
"showParts": {
"type": "boolean"
},
"Preview3d": {
"type": "boolean"
},
"flags": {
"type": "number",
"default": 0
},
"slug": {
"type": "string"
},
@ -358,84 +362,236 @@
}
}
},
"Preview3d": {
"type": "boolean"
},
"howto_categories": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"components": {
"type": "array",
"items": {
"type": "object",
"properties": {
"cart_id": {
"$ref": "#/definitions/store/properties/cart_id"
},
"code": {
"$ref": "#/definitions/store/properties/code"
},
"price": {
"$ref": "#/definitions/store/properties/price"
},
"cscartCats": {
"$ref": "#/definitions/store/properties/cscartCats"
},
"cscartId": {
"$ref": "#/definitions/store/properties/cscartId"
},
"vendorId": {
"$ref": "#/definitions/store/properties/vendorId"
},
"shipping": {
"$ref": "#/definitions/store/properties/shipping"
},
"replaced_by": {
"$ref": "#/definitions/store/properties/replaced_by"
},
"alternatives": {
"$ref": "#/definitions/store/properties/alternatives"
},
"used_by": {
"$ref": "#/definitions/store/properties/used_by"
},
"image": {
"$ref": "#/definitions/store/properties/image"
},
"name": {
"$ref": "#/definitions/store/properties/name"
},
"edrawings": {
"$ref": "#/definitions/store/properties/edrawings"
},
"cad": {
"$ref": "#/definitions/store/properties/cad"
},
"manufacturing": {
"$ref": "#/definitions/store/properties/manufacturing"
},
"showDimensions": {
"$ref": "#/definitions/store/properties/showDimensions"
},
"showParts": {
"$ref": "#/definitions/store/properties/showParts"
},
"Preview3d": {
"$ref": "#/definitions/store/properties/Preview3d"
},
"flags": {
"$ref": "#/definitions/store/properties/flags"
},
"slug": {
"$ref": "#/definitions/store/properties/slug"
},
"keywords": {
"$ref": "#/definitions/store/properties/keywords"
},
"meta_keywords": {
"$ref": "#/definitions/store/properties/meta_keywords"
},
"version": {
"$ref": "#/definitions/store/properties/version"
},
"versions": {
"$ref": "#/definitions/store/properties/versions"
},
"status": {
"$ref": "#/definitions/store/properties/status"
},
"authors": {
"$ref": "#/definitions/store/properties/authors"
},
"assets": {
"$ref": "#/definitions/store/properties/assets"
},
"resources": {
"$ref": "#/definitions/store/properties/resources"
},
"tests": {
"$ref": "#/definitions/store/properties/tests"
},
"download": {
"$ref": "#/definitions/store/properties/download"
},
"gallery": {
"$ref": "#/definitions/store/properties/gallery"
},
"components": {
"$ref": "#/definitions/store/properties/components"
},
"howto_categories": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"steps": {},
"sourceLanguage": {
"type": "string"
},
"category": {
"type": "string"
},
"product_dimensions": {
"type": "string"
},
"production": {
"type": "object",
"properties": {
"fusion-folder": {
"type": "string"
},
"nc-folder": {
"type": "string"
},
"cam": {
"type": "array",
"items": {
"$ref": "#/definitions/store/properties/authors/items"
}
}
},
"required": [
"fusion-folder",
"nc-folder",
"cam"
],
"additionalProperties": false
},
"score": {
"type": "number"
},
"body": {
"type": "string"
},
"features": {
"type": "string"
},
"highlights": {
"type": "string"
},
"specs": {
"type": "string"
},
"license": {
"type": "string"
},
"readme": {
"type": "string"
},
"shared": {
"type": "string"
}
}
]
},
"required": [
"code",
"name",
"manufacturing",
"slug",
"category"
],
"additionalProperties": true
},
"default": []
},
"howto_categories": {
"$ref": "#/definitions/store/properties/components/items/properties/howto_categories"
},
"steps": {
"$ref": "#/definitions/store/properties/components/items/properties/steps"
},
"steps": {},
"sourceLanguage": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/sourceLanguage"
},
"category": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/category"
},
"product_dimensions": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/product_dimensions"
},
"production": {
"type": "object",
"properties": {
"fusion-folder": {
"type": "string"
},
"nc-folder": {
"type": "string"
},
"cam": {
"type": "array",
"items": {
"$ref": "#/definitions/store/properties/authors/items"
}
}
},
"required": [
"fusion-folder",
"nc-folder",
"cam"
],
"additionalProperties": false
"$ref": "#/definitions/store/properties/components/items/properties/production"
},
"score": {
"type": "number"
"$ref": "#/definitions/store/properties/components/items/properties/score"
},
"body": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/body"
},
"features": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/features"
},
"highlights": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/highlights"
},
"specs": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/specs"
},
"license": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/license"
},
"readme": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/readme"
},
"shared": {
"type": "string"
"$ref": "#/definitions/store/properties/components/items/properties/shared"
}
},
"required": [
"code",
"manufacturing",
"name",
"manufacturing",
"slug",
"category"
],

File diff suppressed because one or more lines are too long

1
.gitignore vendored
View File

@ -29,3 +29,4 @@ pnpm-debug.log*
*.tmp
Thumbs.db
releases
undefined

View File

@ -4,7 +4,7 @@ export default defineConfig({
placeholder: "blurred",
format: ["webp", "avif", "jpg"],
fallbackFormat: "jpg",
delay:100,
delay:250,
includeSourceFormat: true,
formatOptions: {
jpg: {

70
package-lock.json generated
View File

@ -82,15 +82,41 @@
"sass-embedded": "^1.83.4"
}
},
"../astro-components/packages/imagetools": {
"version": "0.9.0",
"extraneous": true,
"license": "MIT",
"dependencies": {
"@astropub/codecs": "0.4.4",
"file-type": "17.1.1",
"find-cache-dir": "3.3.2",
"find-up": "^6.3.0",
"object-hash": "3.0.0",
"p-map": "^7.0.3",
"potrace": "2.1.8"
},
"devDependencies": {
"vitest": "^0.12.4"
},
"engines": {
"node": "^14.15.0 || >=16.0.0"
},
"optionalDependencies": {
"imagetools-core": "3.0.2"
},
"peerDependencies": {
"astro": ">=0.26 || >=1.0.0-beta"
}
},
"../polymech-mono/packages/cache": {
"name": "@polymech/cache",
"version": "0.4.8",
"license": "BSD-3-Clause",
"dependencies": {
"@polymech/commons": "link:..\\commons",
"@polymech/core": "link:..\\core",
"@polymech/fs": "link:..\\fs",
"@polymech/log": "link:..\\log",
"@polymech/commons": "file:../commons",
"@polymech/core": "file:../core",
"@polymech/fs": "file:../fs",
"@polymech/log": "file:../log",
"@types/node": "^22.10.2",
"cacache": "^19.0.1",
"md5": "^2.3.0",
@ -3233,13 +3259,13 @@
"license": "MIT"
},
"node_modules/@types/chai-subset": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz",
"integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==",
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.6.tgz",
"integrity": "sha512-m8lERkkQj+uek18hXOZuec3W/fCRTrU4hrnXjH3qhHy96ytuPaPiWGgu7sJb7tZxZonO75vYAjCvpe/e4VUwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "*"
"peerDependencies": {
"@types/chai": "<5.2.0"
}
},
"node_modules/@types/cookie": {
@ -7952,6 +7978,19 @@
"resolved": "packages/imagetools",
"link": true
},
"node_modules/imagetools-core": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-3.0.2.tgz",
"integrity": "sha512-DlArpNiefCc1syIqvOONcE8L8IahN8GjwaEjm6wIJIvuKoFoI1RcKmWWfS2dYxSlTiSp2X5b3JnHDjUXmWqlVA==",
"license": "MIT",
"optional": true,
"dependencies": {
"sharp": "^0.29.3"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@ -16790,19 +16829,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"packages/imagetools/node_modules/imagetools-core": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-3.0.2.tgz",
"integrity": "sha512-DlArpNiefCc1syIqvOONcE8L8IahN8GjwaEjm6wIJIvuKoFoI1RcKmWWfS2dYxSlTiSp2X5b3JnHDjUXmWqlVA==",
"license": "MIT",
"optional": true,
"dependencies": {
"sharp": "^0.29.3"
},
"engines": {
"node": ">=12.0.0"
}
},
"packages/imagetools/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",

View File

@ -17,11 +17,11 @@ import { ITEM_ASSET_URL, PRODUCT_CONFIG, PRODUCT_ROOT, DEFAULT_IMAGE_URL } from
import { GalleryImage, MetaJSON } from './images.js'
import { env } from './index.js'
import { log } from 'node:console'
const IMAGES_GLOB = '*.+(JPG|jpg|png|PNG|gif)'
export const default_sort = (files: string[]): string[] =>
{
export const default_sort = (files: string[]): string[] => {
const getSortableParts = (filename: string) => {
const baseName = path.parse(filename).name;
const match = baseName.match(/^(\d+)_?(.*)$/); // Match leading numbers
@ -40,6 +40,19 @@ export const default_sort = (files: string[]): string[] =>
return aText.localeCompare(bText, undefined, { numeric: true, sensitivity: 'base' })
});
}
export const default_filter = async (url: string) => {
try {
const response = await fetch(url, { method: 'HEAD' })
if (!response.ok) {
logger.warn(`Image URL not found ${url}`)
return false
}
} catch (error) {
logger.warn(`Image URL not found ${url} : ${error.message}`)
return false
}
return true
}
export const image_url = async (src, fallback = DEFAULT_IMAGE_URL) => {
let safeSrc = src
@ -66,7 +79,7 @@ export const gallery = async (
const productConfig: any = read(PRODUCT_CONFIG(product), "json")
if (!productConfig) {
logger.warn(`item gallery : item ${product} config not found !`)
return
return []
}
const mediaPath = `${root}/${product}/${assetPath}/`
if (!exists(mediaPath)) {
@ -86,9 +99,23 @@ export const gallery = async (
if (!galleryFiles) {
logger.warn(`ProductGallery : Product ${product} media files not found ! ${mediaPath}`)
return
return []
}
const assetUrl = (filePath) => {
return sanitizeUri(ITEM_ASSET_URL(
{
assetPath,
filePath,
ITEM_REL: product,
...profile.variables
}
))
}
galleryFiles = await pMap(galleryFiles, async (f) => (await default_filter(assetUrl(f))) ? f : null, { concurrency: 5 })
galleryFiles = galleryFiles.filter((f) => f !== null)
galleryFiles = default_sort(galleryFiles)
return await pMap(galleryFiles, async (file: string) => {
const parts = path.parse(file)
const filePath = path.join(mediaPath, file)
@ -123,21 +150,11 @@ export const gallery = async (
delete imageMeta.exif.icc
delete imageMeta.exif.xmp
delete imageMeta.exif.iptc
const assetUrl = (filePath) => {
return sanitizeUri(ITEM_ASSET_URL(
{
assetPath,
filePath,
ITEM_REL: product,
...profile.variables
}
))
}
const src = await image_url(assetUrl(file))
const ret: GalleryImage =
{
name: path.parse(file).name,
url: await image_url(assetUrl(file)),
src: await image_url(assetUrl(file)),
src: src,
meta: {
format: imageMeta.format,
width: imageMeta.width,
@ -187,7 +204,7 @@ export const toJsonLd = async (images: GalleryImage[], lang: string, contentUrl:
"@context": "https://schema.org",
"@type": "ImageObject",
"inLanguage": lang,
"contentUrl": contentUrl || image.src,
"contentUrl": contentUrl || image.src,
"url": contentUrl || image.src,
"name": image.title || image.name,
"description": image.description || image.alt || "",

View File

@ -175,7 +175,7 @@ const onItem = async (item: IStoreItem, ctx: ILoaderContextEx) => {
let data: IComponentConfigEx = item.data
const itemRel = data.rel
const itemRelMin = data.rel.replace('products/', '')
const itemRelMin = itemRel.replace('products/', '')
const itemDir = PRODUCT_DIR(itemRel)
const default_profile = env(itemRel)
@ -225,7 +225,7 @@ const onItem = async (item: IStoreItem, ctx: ILoaderContextEx) => {
data = {
...data,
...default_profile.variables,
product_rel_min: itemRelMin.replace('products/', ''),
product_rel_min: itemRelMin,
}
data = resolveConfig(data as Record<string, string>) as IComponentConfigEx
item.data = data
@ -236,12 +236,6 @@ const onItem = async (item: IStoreItem, ctx: ILoaderContextEx) => {
data.cad = await cad(item, ctx)
data.assets.renderings = await gallery('renderings', data.rel) as []
data.assets.renderings.length && (data.thumbnail =
{
alt: data.assets.renderings[0].alt,
url: data.assets.renderings[0].url,
src: data.assets.renderings[0].url
})
data.assets.gallery = await gallery('media/gallery', data.rel) as []
data.image = data.assets.renderings[0] || {}
data.assets.showcase = await gallery('media/showcase', data.rel) as []

View File

@ -1 +0,0 @@
TEST,TEST
1 TEST TEST

View File

@ -1,10 +0,0 @@
{
"glossaryId": "94f02b66-2ee8-4119-a8d7-e0a11dd8992d",
"name": "OSR-en-pt",
"ready": true,
"sourceLang": "en",
"targetLang": "pt",
"creationTime": "2025-03-11T22:17:00.006Z",
"entryCount": 1,
"hash": "zDrlayXO43sB98wNoqof0g=="
}