generated from polymech/site-template
model:product-slim
This commit is contained in:
parent
ce59c9a76c
commit
18101ebc1e
File diff suppressed because one or more lines are too long
@ -1210,5 +1210,257 @@
|
||||
"https://www.amazon.de/-/en/3M-8812-Particulate-Respirator-10-Pack/dp/B07FYV4CQ7": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743178707788
|
||||
},
|
||||
"https://www.apa-injection.com/en/our-idea-of-plastic-injection/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743178997109
|
||||
},
|
||||
"https://firstmold.com/tips/automotive-injection-molding/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743178997649
|
||||
},
|
||||
"https://www.onearmy.earth/news/educational-workshops": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743178997903
|
||||
},
|
||||
"https://nelsonmillergroup.com/resources/plastic-injection-molding-e-book/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743178998482
|
||||
},
|
||||
"https://www.hudsonbooksellers.com/book/9781569906897": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743178999445
|
||||
},
|
||||
"https://www.energy.gov/eere/bioenergy/articles/transitioning-sustainable-circular-economy-plastics-workshop-report-2023": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179000786
|
||||
},
|
||||
"https://parlormultimedia.com/writingspaces/wp-content/uploads/2024/07/technical.pdf": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179001375
|
||||
},
|
||||
"https://www.weezandmerl.com/product-page/advanced-plastic-recycling-workshop": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179003000
|
||||
},
|
||||
"https://www.themillsfabrica.com/events/plastic-circularity-recycling-workshop/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179004604
|
||||
},
|
||||
"https://www.qitech.de/en/industries": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179082766
|
||||
},
|
||||
"https://www.qitech.de/en/ind/academy-area/filament-extruder-comparision": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179083280
|
||||
},
|
||||
"https://youtu.be/IcmKFDxsUgA": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179083584
|
||||
},
|
||||
"https://example-secondhand-stores.com": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179258790
|
||||
},
|
||||
"https://laser-cutting-service.com": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179259472
|
||||
},
|
||||
"https://patreon.com": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179259754
|
||||
},
|
||||
"https://example-video-link.com": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179259822
|
||||
},
|
||||
"https://hackaday.com/2023/09/23/getting-shredded-plastic-and-legs/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179376981
|
||||
},
|
||||
"https://apw.org.nz/wp-content/uploads/2015/06/HomeBrewRevolution_Carson.pdf": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179378886
|
||||
},
|
||||
"https://scibizsw.com/20_THE%20OFFICIAL%20RASPBERRY%20PI%20PROJECTS%20BOOK%20v3.pdf": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179379522
|
||||
},
|
||||
"https://www.youtube.com/watch?v=PfF3cljHbRw": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179379715
|
||||
},
|
||||
"https://example.com/sheetpress": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179379944
|
||||
},
|
||||
"https://example.com/cartridge-heaters": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179380123
|
||||
},
|
||||
"https://example.com/thermocouples": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179380309
|
||||
},
|
||||
"https://example.com/pneumatic-valve": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179380485
|
||||
},
|
||||
"https://www.raspberrypi.com/": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179380548
|
||||
},
|
||||
"https://www.analog.com/max31855": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179380866
|
||||
},
|
||||
"https://example.com/ssr": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179381047
|
||||
},
|
||||
"https://www.st.com/en/imaging-and-photonics-solutions/vl6180.html": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179381203
|
||||
},
|
||||
"https://www.arduino.cc/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179381554
|
||||
},
|
||||
"https://nodejs.org/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179381826
|
||||
},
|
||||
"https://www.xrite.com/learning-color-education/using-our-solutions/automate-offset-press": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179498221
|
||||
},
|
||||
"https://www.tappi.org/product_pull/04/aug/advanced-ex-press-sheet-management-for-improved-quality-and/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179499733
|
||||
},
|
||||
"https://www.piworld.com/article/sheetfed-offset-printing-press-automation-advancements/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179503134
|
||||
},
|
||||
"https://www.industrialautomation.us/industries/printing/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179504942
|
||||
},
|
||||
"https://whattheythink.com/articles/111446-product-spotlight-canon-press-automation-modulesoptimizing-simplifying-printing/": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179505153
|
||||
},
|
||||
"https://www.packagingimpressions.com/article/automation-in-offset-simplifying-production-and-increasing-profitability/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179508704
|
||||
},
|
||||
"https://www.emerson.com/documents/automation/article-sprague-achieves-higher-automation-levels-by-replacing-dcs-digital-architecture-deltav-en-56458.pdf": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179509350
|
||||
},
|
||||
"https://ippta.co/wp-content/uploads/2021/01/IPPTA-71-29-35-Shreyans-Doubled-its.pdf": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179509534
|
||||
},
|
||||
"https://www.solidworks.com": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179614478
|
||||
},
|
||||
"https://example.com/REX-100": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179615232
|
||||
},
|
||||
"https://example.com/wiring-tutorials": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179615885
|
||||
},
|
||||
"https://www.aliexpress.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179657179
|
||||
},
|
||||
"https://chisel.tech/": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179657272
|
||||
},
|
||||
"https://www.solidworks.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179658653
|
||||
},
|
||||
"https://lasercut.ru/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179659428
|
||||
},
|
||||
"https://leroymerlin.ru/": {
|
||||
"isValid": false,
|
||||
"timestamp": 1743179669940
|
||||
},
|
||||
"https://www.tme.eu/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179670711
|
||||
},
|
||||
"https://www.instructables.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179670809
|
||||
},
|
||||
"https://www.youtube.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179670967
|
||||
},
|
||||
"https://reprap.org/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179671632
|
||||
},
|
||||
"https://www.cncmachines.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179722458
|
||||
},
|
||||
"https://www.vectric.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179722580
|
||||
},
|
||||
"https://www.machsupport.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179724248
|
||||
},
|
||||
"https://www.boschtools.com/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179725191
|
||||
},
|
||||
"https://www.trendhunter.com/trends/bathroom-toilet-stool": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179851853
|
||||
},
|
||||
"https://www.harborcitysupply.com/blog/accessories-in-public-restrooms-ada-guidelines/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179852650
|
||||
},
|
||||
"https://hendriksenpublishing.com/2020/05/22/patents-pending-aesthetic-toilet-accessory-that-helps-you-squat-while-you-sit-or-pee/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179853451
|
||||
},
|
||||
"https://medschenker.com/toilet-back-support-movable-position/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179853915
|
||||
},
|
||||
"https://www.machinedesign.com/3d-printing-cad/article/21837356/from-cad-to-cnc-in-3-steps": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179854336
|
||||
},
|
||||
"https://www.ikea.com/ph/en/this-is-ikea/about-us/the-story-of-ikea-flatpacks-puba710ccb0/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179855423
|
||||
},
|
||||
"https://www.hajim.rochester.edu/senior-design-day/commode-for-neurogenic-bowel/": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179861971
|
||||
},
|
||||
"https://www.youtube.com/watch?v=n2r79ZAMgIE": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179862101
|
||||
},
|
||||
"https://www.youtube.com/watch?v=Wx8238bGSCY": {
|
||||
"isValid": true,
|
||||
"timestamp": 1743179862227
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Return a list of references (only with links), as Markdown, grouped : Articles, Books, Papers, Youtube, Opensource Designs, ... Dont comment !\n\nText to process:\nTransform plastic waste into charming Christmas ornaments for decoration or gift embellishment.\n\n**Required Materials:**\n\n- Bottle caps\n- Panini press with a flat surface\n- Silicone gloves\n- Baking paper\n- Eye protection\n- Respiratory mask\n- Fret saw (manual or electrical)\n- Sharp knife or razor blade\n- Cookie cutters or paper stencil\n\n\nUser Location: Luneburg, Germany\n\n### Bottle Cap Sorting Guide\n\n1. **Identify Plastic Type** \n Sort bottle caps by type: either HDPE or PP. Check for the recycling symbol inside the cap: '2' indicates HDPE and '5' indicates PP.\n\n2. **Physical Identification** \n If not labeled, determine plastic type by feel. HDPE caps are more flexible, PP caps are rigid. Typically, milk jug caps are HDPE; soda bottle caps may be PP. \n\n3. **Contamination Precaution** \n When uncertain about a cap's type, discard it to prevent possible contamination of the batch.\n\n### Cleaning and Preparing Caps\n\n1. **Wash Caps**: Soak caps in a sink and scrub with a brush, or for larger quantities, place them in a laundry bag and use a short cycle in the washing machine. Ensure the caps are thoroughly dried before proceeding.\n\n2. **Color Selection**: Decide on color combinations for your ornaments. While the example uses red, white, and green, choose based on your available colors and desired aesthetic.\n\nPlug in your panini press and let it heat up. Use a flat surface model for an even plastic sheet. Once hot, place a baking sheet on the press. Teflon sheets are recommended for durability.\n\nPlace bottle caps on the press; orientation doesn't matter. Cover them with a second baking sheet and close the press.\n\nTo aid the melting process, place a heavy object, such as bricks or books, on top of the press.\n\nAfter melting the bottle caps, you can add additional layers as in Step 2. The desired thickness of your ornaments will determine the number of layers. For a plastic sheet approximately 0.12 to 0.16 inches (3 to 4 mm) thick, melt 2 to 4 layers of bottle caps, depending on their size.\n\nYou should now have a layer of melted bottle caps. You may use the sheet immediately or create a batik design. To do so, wear silicone gloves, roll the warm plastic into a sausage shape, and twist it. Let your creativity guide you—pull, fold, and twist the plastic until the desired pattern is achieved. If the plastic hardens, simply reheat it in the press to make it moldable again.\n\nAt this point, you have a lump of plastic that needs to be melted again to form a flat sheet.\n\nPlace the plastic piece inside the panini press and heat it until it softens. Once pliable, apply pressure to the press. To enhance stretching, consider gently sitting on the press, ensuring you avoid burns. \n\nAlternatively, use a rolling pin after removing the plastic, though maintaining contact with the heat source typically yields better results.\n\nOpen the press periodically to check if the sheet has reached the desired thickness. Once satisfied, turn off the press and allow the sheet to cool with a weight on top to prevent deformation.\n\nOnce the sheet has cooled, you can begin designing. Use a pen suitable for plastic to sketch your ornaments. Cookie cutters or paper stencils can serve as helpful guides.\n\nConsider the sawing process when selecting a design; intricate patterns are harder to cut. Starting with simple designs and gradually moving to complex ones is advisable.\n\n## Cutting Instructions\n\nFor this step, use a fretsaw, which can be manual or electric. An electric saw simplifies the process, but a manual saw is also effective with some additional patience.\n\nGuide the saw along the lines drawn on the plastic sheet to complete your Christmas ornament.\n\nTo clean the edges of your ornament, use a sharp knife or razor blade, as it is more effective than sandpaper. Ensure all small plastic pieces are collected during this process for reuse. They can be melted down again in future projects.\n\nTo complete your ornament, drill a small hole at the top to accommodate your string, considering its thickness. \n\nWe used strings collected over the years. \n\nYour ornaments are now ready. Congratulations on your effort to reduce waste during Christmas.\n\n### Handmade Holiday Ornaments\n\nThis step is optional. By gifting your handmade ornaments to friends or family, you demonstrate that new items are not necessary for Christmas decorations. Creating ornaments from bottle caps utilizes materials that might otherwise be discarded. This approach results in unique, handmade decorations. \n\nMerry Christmas,\nMaria & Nike from IN MOCEAN"
|
||||
"content": "Return a list of references (only with links), as Markdown, grouped : Articles, Books, Papers, Youtube, Opensource Designs, ... Dont comment !\n\nText to process:\nIn this guide, you will create alphabet magnets using PLA scraps from 3D prints. This process requires an oven and reaches temperatures of 400°F (204°C), so safety gear is necessary.\n\n\nUser Location: Conway, United States of America (the)\n\n**Materials Required:**\n\n- Small PLA scraps\n- Clippers\n- Safety glasses\n- Oven mitts\n- Silicone mold (up to 450°F / 232°C)\n- Cookie sheet\n- Magnetic tape\n- X-acto knife\n- Sanding paper\n- Oven\n\nBefore filling the mold, place it on a cookie sheet to prevent spills. Wear safety glasses, and use clippers to cut the PLA scraps so they fit within the mold, as the scraps may scatter when clipped. Ensure the mold is fully filled.\n\n### Plastic Molding How-To\n\n1. After filling the mold with plastic, place the cookie sheet in the oven.\n2. Set the oven to 400°F (204°C) and bake.\n3. Monitor the plastic as it melts, which may take approximately 30 minutes depending on oven efficiency.\n4. Once melted, use oven mitts to remove the cookie sheet from the oven.\n5. Place the sheet on a heat-safe surface like the stovetop.\n6. Allow it to cool before proceeding to the next step.\n\nThe mold might not be sufficiently filled. Add more material, melt it, and repeat this process until the mold is adequately filled.\n\n### Tutorial Instructions\n\n1. Once the mold has cooled completely, remove the letters.\n2. Sand the backs of the letters until flat, preparing for magnet attachment.\n3. Align the letters on the adhesive side of magnetic tape.\n4. Use an Exacto knife to trim the excess tape."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
|
||||
BIN
src/model/data/_1_.jpg
Normal file
BIN
src/model/data/_1_.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
BIN
src/model/data/_3_.jpg
Normal file
BIN
src/model/data/_3_.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
src/model/data/_4_.png
Normal file
BIN
src/model/data/_4_.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 593 KiB |
BIN
src/model/data/_5_.png
Normal file
BIN
src/model/data/_5_.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 252 KiB |
6
src/model/data/data.html
Normal file
6
src/model/data/data.html
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
<div><p>Our semi-automatic injection molding machine is ideal for manufacturing lightweight parts with precision and efficiency, perfect for entrepreneurs, small workshops and educational projects. Its compact vertical design offers innovative recycling solutions in small spaces.</p></div>
|
||||
|
||||
|
||||
|
||||
21
src/model/data/data.json
Normal file
21
src/model/data/data.json
Normal file
File diff suppressed because one or more lines are too long
227
src/model/product.ts
Normal file
227
src/model/product.ts
Normal file
@ -0,0 +1,227 @@
|
||||
import * as path from 'path'
|
||||
import { findUp } from 'find-up'
|
||||
|
||||
import pMap from 'p-map'
|
||||
import { sanitizeFilename } from "@polymech/fs/utils"
|
||||
import { execFileSync, execFile } from "child_process";
|
||||
import { sync as read } from '@polymech/fs/read'
|
||||
import { sync as exists } from '@polymech/fs/exists'
|
||||
import { sync as mkdir } from '@polymech/fs/dir'
|
||||
import { sync as rm } from '@polymech/fs/remove'
|
||||
import { sync as write } from '@polymech/fs/write'
|
||||
import type { Loader, LoaderContext } from 'astro/loaders'
|
||||
import { resolveVariables } from "@polymech/commons/variables"
|
||||
|
||||
import { env, logger } from '@/base/index.js'
|
||||
import { download } from './download.js'
|
||||
import { default_image } from 'config/config.js'
|
||||
|
||||
import { applyFilters, default_filters_plain, FilterFunction } from './filters.js'
|
||||
import { TemplateContext, buildPrompt, LLMConfig, createTemplates } from '@/base/kbot-templates.js'
|
||||
import { template_filter } from '@/base/kbot.js'
|
||||
|
||||
export interface IProduct {
|
||||
title: string
|
||||
price: string
|
||||
storeName: string
|
||||
storeLink: string
|
||||
description: string
|
||||
features: string
|
||||
options: string
|
||||
authorImage: string
|
||||
images: string[]
|
||||
content: string | null
|
||||
url: string
|
||||
prefix: string
|
||||
slug: string
|
||||
files?: any[]
|
||||
}
|
||||
|
||||
export const ITEM_TYPE = 'product'
|
||||
|
||||
export const PRODUCT_ROOT = () => path.join(process.cwd(), 'src/content/products')
|
||||
export const PRODUCT_GLOB = () => 'src/content/products/**/*.mdx'
|
||||
export const PRODUCT_MIGRATION = () => path.join(process.cwd(), 'src/model/data/data.json')
|
||||
export const PRODUCT_FILTER_LLM = true
|
||||
|
||||
export const item_path = (item: IProduct) => `${PRODUCT_ROOT()}/${item.slug}`
|
||||
export const asset_local_abs = async (item: IProduct, imageUrl: string) => {
|
||||
const sanitizedFilename = sanitizeFilename(path.basename(imageUrl))
|
||||
const asset_path = path.join(PRODUCT_ROOT(), item.slug, sanitizedFilename)
|
||||
if (exists(asset_path)) {
|
||||
return asset_path
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const downloadFiles = async (dst: string, product: IProduct) => {
|
||||
const asset_root = path.join(PRODUCT_ROOT(), product.slug)
|
||||
return await pMap(product.images, async (imageUrl) => {
|
||||
const sanitizedFilename = sanitizeFilename(path.basename(imageUrl)).toLowerCase()
|
||||
const asset_path = path.join(PRODUCT_ROOT(), product.slug, sanitizedFilename)
|
||||
if (!exists(asset_path)) {
|
||||
try {
|
||||
await download(imageUrl, asset_path)
|
||||
} catch (e) {
|
||||
logger.error('error download product image', e)
|
||||
}
|
||||
}
|
||||
}, { concurrency: 1 })
|
||||
}
|
||||
|
||||
export const asset_local_rel = async (item: IProduct, imageUrl: string) => {
|
||||
const sanitizedFilename = sanitizeFilename(path.basename(imageUrl)).toLowerCase()
|
||||
const asset_path = path.join(PRODUCT_ROOT(), item.slug, sanitizedFilename)
|
||||
if (exists(asset_path)) {
|
||||
return `/resources/products/${item.slug}/${sanitizedFilename}`
|
||||
} else {
|
||||
await download(imageUrl, asset_path)
|
||||
}
|
||||
return default_image().src
|
||||
}
|
||||
|
||||
export const raw = async () => {
|
||||
const src = PRODUCT_MIGRATION()
|
||||
const data = read(src, 'json') as any
|
||||
const products = [data] // Since we're working with a single product for now
|
||||
return products
|
||||
}
|
||||
|
||||
export const defaults = async (data: any, cwd: string, root: string) => {
|
||||
let defaultsJSON = await findUp('defaults.json', {
|
||||
stopAt: root,
|
||||
cwd: cwd
|
||||
})
|
||||
try {
|
||||
if (defaultsJSON) {
|
||||
data = {
|
||||
...read(defaultsJSON, 'json') as any,
|
||||
...data,
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const commons = async (text: string): Promise<string> => {
|
||||
return await template_filter(text, 'simple', TemplateContext.COMMONS)
|
||||
}
|
||||
|
||||
const content = async (str: string, filters: FilterFunction[] = default_filters_plain) => await applyFilters(str, filters)
|
||||
|
||||
const to_mdx = async (item: IProduct) => {
|
||||
const itemDir = item_path(item)
|
||||
|
||||
// Create index.mdx with all content
|
||||
const mdxContent = [
|
||||
'---',
|
||||
`title: ${item.title}`,
|
||||
`price: ${item.price}`,
|
||||
`storeName: ${item.storeName}`,
|
||||
`storeLink: ${item.storeLink}`,
|
||||
`url: ${item.url}`,
|
||||
`prefix: ${item.prefix}`,
|
||||
'---',
|
||||
'',
|
||||
`import { Image } from 'astro:assets'`,
|
||||
'',
|
||||
`# ${item.title}`,
|
||||
'',
|
||||
...item.images.map((img, index) =>
|
||||
`<Image src={import('./${sanitizeFilename(path.basename(img))}')} alt="${item.title} - Image ${index + 1}" />`
|
||||
),
|
||||
'',
|
||||
item.description,
|
||||
'',
|
||||
'## Features',
|
||||
'',
|
||||
item.features,
|
||||
'',
|
||||
'## Options',
|
||||
'',
|
||||
item.options
|
||||
].filter(Boolean).join('\n')
|
||||
write(path.join(itemDir, 'index.mdx'), mdxContent)
|
||||
}
|
||||
|
||||
const complete = async (item: IProduct) => {
|
||||
// commons: language, tone, bullshit filter, and a piece of love, just a bit, at least :)
|
||||
if (PRODUCT_FILTER_LLM) {
|
||||
item.description = await commons(item.description || '')
|
||||
}
|
||||
|
||||
// default pass, links, words, formatting, ...
|
||||
item.description = await content(item.description)
|
||||
item.features = await content(item.features)
|
||||
item.options = await content(item.options)
|
||||
|
||||
await to_mdx(item)
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
const onStoreItem = async (store: any, ctx: LoaderContext) => {
|
||||
const item = store.data.item as IProduct
|
||||
const processedImages = await pMap(item.images, async (imageUrl) => {
|
||||
return {
|
||||
url: imageUrl,
|
||||
src: await asset_local_rel(item, imageUrl) || default_image().src,
|
||||
alt: path.basename(imageUrl)
|
||||
}
|
||||
}, { concurrency: 1 })
|
||||
|
||||
item.images = processedImages.map(img => img.url)
|
||||
item.files = await downloadFiles(item.slug, item)
|
||||
await complete(item)
|
||||
const configPath = path.join(item_path(item), 'config.json')
|
||||
write(configPath, JSON.stringify(item, null, 2))
|
||||
logger.info(`Stored item ${item.slug} at ${configPath}`)
|
||||
return item
|
||||
}
|
||||
|
||||
export function loader(): Loader {
|
||||
const load = async ({
|
||||
config,
|
||||
logger,
|
||||
watcher,
|
||||
parseData,
|
||||
store,
|
||||
generateDigest }: LoaderContext) => {
|
||||
|
||||
store.clear()
|
||||
let items = await raw()
|
||||
for (const item of items) {
|
||||
const id = item.slug
|
||||
const data = {
|
||||
slug: item.slug,
|
||||
id,
|
||||
title: item.title,
|
||||
type: ITEM_TYPE,
|
||||
components: [],
|
||||
item
|
||||
}
|
||||
const storeItem = {
|
||||
digest: await generateDigest(data),
|
||||
filePath: id,
|
||||
id: `${item.slug}`,
|
||||
data: data
|
||||
}
|
||||
|
||||
await onStoreItem(storeItem, {
|
||||
logger,
|
||||
watcher,
|
||||
parseData,
|
||||
store,
|
||||
generateDigest
|
||||
} as any)
|
||||
|
||||
storeItem.data['config'] = JSON.stringify(storeItem.data, null, 2)
|
||||
store.set(storeItem)
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: `astro:store:${ITEM_TYPE}`,
|
||||
load
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user