diff --git a/src/config/cli.ts b/src/config/cli.ts new file mode 100644 index 0000000..5dafcd2 --- /dev/null +++ b/src/config/cli.ts @@ -0,0 +1,9 @@ +import cli from 'yargs' +import { hideBin } from 'yargs/helpers' +import { } from './network.js' + +const argv = cli(hideBin(process.argv)).parse() + +export const options = () => { + console.log('Options: ', argv) +} \ No newline at end of file diff --git a/src/config/config.json b/src/config/config.json new file mode 100644 index 0000000..e284ffc --- /dev/null +++ b/src/config/config.json @@ -0,0 +1,88 @@ +{ + "site": { + "title": "Polymech", + "base_url": "https://polymech.io/", + "description" : "", + "base_path": "/", + "trailing_slash": false, + "favicon": "/images/favicon.png", + "logo": "/images/logo.png", + "logo_darkmode": "/images/logo-darkmode.png", + "logo_width": "150", + "logo_height": "33", + "logo_text": "Astrofront", + "image": { + "default": "/images/default-image.png", + "error": "/images/error-image.png", + "alt": "Astrofront", + "src": "https://assets.osr-plastic.org/machines//assets/newsletter/common/products/extruders/overview-3.jpg" + } + }, + "footer_left": [ + { + "href": "/infopages/privacy", + "text": "Privacy" + }, + { + "href": "/infopages/contact", + "text": "Contact" + } , + { + "href": "/newsletter/newsletter_2024_09_en-hugo-release.html", + "text": "Newsletter" + } + ], + "footer_right": [ + + ], + "settings": { + "search": true, + "account": true, + "sticky_header": true, + "theme_switcher": true, + "default_theme": "system" + }, + "params": { + "contact_form_action": "#", + "copyright": "Designed And Developed by [Themefisher](https://themefisher.com/)" + }, + "navigation_button": { + "enable": true, + "label": "Get Started", + "link": "https://github.com/themefisher/astrofront" + }, + "ecommerce": { + "brand": "Polymech", + "currencySymbol": "", + "currencyCode": "EUR" + }, + "metadata": { + "country": "Spain", + "city": "Barcelona", + "author": "Polymech", + "author_bio": "I am in, if its true", + "author_url": "https://polymech.io/", + "image": "/images/og-image.png", + "description": "Polymech is a plastic prototyping company that offers product design services.", + "keywords": "Plastic, Prototyping, Product Design, Opensource" + }, + "shopify": { + "currencySymbol": "", + "currencyCode": "EUR", + "collections": { + "hero_slider": "hidden-homepage-carousel", + "featured_products": "featured-products" + } + }, + "pages":{ + "home":{ + "hero": "https://assets.osr-plastic.org/machines//assets/newsletter/common/products/extruders/overview-3.jpg", + "blog":{ + "store": "resources" + } + } + }, + "tracking": { + "googleAnalytics": "G-RW6Q6EG3J0" + } +} diff --git a/src/config/config.ts b/src/config/config.ts new file mode 100644 index 0000000..f4851e9 --- /dev/null +++ b/src/config/config.ts @@ -0,0 +1,170 @@ +import * as path from 'path' +import { IMAGE_PRESET, E_BROADBAND_SPEED } from "./network.js" +import { resolve, template } from '@polymech/commons' +import { sync as read } from '@polymech/fs/read' +import { sanitizeUri } from 'micromark-util-sanitize-uri' + +export const OSR_ROOT = () => path.resolve(resolve("${OSR_ROOT}")) + +export const LOGGING_NAMESPACE = 'polymech-site' +export const TRANSLATE_CONTENT = true +export const LANGUAGES = ['en', 'ar', 'de', 'ja', 'es', 'zh', 'fr'] +export const LANGUAGES_PROD = ['en', 'es', 'ar', 'de', 'ja', 'zh', 'fr', 'nl', 'it', 'pt'] +export const isRTL = (lang) => lang === 'ar' + +// i18n constants +export const I18N_STORE = (root, lang) => `${root}/i18n-store/store-${lang}.json` +export const I18N_SOURCE_LANGUAGE = 'en' +export const I18N_CACHE = true +export const I18N_ASSET_PATH = "${SRC_DIR}/${SRC_NAME}-${DST_LANG}${SRC_EXT}" + +// Products +export const PRODUCT_ROOT = () => path.resolve(resolve("${OSR_ROOT}/products")) +export const PRODUCT_BRANCHES = read(path.join(PRODUCT_ROOT(), 'config/machines.json'), 'json') +export const PRODUCT_GLOB = '**/config.json' + +// Product compiler +export const PRODUCT_CONFIG = (product) => + path.resolve(resolve(`${PRODUCT_ROOT()}/${product}/config.json`, false, + { + product + })) +export const PRODUCT_DIR = (product) => path.resolve(resolve(`${PRODUCT_ROOT()}/${product}`)) +export const PRODUCT_HUGO_TEMPLATE = './osr/hugo/root.html' +export const PRODUCTS_TARGET_SRC = './src/content/en/retail' +export const PRODUCTS_TARGET = (lang) => `./content/${lang}/products` + +// Product assets + +export const ASSETS_LOCAL = false +export const ASSETS_GLOB = '*.+(JPG|jpg|jpeg|png|PNG|gif)' +// OSRL - Language +export const IS_DEV = true +export const OSRL_ENV = 'astro-release' +export const OSRL_ENV_DEV = 'astro-debug' +export const OSRL_ENVIRONMENT = IS_DEV ? OSRL_ENV_DEV : OSRL_ENV +export const OSRL_MODULE_NAME = 'polymech.io' +export const OSRL_PRODUCT_PROFILE = './src/config/profile.json' +export const OSRL_LANG_FLAVOR = 'osr' + +// Products +export const ENABLED_PRODUCTS = "${OSR_ROOT}/products/config/machines.json" +export const PRODUCT_SPECS = (rel) => `${PRODUCT_ROOT()}/${rel}/specs.xlsx` + +// Tasks +export const TASK_CONFIG_LOG_DIRECTORY = './config/' + +// Task: compile:content +export const TASK_COMPILE_CONTENT = true +export const TASK_COMPILE_CONTENT_CACHE = false + +// Task - Logging +export const TASK_LOG_DIRECTORY = './logs/' + +// Task - Retail Config +export const REGISTER_PRODUCT_TASKS = true +export const RETAIL_PRODUCT_BRANCH = 'site' +export const PROJECTS_BRANCH = 'projects' +export const RETAIL_COMPILE_CACHE = false +export const RETAIL_MEDIA_CACHE = true +export const RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS = 'info' + +export const ConvertProductMedia = true +export const TranslateProductAssets = false +export const PopulateProductDefaults = true + +// CAD +export const CAD_MAIN_MATCH = (product) => `${product}/cad*/*Global*.+(SLDASM)` +export const CAD_CAM_MAIN_MATCH = (product) => `${product}/cad*/*-CNC*.+(SLDASM)` + +export const CAD_CACHE = true +export const CAD_EXPORT_CONFIGURATIONS = false +export const CAD_EXPORT_SUB_COMPONENTS = true +export const CAD_MODEL_FILE_PATH = (SOURCE, CONFIGURATION = '') => + SOURCE.replace('.json', `${CONFIGURATION ? '-' + CONFIGURATION : ''}.tree.json`) +export const CAD_DEFAULT_CONFIGURATION = 'Default' +export const CAD_RENDERER = 'solidworks' +export const CAD_RENDERER_VIEW = 'Render' +export const CAD_RENDERER_QUALITY = 1 +export const CAD_EXTENSIONS = ['.STEP', '.html'] +export const CAD_MODEL_EXT = '.tree.json' + +export const CAD_URL = (file: string, variables: Record) => + sanitizeUri(template("${OSR_MACHINES_ASSETS_URL}/${file}", { file, ...variables })) + +export const ASSET_URL = (file: string, variables: Record) => + sanitizeUri(template("${OSR_MACHINES_ASSETS_URL}/products/${product_rel_min}/${file}", { file, ...variables })) + +export const ITEM_ASSET_URL = (variables: Record) => + template("${OSR_MACHINES_ASSETS_URL}/${ITEM_REL}/${assetPath}/${filePath}", variables) + + +//back compat - osr-cad +export const parseBoolean = (value: string): boolean => { + return value === '1' || value.toLowerCase() === 'true'; +} +///////////////////////////////////////////// +// +// Rendering +export const SHOW_DESCRIPTION = false +export const SHOW_LICENSE = true +export const SHOW_RENDERINGS = true + +export const SHOW_TABS = false +export const SHOW_GALLERY = true +export const SHOW_FILES = true +export const SHOW_SPECS = true +export const SHOW_CHECKOUT = true +export const SHOW_CONTACT = true +export const SHOW_3D_PREVIEW = true +export const SHOW_RESOURCES = true +export const SHOW_DEBUG = false +export const SHOW_SAMPLES = true +export const SHOW_README = false +export const SHOW_RELATED = true + +///////////////////////////////////////////// +// +// Plugins + +// RSS +export const RSS_CONFIG = +{ + title: 'Polymech RSS Feed', + description: '', +} + +///////////////////////////////////////////// +// +// Defaults +export const DEFAULT_IMAGE_URL = 'https://picsum.photos/640/640' +export const default_image = () => { + return { + alt: 'none', + src: DEFAULT_IMAGE_URL + } +} +export const DEFAULT_LICENSE = `CERN Open Source Hardware License` +export const DEFAULT_CONTACT = `sales@plastic-hub.com` +///////////////////////////////////////////// +// +// Optimization + +export const O_IMAGE = IMAGE_PRESET[E_BROADBAND_SPEED.MEDIUM] +export const IMAGE_SETTINGS = +{ + GALLERY: { + SHOW_TITLE: true, + SHOW_DESCRIPTION: false, + SIZES_THUMB: O_IMAGE.sizes_thumbs, + SIZES_LARGE: O_IMAGE.sizes_large, + SIZES_REGULAR: O_IMAGE.sizes_medium + }, + LIGHTBOX: { + SHOW_TITLE: true, + SHOW_DESCRIPTION: true, + SIZES_THUMB: O_IMAGE.sizes_thumbs, + SIZES_LARGE: O_IMAGE.sizes_large, + SIZES_REGULAR: O_IMAGE.sizes_medium + } +} \ No newline at end of file diff --git a/src/config/menu.json b/src/config/menu.json new file mode 100644 index 0000000..2214f16 --- /dev/null +++ b/src/config/menu.json @@ -0,0 +1,59 @@ +{ + "main": [ + { + "name": "Home", + "url": "/" + }, + { + "name": "Products", + "url": "/products" + }, + { + "name": "Pages", + "url": "", + "hasChildren": true, + "children": [ + { + "name": "About", + "url": "/about" + }, + { + "name": "Contact", + "url": "/contact" + }, + { + "name": "404 Page", + "url": "/404" + } + ] + }, + { + "name": "Contact", + "url": "/contact" + } + ], + "footer": [ + { + "name": "About", + "url": "/about" + }, + { + "name": "Products", + "url": "/products" + }, + { + "name": "Contact", + "url": "/contact" + } + ], + "footerCopyright": [ + { + "name": "Privacy & Policy", + "url": "/privacy-policy" + }, + { + "name": "Terms of Service", + "url": "/terms-services" + } + ] +} diff --git a/src/config/navigation.ts b/src/config/navigation.ts new file mode 100644 index 0000000..bcac035 --- /dev/null +++ b/src/config/navigation.ts @@ -0,0 +1,41 @@ +import { translate } from '../base/i18n.js' +import { I18N_SOURCE_LANGUAGE } from 'config/config.js' +import config from "./config.json" with { type: "json" } +import pMap from 'p-map' + +export const items = async (opts: { locale: string }) => { + const _T = async (text: string) => await translate(text, I18N_SOURCE_LANGUAGE, opts.locale) + return [ + { + "href": `/${opts.locale}`, + "title": _T("Home"), + "ariaLabel": "Home", + "class": "hover:text-orange-600" + }, + { + "href": `/${opts.locale}/infopages/resources`, + "title": _T("Resources"), + "ariaLabel": "Resources", + "class": "hover:text-orange-600" + } + ] +} +const isAbsoluteUrl = (url: string): boolean => /^[a-zA-Z]+:/.test(url); + +const createFooterLinks = async (items: any[], locale: string) => { + const _T = async (text: string) => await translate(text, I18N_SOURCE_LANGUAGE, locale); + + return await pMap(items, async (item) => { + const translatedText = await _T(item.text); // Single translation call + + return { + "href": isAbsoluteUrl(item.href) ? item.href : `/${locale}${item.href}`, + "title": translatedText, // Use cached translation + "ariaLabel": translatedText, // Use cached translation + "class": "hover:text-orange-600" + }; + }); +}; + +export const footer_left = (locale: string) => createFooterLinks(config.footer_left, locale); +export const footer_right = (locale: string) => createFooterLinks(config.footer_right, locale); diff --git a/src/config/network.ts b/src/config/network.ts new file mode 100644 index 0000000..20aa5e6 --- /dev/null +++ b/src/config/network.ts @@ -0,0 +1,49 @@ +import { z } from "zod" +///////////////////////////////////////////// +// +// Optimizations + +// Image optimization (imagetools breakpoints & min widths) + +export enum E_BROADBAND_SPEED { + SLOW = "slow", + MEDIUM = "medium", + FAST = "fast", +} + +const imageConfigSchema = z.object({ + sizes_medium: z.string(), + sizes_thumbs: z.string(), + sizes_large: z.string(), +}) +const imagesSchema = z.object({ + [E_BROADBAND_SPEED.SLOW]: imageConfigSchema, + [E_BROADBAND_SPEED.MEDIUM]: imageConfigSchema, + [E_BROADBAND_SPEED.FAST]: imageConfigSchema, +}); + +type Images = z.infer; + +export const IMAGE_PRESET: Images = +{ + [E_BROADBAND_SPEED.SLOW]: { + // For 2g connections: smaller image widths help performance. (Middle East & Africa) + sizes_medium: "(min-width: 100px) 100px, 100vw", + sizes_thumbs: "(min-width: 80px) 80px, 80vw", + sizes_large: "(min-width: 320px) 320px, 320vw", + }, + [E_BROADBAND_SPEED.MEDIUM]: + { + // For 3g connections: a moderate size image for a balance of quality and speed. + sizes_medium: "(min-width: 400px) 400px, 400vw", + sizes_thumbs: "(min-width: 120px) 120px, 120vw", + sizes_large: "(min-width: 1024px) 1024px, 1024vw", + }, + [E_BROADBAND_SPEED.FAST]: + { + // For 4g connections: larger images for high-resolution displays. + sizes_medium: "(min-width: 1024px) 1024px, 1024vw", + sizes_thumbs: "(min-width: 180px) 180px, 180vw", + sizes_large: "(min-width: 1200px) 1200px, 1200vw" + } +} \ No newline at end of file diff --git a/src/config/profile.json b/src/config/profile.json new file mode 100644 index 0000000..dbc3ff9 --- /dev/null +++ b/src/config/profile.json @@ -0,0 +1,43 @@ +{ + "includes": [], + "variables": { + "PRODUCT_ROOT": "${root}/${product}/", + "abs_url": "https://assets.osr-plastic.org", + "CACHE": "${root}/cache/", + "CACHE_URL": "${abs_url}/cache/", + "GIT_REPO": "https://git.polymech.io/", + "OSR_MACHINES_ASSETS_URL":"https://assets.osr-plastic.org", + "PRODUCTS_ASSETS_URL":"https://assets.osr-plastic.org/${product_rel}", + "OSR_FILES_WEB":"https://files.polymech.io/files/machines", + "PRODUCTS_FILES_URL":"${OSR_FILES_WEB}/${product_rel}", + "DISCORD":"https://discord.gg/s8K7yKwBRc" + }, + "env": { + "astro-release":{ + "includes": [ + "${PRODUCT_ROOT}" + ], + "variables": { + "OSR_MACHINES_ASSETS_URL":"https://assets.osr-plastic.org/" + } + }, + "astro-debug":{ + "includes": [ + "${PRODUCT_ROOT}" + ], + "variables": { + "OSR_MACHINES_ASSETS_URL":"https://assets.osr-plastic.org", + "showCart": false, + "showPrice": false, + "showResources": false, + "showShipping": false, + "showPaymentTerms": false, + "showHowtos": false, + "showRenderings": true, + "debug": true + } + } + + } + +} \ No newline at end of file diff --git a/src/config/social.json b/src/config/social.json new file mode 100644 index 0000000..733bce2 --- /dev/null +++ b/src/config/social.json @@ -0,0 +1,24 @@ +{ + "main": [ + { + "name": "facebook", + "icon": "FaFacebookF", + "link": "https://www.facebook.com/themefisher" + }, + { + "name": "twitter", + "icon": "FaXTwitter", + "link": "https://x.com/themefisher" + }, + { + "name": "linkedin", + "icon": "FaLinkedinIn", + "link": "https://bd.linkedin.com/company/themefisher" + }, + { + "name": "github", + "icon": "FaGithub", + "link": "https://github.com/themefisher/astrofront" + } + ] +} diff --git a/src/config/stores.json b/src/config/stores.json new file mode 100644 index 0000000..4a446b9 --- /dev/null +++ b/src/config/stores.json @@ -0,0 +1,8 @@ +{ + "shop":{ + "title": "Shop", + "description": "", + "items":"${OSR_ROOT}/products/products/**/config.json", + "root":"${OSR_ROOT}/products" + } +} \ No newline at end of file diff --git a/src/config/theme.json b/src/config/theme.json new file mode 100644 index 0000000..98e2abd --- /dev/null +++ b/src/config/theme.json @@ -0,0 +1,44 @@ +{ + "colors": { + "default": { + "theme_color": { + "primary": "#121212", + "body": "#fff", + "border": "#eaeaea", + "theme_light": "#f2f2f2", + "theme_dark": "#000" + }, + "text_color": { + "default": "#444", + "dark": "#000", + "light": "#666" + } + }, + "darkmode": { + "theme_color": { + "primary": "#fff", + "body": "#252525", + "border": "#3E3E3E", + "theme_light": "#222222", + "theme_dark": "#000" + }, + "text_color": { + "default": "#DDD", + "dark": "#fff", + "light": "#DDD" + } + } + }, + "fonts": { + "font_family": { + "primary": "Karla:wght@400;500;700", + "primary_type": "sans-serif", + "secondary": "", + "secondary_type": "" + }, + "font_size": { + "base": "16", + "scale": "1.2" + } + } +}