diff --git a/packages/imagetools_3/astroViteConfigs.js b/packages/imagetools_3/astroViteConfigs.js index 841e04a..613ad89 100644 --- a/packages/imagetools_3/astroViteConfigs.js +++ b/packages/imagetools_3/astroViteConfigs.js @@ -1,12 +1,12 @@ export default { - "environment": "dev", + "environment": "build", "isSsrBuild": false, "projectBase": "", "publicDir": "C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\public\\", "rootDir": "C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\", - "mode": "dev", - "outDir": "dist", - "assetsDir": "/_astro", + "mode": "production", + "outDir": "C:\\Users\\zx\\Desktop\\polymech\\library.polymech\\dist\\", + "assetsDir": "_astro", "sourcemap": false, "assetFileNames": "/_astro/[name]@[width].[hash][extname]" } \ No newline at end of file diff --git a/packages/imagetools_3/utils/runtimeChecks.js b/packages/imagetools_3/utils/runtimeChecks.js index ae71025..5c22c60 100644 --- a/packages/imagetools_3/utils/runtimeChecks.js +++ b/packages/imagetools_3/utils/runtimeChecks.js @@ -46,10 +46,8 @@ const configFile = findUpSync([ "astro-imagetools.config.js", "astro-imagetools.config.mjs", ]); - -const configFunction = configFile - ? await import(configFile).catch(async () => await import("/" + configFile)) - : null; +/* @vite-ignore */ +const configFunction = configFile ? await import(configFile).catch(async () => await import("/" + configFile)) : null; const rawGlobalConfigOptions = configFunction?.default ?? {}; @@ -93,7 +91,7 @@ const cache_dir = () => { if (!exists(dir)) { mkdir(dir); } - }else{ + } else { dir = GlobalConfigOptions.cacheRoot } return dir + "/"; diff --git a/packages/polymech/src/app/config-loader.ts b/packages/polymech/src/app/config-loader.ts index beb471a..f645234 100644 --- a/packages/polymech/src/app/config-loader.ts +++ b/packages/polymech/src/app/config-loader.ts @@ -7,6 +7,7 @@ import { hideBin } from 'yargs/helpers'; import { substitute } from "@polymech/commons/variables"; import { appConfigSchema } from "./config.schema.js"; import type { AppConfig } from "./config.schema.js"; +import { z } from "astro/zod"; const I18N_SOURCE_LANGUAGE = 'en'; @@ -40,14 +41,15 @@ function deepMerge(target: any, source: any): any { export function loadConfig( locale: string = I18N_SOURCE_LANGUAGE, - libraryPath: string = LIBRARY_CONFIG_PATH + config: string = LIBRARY_CONFIG_PATH, + schema: z.ZodType = appConfigSchema, ): AppConfig { // 1. Load Library Config (Defaults) let rawLibraryContent: string; try { - rawLibraryContent = fs.readFileSync(libraryPath, 'utf-8'); + rawLibraryContent = fs.readFileSync(config, 'utf-8'); } catch (error) { - throw new Error(`Failed to read library config file at ${libraryPath}: ${error}`); + throw new Error(`Failed to read library config file at ${config}: ${error}`); } const variables = { @@ -61,7 +63,6 @@ export function loadConfig( } catch (error) { throw new Error(`Failed to parse library config JSON: ${error}`); } - // 2. Parse CLI Arguments // We assume the caller might want to pass args, or we just grab process.argv // We cast to any because yargs returns a complex type @@ -69,7 +70,7 @@ export function loadConfig( // 3. Determine User Config Path // Check for --config - const userConfigPath = argv.config ? path.resolve(argv.config) : USER_CONFIG_DEFAULT_PATH; + const userConfigPath = argv.config ? path.resolve(argv.config) : LIBRARY_CONFIG_PATH; // 4. Load User Config (if exists) let userConfig: any = {}; @@ -81,8 +82,11 @@ export function loadConfig( } catch (error) { console.warn(`Failed to load or parse user config at ${userConfigPath}: ${error}`); } + } else { + console.log('User config not found at', userConfigPath); } + // 5. Merge: Library <- User <- CLI // Note: yargs parses --config as part of argv, but also other flags like --core.logging_namespace // We filter out specific known CLI-only flags if needed, but config schema validation will drop unknown keys anyway? @@ -92,17 +96,11 @@ export function loadConfig( // CLI args often come with standard keys like '$0', '_' which we might want to exclude if we blindly merge. // However, deepMerge will add them. // Ideally we would only merge keys that exist in the schema, but dynamic is fine for now. - let mergedConfig = deepMerge(libraryConfig, userConfig); mergedConfig = deepMerge(mergedConfig, argv); - // 6. Validate - const result = appConfigSchema.safeParse(mergedConfig); + // @todo 6. Validate + // const result = schema.parse(mergedConfig); - if (!result.success) { - // Pretty print error if possible or just message - throw new Error(`Config validation failed: ${result.error.message}`); - } - - return result.data; + return mergedConfig; } diff --git a/packages/polymech/src/app/config.schema.ts b/packages/polymech/src/app/config.schema.ts index bc27d76..cfdbb11 100644 --- a/packages/polymech/src/app/config.schema.ts +++ b/packages/polymech/src/app/config.schema.ts @@ -62,6 +62,7 @@ export const devSchema = z.object({ export const i18NSchema = z.object({ store: z.string(), cache: z.boolean(), + source_language: z.string(), asset_path: z.string() }); diff --git a/packages/polymech/src/app/config.ts b/packages/polymech/src/app/config.ts index a8ba02f..b05140c 100644 --- a/packages/polymech/src/app/config.ts +++ b/packages/polymech/src/app/config.ts @@ -6,6 +6,7 @@ import { sanitizeUri } from 'micromark-util-sanitize-uri' import { loadConfig } from './config-loader.js' export const I18N_SOURCE_LANGUAGE = 'en' + // Load config const config = loadConfig(I18N_SOURCE_LANGUAGE) diff --git a/packages/polymech/src/app/navigation.ts b/packages/polymech/src/app/navigation.ts index 9d4b818..41826c4 100644 --- a/packages/polymech/src/app/navigation.ts +++ b/packages/polymech/src/app/navigation.ts @@ -1,5 +1,5 @@ import { translate } from '../base/i18n.js' -import { I18N_SOURCE_LANGUAGE } from 'config/config.js' +import { I18N_SOURCE_LANGUAGE } from '../app/config.js' import { loadConfig } from './config-loader.js' import pMap from 'p-map' diff --git a/packages/polymech/src/base/collections.ts b/packages/polymech/src/base/collections.ts index ae87234..cf1572d 100644 --- a/packages/polymech/src/base/collections.ts +++ b/packages/polymech/src/base/collections.ts @@ -2,7 +2,7 @@ import type { CollectionEntry } from 'astro:content'; import { isFolder } from '@polymech/commons'; import { parseFrontmatter } from '@astrojs/markdown-remark'; import { translate } from './i18n.js'; -import { I18N_SOURCE_LANGUAGE } from "config/config.js"; +import { I18N_SOURCE_LANGUAGE } from "../app/config.js"; // Filter function type export type CollectionFilter = (entry: CollectionEntry, astroConfig?: any) => boolean; diff --git a/packages/polymech/src/base/i18n.ts b/packages/polymech/src/base/i18n.ts index af54d00..573e5e2 100644 --- a/packages/polymech/src/base/i18n.ts +++ b/packages/polymech/src/base/i18n.ts @@ -3,15 +3,22 @@ import { resolve } from '@polymech/commons' import { sync as exists } from '@polymech/fs/exists' import type { IOptions } from '@polymech/i18n' -import { CONFIG_DEFAULT } from '@polymech/commons' -import { I18N_ASSET_PATH, I18N_CACHE, I18N_SOURCE_LANGUAGE, PRODUCT_SPECS, RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS } from '@/app/config.js' +export type { IOptions } from '@polymech/i18n' +import { CONFIG_DEFAULT } from '@polymech/commons' import { translateXLS } from '@polymech/i18n/translate_xls' -import { I18N_STORE, OSR_ROOT } from 'config/config.js' import { translateText } from '@polymech/i18n/translate_text' + + +import { PolymechInstance } from '../registry.js'; +import { AppConfig } from "../app/config.schema.js" + +import { I18N_STORE, OSR_ROOT } from '../app/config.js' +import { I18N_ASSET_PATH, I18N_CACHE, PRODUCT_SPECS, RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS } from '../app/config.js' + import { logger } from './index.js' -export type { IOptions } from '@polymech/i18n' +const loadConfig = (): AppConfig => PolymechInstance.getConfig(); export const translate = async (text: string, srcLanguage = 'en', targetLanguage, opts = {}) => { if (!targetLanguage) { @@ -20,7 +27,7 @@ export const translate = async (text: string, srcLanguage = 'en', targetLanguage try { const store = I18N_STORE(OSR_ROOT(), targetLanguage) let translation = text - translation = await translateText(text, srcLanguage, targetLanguage, { + translation = await translateText(text, srcLanguage, targetLanguage, { store, ...opts }) @@ -31,19 +38,20 @@ export const translate = async (text: string, srcLanguage = 'en', targetLanguage return text } export const translateSheets = async (product, language) => { - const config: any = CONFIG_DEFAULT() - if (language === I18N_SOURCE_LANGUAGE) { + const pm_config: any = CONFIG_DEFAULT() + const config = loadConfig() + if (language === config.i18n.source_language) { return } const i18nOptions: IOptions = { - srcLang: I18N_SOURCE_LANGUAGE, + srcLang: config.i18n.source_language, dstLang: language, src: PRODUCT_SPECS(product), store: I18N_STORE(OSR_ROOT(), language), dst: I18N_ASSET_PATH, query: "$[*][0,1,2,3]", cache: I18N_CACHE, - api_key: config.deepl.auth_key, + api_key: pm_config.deepl.auth_key, logLevel: RETAIL_LOG_LEVEL_I18N_PRODUCT_ASSETS } const src = `${PRODUCT_SPECS(product)}` diff --git a/packages/polymech/src/base/index.ts b/packages/polymech/src/base/index.ts index 4566ab1..1ad909d 100644 --- a/packages/polymech/src/base/index.ts +++ b/packages/polymech/src/base/index.ts @@ -9,17 +9,11 @@ import { findUp } from 'find-up' import { createLogger } from '@polymech/log' import { parse, IProfile } from '@polymech/commons/profile' -import { translate } from "@/base/i18n.js" -// import { renderMarkup } from "../model/component.js" - import { - LOGGING_NAMESPACE, OSRL_ENV, OSRL_PRODUCT_PROFILE, - PRODUCT_ROOT, - I18N_SOURCE_LANGUAGE -} from 'config/config.js' - + PRODUCT_ROOT +} from '../app/config.js' export const logger = createLogger('polymech-astro') diff --git a/packages/polymech/src/base/media.ts b/packages/polymech/src/base/media.ts index f5b32e1..1d0051e 100644 --- a/packages/polymech/src/base/media.ts +++ b/packages/polymech/src/base/media.ts @@ -14,9 +14,9 @@ import { files } from '@polymech/commons' import { sync as exists } from '@polymech/fs/exists' import { sync as read } from '@polymech/fs/read' -import { logger } from '@/base/index.js' +import { logger } from './index.js' -import { removeArrayValues, removeArrays, removeBufferValues, removeEmptyObjects } from '@/base/objects.js' +import { removeArrayValues, removeArrays, removeBufferValues, removeEmptyObjects } from './objects.js' import { ITEM_ASSET_URL, PRODUCT_CONFIG, PRODUCT_ROOT, DEFAULT_IMAGE_URL, FILE_SERVER_DEV } from '../app/config.js' import { GalleryImage, MetaJSON } from './images.js' diff --git a/packages/polymech/src/bin.ts b/packages/polymech/src/bin.ts index 83e82f4..4bc21df 100644 --- a/packages/polymech/src/bin.ts +++ b/packages/polymech/src/bin.ts @@ -2,5 +2,6 @@ import { cli } from './cli.js'; import './commands/build-config.js'; import './commands/build.js'; +import './commands/dev.js'; cli.parse(); diff --git a/packages/polymech/src/commands/build-config.ts b/packages/polymech/src/commands/build-config.ts index 6cc24ce..2e7cff5 100644 --- a/packages/polymech/src/commands/build-config.ts +++ b/packages/polymech/src/commands/build-config.ts @@ -18,7 +18,7 @@ export const builder = (yargs: CLI.Argv) => { alias: 'd', type: 'string', describe: 'Output d.ts path', - default: './src/app/config.d.ts' + default: './src/app/config-types.ts' }) .option('dest-schema', { alias: 'z', diff --git a/packages/polymech/src/commands/dev.ts b/packages/polymech/src/commands/dev.ts new file mode 100644 index 0000000..edeeb40 --- /dev/null +++ b/packages/polymech/src/commands/dev.ts @@ -0,0 +1,35 @@ +import { spawnSync } from 'child_process'; +import * as CLI from 'yargs'; +import { cli } from '../cli.js'; +import { handler as configHandler, builder as configBuilder } from './build-config.js'; + +export const command = 'dev [src]'; +export const desc = 'Generate config and start Astro dev server'; + +export const builder = (yargs: CLI.Argv) => { + return configBuilder(yargs) + .strict(false); +}; + +export async function handler(argv: CLI.Arguments) { + // 1. Config Generation + await configHandler(argv); + + // 2. Astro Dev + const devIndex = process.argv.indexOf('dev'); + const forwardedArgs = devIndex !== -1 ? process.argv.slice(devIndex + 1) : []; + + console.log('[pm-astro] Running astro dev...'); + // Execute astro dev + // Standard dev args like --host can be passed by user + const result = spawnSync('npx', ['astro', 'dev', ...forwardedArgs], { + stdio: 'inherit', + shell: true + }); + + if (result.status !== 0) { + process.exit(result.status || 1); + } +} + +cli.command(command, desc, builder, handler); diff --git a/packages/polymech/src/components/BaseHead.astro b/packages/polymech/src/components/BaseHead.astro index a6c6432..299b4a4 100644 --- a/packages/polymech/src/components/BaseHead.astro +++ b/packages/polymech/src/components/BaseHead.astro @@ -4,18 +4,17 @@ import "../styles/flowbite.css" import "../styles/global.css" import "../styles/custom.scss" -import { I18N_SOURCE_LANGUAGE } from "config/config.js" +import { sync as read } from '@polymech/fs/read' +import { AstroSeo } from "@astrolib/seo" + +import { I18N_SOURCE_LANGUAGE } from "../app/config.js" import { translate } from '@polymech/astro-base/base/i18n.js' import { item_defaults } from '@/base/index.js' -import { LANGUAGES_PROD } from "config/config.js" -import config from "config/config.json" +import { LANGUAGES_PROD } from "../app/config.js" +import config from "../app/config.json" import { plainify } from "@polymech/astro-base/base/strings.js" -import { sync as read } from '@polymech/fs/read' - -import { AstroSeo } from "@astrolib/seo" - import StructuredData from '@polymech/astro-base/components/ArticleStructuredData.astro' import Hreflang from '@polymech/astro-base/components/hreflang.astro' diff --git a/packages/polymech/src/components/GalleryK.astro b/packages/polymech/src/components/GalleryK.astro index 749a01e..1651aed 100644 --- a/packages/polymech/src/components/GalleryK.astro +++ b/packages/polymech/src/components/GalleryK.astro @@ -1,9 +1,10 @@ --- import { Img } from "imagetools/components"; -import Translate from "./i18n.astro" -import { translate } from "@/base/i18n"; -import { I18N_SOURCE_LANGUAGE, IMAGE_SETTINGS } from "config/config.js" +import Translate from "./i18n.astro" +import { translate } from "../base/i18n"; + +import { I18N_SOURCE_LANGUAGE, IMAGE_SETTINGS } from "../app/config.js" interface Image { alt: string diff --git a/packages/polymech/src/components/MasonryGallery.astro b/packages/polymech/src/components/MasonryGallery.astro index 26646c6..99a661e 100644 --- a/packages/polymech/src/components/MasonryGallery.astro +++ b/packages/polymech/src/components/MasonryGallery.astro @@ -1,10 +1,11 @@ --- import { Img } from "imagetools/components"; + +import { globBase, pathInfo } from "@polymech/commons"; import Translate from "./i18n.astro"; -import { IMAGE_SETTINGS } from "config/config.js"; +import { IMAGE_SETTINGS } from "../app/config.js"; import path from "node:path"; import { glob } from 'glob'; -import { globBase, pathInfo } from "@polymech/commons"; import { extractImageMetadata, groupByYear, groupByMonth, GroupInfo } from "../base/media"; import { resolveImagePath } from "../utils/path-resolution.js"; diff --git a/packages/polymech/src/components/global/Footer.astro b/packages/polymech/src/components/global/Footer.astro index ee4c000..b93f053 100644 --- a/packages/polymech/src/components/global/Footer.astro +++ b/packages/polymech/src/components/global/Footer.astro @@ -2,7 +2,7 @@ import Wrapper from "@/components/containers/Wrapper.astro"; import { footer_left, footer_right } from "../../app/navigation.js"; import { ISO_LANGUAGE_LABELS } from "@polymech/i18n"; -import { LANGUAGES_PROD, I18N_SOURCE_LANGUAGE } from "config/config.js"; +import { LANGUAGES_PROD, I18N_SOURCE_LANGUAGE } from "../../app/config.js"; const locale = Astro.currentLocale || I18N_SOURCE_LANGUAGE; const currentUrl = new URL(Astro.url); diff --git a/packages/polymech/src/components/global/Navigation.astro b/packages/polymech/src/components/global/Navigation.astro index cf017bd..603a018 100644 --- a/packages/polymech/src/components/global/Navigation.astro +++ b/packages/polymech/src/components/global/Navigation.astro @@ -1,13 +1,12 @@ --- import Wrapper from "@/components/containers/Wrapper.astro"; - -import { I18N_SOURCE_LANGUAGE } from "@/app/config"; - import { items } from "../../app/navigation.js"; - import ThemeToggle from "./ThemeToggle.astro"; -const locale = Astro.currentLocale || I18N_SOURCE_LANGUAGE; +import { PolymechInstance } from "../../registry.js"; +import { AppConfig } from "@/app/config.schema.js"; +const config = (): AppConfig => PolymechInstance.getConfig(); +const locale = Astro.currentLocale || config().i18n.source_language; const navItems = await items({ locale }); --- diff --git a/packages/polymech/src/components/i18n.astro b/packages/polymech/src/components/i18n.astro index 7998908..2710edd 100644 --- a/packages/polymech/src/components/i18n.astro +++ b/packages/polymech/src/components/i18n.astro @@ -1,21 +1,23 @@ --- -import { I18N_SOURCE_LANGUAGE } from "config/config.js" -import { translate, IOptions } from '@/base/i18n.js' +import { I18N_SOURCE_LANGUAGE } from "../app/config.js"; +import { translate, IOptions } from "../base/i18n.js"; -export interface Props extends IOptions { - language?: string, - clazz?:string +export interface Props extends IOptions { + language?: string; + clazz?: string; } -const { - language = Astro.currentLocale, - clazz = '', - ...rest -} = Astro.props +const { language = Astro.currentLocale, clazz = "", ...rest } = Astro.props; -const content = await Astro.slots.render('default') -const translatedText = await translate(content, I18N_SOURCE_LANGUAGE, language, rest) +const content = await Astro.slots.render("default"); +const translatedText = await translate( + content, + I18N_SOURCE_LANGUAGE, + language, + rest, +); --- +

- {translatedText} + {translatedText}

diff --git a/packages/polymech/src/components/modbus/CoilsTable.astro b/packages/polymech/src/components/modbus/CoilsTable.astro index fe57101..b7db18d 100644 --- a/packages/polymech/src/components/modbus/CoilsTable.astro +++ b/packages/polymech/src/components/modbus/CoilsTable.astro @@ -1,43 +1,44 @@ --- -import { getProcessedCoilsData } from '../../utils/modbus-data'; -import { getModbusFunctionName, getFunctionCategory } from '../../utils/modbusUtils'; +import { getProcessedCoilsData } from "../../utils/modbus-data"; const groupedCoils = getProcessedCoilsData(); const groupNames = Object.keys(groupedCoils).sort(); ---
- {groupNames.map(groupName => ( -
-

{groupName}

-
- - - - - - - - - - - - {groupedCoils[groupName].map(coil => { - return ( - - - - - - - - ); - })} - -
FCAddressNameComponentID
1/5{coil.address}{coil.name}{coil.component}{coil.id}
+ { + groupNames.map((groupName) => ( +
+

{groupName}

+
+ + + + + + + + + + + + {groupedCoils[groupName].map((coil) => { + return ( + + + + + + + + ); + })} + +
FCAddressNameComponentID
1/5{coil.address}{coil.name}{coil.component}{coil.id}
+
-
- ))} + )) + }
diff --git a/packages/polymech/src/layouts/StoreLayout.astro b/packages/polymech/src/layouts/StoreLayout.astro index d65c9b4..5ea907d 100644 --- a/packages/polymech/src/layouts/StoreLayout.astro +++ b/packages/polymech/src/layouts/StoreLayout.astro @@ -1,21 +1,18 @@ --- import "flowbite"; -import { createMarkdownComponent } from "@/base/index.js"; -import { translate } from "@polymech/astro-base/base/i18n.js"; -import Translate from "@polymech/astro-base/components/i18n.astro"; -import LGallery from "@polymech/astro-base/components/GalleryK.astro"; +import { createMarkdownComponent } from "../base/index.js"; +import { translate } from "../base/i18n.js"; +import Translate from "../components/i18n.astro"; +import LGallery from "../components/GalleryK.astro"; import BaseLayout from "./BaseLayout.astro"; -import Wrapper from "@/components/containers/Wrapper.astro"; - -import Readme from "@/components/polymech/readme.astro"; -import Breadcrumb from "@/components/Breadcrumb.astro"; - -import Resources from "@/components/polymech/resources.astro"; -import Specs from "@polymech/astro-base/components/specs.astro"; - -import TabButton from "@polymech/astro-base/components/tab-button.astro"; -import TabContent from "@polymech/astro-base/components/tab-content.astro"; +import Wrapper from "../components/containers/Wrapper.astro"; +import Readme from "../components/polymech/readme.astro"; +import Breadcrumb from "../components/Breadcrumb.astro"; +import Resources from "../components/polymech/resources.astro"; +import Specs from "../components/specs.astro"; +import TabButton from "../components/tab-button.astro"; +import TabContent from "../components/tab-content.astro"; import { I18N_SOURCE_LANGUAGE, @@ -60,7 +57,7 @@ const Content_Debug = await createMarkdownComponent(str_debug); -
-

+

{`${data.title}`}

{ isRTL(Astro.currentLocale) && ( -
- "{data.title}" -
+
"{data.title}"
) }
- -
) } @@ -220,149 +219,147 @@ const Content_Debug = await createMarkdownComponent(str_debug);
) } - - - - {data.assets.showcase && data.assets.showcase.length > 0 && ( -
-
- {" "} -
-
- )} - + + { + data.assets.showcase && data.assets.showcase.length > 0 && ( +
+
+ {" "} +
+
+ ) + } +
-
-
    - {SHOW_README && } - - - - {SHOW_SAMPLES && } - {SHOW_DEBUG && } -
-
-
- +
+
    + {SHOW_README && } + + + + {SHOW_SAMPLES && } + {SHOW_DEBUG && } +
+
+
+ + { + SHOW_README && data.readme && ( + + ) + } + + + { - SHOW_README && data.readme && ( - + SHOW_SAMPLES && ( + ) } - - - - { - SHOW_SAMPLES && ( - - ) - } - { - SHOW_RESOURCES && ( - - ) - } - { - SHOW_DEBUG && ( - - ) - } -
- +
diff --git a/packages/polymech/src/layouts/WithSidebar.astro b/packages/polymech/src/layouts/WithSidebar.astro index 48e3b94..1ce84d1 100644 --- a/packages/polymech/src/layouts/WithSidebar.astro +++ b/packages/polymech/src/layouts/WithSidebar.astro @@ -1,8 +1,8 @@ --- -import BaseLayout from './BaseLayout.astro'; -import Sidebar from '@/components/sidebar/Sidebar.astro'; -import MobileToggle from '@/components/sidebar/MobileToggle.astro'; -import { getSidebarConfig } from '@/components/sidebar/config'; +import BaseLayout from "./BaseLayout.astro"; +import Sidebar from "../components/sidebar/Sidebar.astro"; +import MobileToggle from "../components/sidebar/MobileToggle.astro"; +import { getSidebarConfig } from "../components/sidebar/config"; interface Props { frontmatter: { @@ -20,12 +20,12 @@ const sidebarConfig = getSidebarConfig();
- + - +
diff --git a/packages/polymech/src/model/component.ts b/packages/polymech/src/model/component.ts index d156efc..9be9f1d 100644 --- a/packages/polymech/src/model/component.ts +++ b/packages/polymech/src/model/component.ts @@ -1,49 +1,49 @@ +import type { DataEntry } from "astro:content" + import * as path from 'path' import { findUp } from 'find-up' import { sync as read } from '@polymech/fs/read' import { sync as exists } from '@polymech/fs/exists' -import { env } from '@/base/index.js' +import { env } from '../base/index.js' import { gallery } from '@polymech/astro-base/base/media.js'; import { get } from '@polymech/commons/component' import { PFilterValid } from '@polymech/commons/filter' import { IAssemblyData } from '@polymech/cad' -import { logger as log } from '@/base/index.js' +import { logger as log } from '../base/index.js' +import { translate } from "../base/i18n.js" +import { slugify } from '../base/strings.js' +import { loadConfig } from '../app/config-loader.js' import { filesEx, forward_slash, resolveConfig, template } from '@polymech/commons' + import { ICADNodeSchema, IComponentConfig } from '@polymech/commons/component' -import { DataEntry } from "astro:content" import type { Loader, LoaderContext } from 'astro/loaders' import { PolymechInstance } from '../registry.js'; - -// Access config safely -const c = () => { - const cfg = PolymechInstance.getConfig(); - if (!cfg) throw new Error("Polymech configuration missing. Ensure setConfig is called."); - return cfg; -} +import { AppConfig } from "../app/config.schema.js" +const config = (): AppConfig => PolymechInstance.getConfig(); // Config Accessors -const PRODUCT_ROOT = () => c().products?.root || ''; -const PRODUCT_GLOB = () => c().products?.glob || ''; +const PRODUCT_ROOT = () => config().products?.root || ''; +const PRODUCT_GLOB = () => config().products?.glob || ''; const PRODUCT_DIR = (rel: string) => path.join(PRODUCT_ROOT(), rel); -const CAD_MAIN_MATCH = (product: string) => template(c().cad?.main_match || '', { product }); +const CAD_MAIN_MATCH = (product: string) => template(config().cad?.main_match || '', { product }); const CAD_URL = (file: string, variables: Record) => - template(c().assets?.cad_url || '', { file, ...variables }); + template(config().assets?.cad_url || '', { file, ...variables }); -const CAD_EXTENSIONS = () => c().cad?.extensions || []; +const CAD_EXTENSIONS = () => config().cad?.extensions || []; const CAD_MODEL_EXT = ".tree.json"; -const CAD_EXPORT_CONFIGURATIONS = () => c().cad?.export_configurations; -const CAD_DEFAULT_CONFIGURATION = () => c().cad?.default_configuration || ''; +const CAD_EXPORT_CONFIGURATIONS = () => config().cad?.export_configurations; +const CAD_DEFAULT_CONFIGURATION = () => config().cad?.default_configuration || ''; // Product Branches const PRODUCT_BRANCHES = () => { - const enabled = c().products?.enabled; + const enabled = config().products?.enabled; const resolvedPath = enabled ? path.resolve(enabled) : null; return (resolvedPath && exists(resolvedPath)) ? read(resolvedPath, 'json') : null; } @@ -272,3 +272,32 @@ export function loader(branch: string): Loader { load }; } + +export const group_path = (item) => item.id.split("/")[1] + +const group_label = async (text: string, locale) => await translate(slugify(text), config().i18n.source_language, locale) + +const group = async (items, locale) => { + return items.reduce(async (accPromise, item) => { + const acc = await accPromise + const id = group_path(item) + let key: string = await group_label(id, locale) + key = key.charAt(0).toUpperCase() + key.slice(1) + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(item) + return acc + }, {}) +} + +export const group_by_path = async (items, locale): Promise => await group(items, locale) + +export const mailto = (to: string, subject: string, body: string): string => { + const encode = (str: string) => encodeURIComponent(str).replace(/%20/g, '+'); + return `mailto:${encode(to)}?subject=${encode(subject)}&body=${encode(body)}`; +} + +export const item_checkout = async (item: IComponentConfig) => { + // return `mailto:${DEFAULT_CONTACT}?subject=${item.name}&body=${""}` +} \ No newline at end of file diff --git a/packages/polymech/src/model/json-ld.ts b/packages/polymech/src/model/json-ld.ts index 98c9e1c..ec3ca70 100644 --- a/packages/polymech/src/model/json-ld.ts +++ b/packages/polymech/src/model/json-ld.ts @@ -1,5 +1,6 @@ import type { IComponentNode, IComponentConfig } from '@polymech/commons' -import config from "../app/config.json" +import { PolymechInstance } from '../registry.js'; +const config = () => PolymechInstance.getConfig(); interface ProductJsonLD { '@context': 'https://schema.org' @@ -21,18 +22,18 @@ interface ProductJsonLD { } } -export const get = async (node: IComponentNode, component: IComponentConfig, opts:{ - url?:string +export const get = async (node: IComponentNode, component: IComponentConfig, opts: { + url?: string }): Promise => { const jsonLD: ProductJsonLD = { '@context': 'https://schema.org', - '@type': 'Product', + '@type': 'Product', name: component.name, description: component.keywords, sku: component.code, brand: { '@type': 'Brand', - name: config.ecommerce?.brand || config.site.title + name: config().ecommerce?.brand || config().site.title } } if (component.image?.url) { @@ -43,9 +44,9 @@ export const get = async (node: IComponentNode, component: IComponentConfig, opt jsonLD.offers = { '@type': 'Offer', price: component.price, - priceCurrency: config.ecommerce?.currencyCode || 'EU', + priceCurrency: config().ecommerce?.currencyCode || 'EU', availability: 'https://schema.org/InStock', - url: opts.url || config.site.base_url + url: opts.url || config().site.base_url } } return jsonLD diff --git a/packages/polymech/src/model/merchant.ts b/packages/polymech/src/model/merchant.ts index bbbb80a..847df12 100644 --- a/packages/polymech/src/model/merchant.ts +++ b/packages/polymech/src/model/merchant.ts @@ -1,7 +1,5 @@ import type { IComponentNode, IComponentConfig } from '@polymech/commons' -import config from "../app/config.json" - interface GoogleMerchantProduct { id: string title: string @@ -16,7 +14,7 @@ interface GoogleMerchantProduct { } export const get = async (node: IComponentNode, config: IComponentConfig, opts: { - url?:string + url?: string }): Promise => { const product: GoogleMerchantProduct = { id: config.code, diff --git a/packages/polymech/src/pages/404.astro b/packages/polymech/src/pages/404.astro index 11abf8b..6be8b28 100644 --- a/packages/polymech/src/pages/404.astro +++ b/packages/polymech/src/pages/404.astro @@ -1,18 +1,18 @@ --- -import BaseLayout from "@/layouts/BaseLayout.astro"; +import BaseLayout from "../layouts/BaseLayout.astro"; Astro.redirect("/en/home"); ---
+ class="flex flex-col gap-12 h-full justify-between p-4 text-center py-20" + >
-

+

404 Page not found

-

+

The page you are looking for does not exist. Please try again. If the problem persists, please contact us.

@@ -21,13 +21,15 @@ Astro.redirect("/en/home"); href="/" title="link to your page" aria-label="your label" - class="relative group overflow-hidden pl-4 h-14 flex space-x-6 items-center bg-white hover:bg-neutral-200 duration-300 rounded-xl w-full justify-between"> + class="relative group overflow-hidden pl-4 h-14 flex space-x-6 items-center bg-white hover:bg-neutral-200 duration-300 rounded-xl w-full justify-between" + > Go home @@ -64,13 +66,13 @@ Astro.redirect("/en/home"); href="/forms/contact" title="link to your page" aria-label="your label" - class="relative group overflow-hidden pl-4 h-14 flex space-x-6 items-center hover:bg-black duration-300 rounded-xl w-full justify-between"> - Contact us + class="relative group overflow-hidden pl-4 h-14 flex space-x-6 items-center hover:bg-black duration-300 rounded-xl w-full justify-between" + > + Contact us diff --git a/packages/polymech/src/pages/[locale]/resources/[...slug].astro b/packages/polymech/src/pages/[locale]/resources/[...slug].astro index dcccab9..0bf9030 100644 --- a/packages/polymech/src/pages/[locale]/resources/[...slug].astro +++ b/packages/polymech/src/pages/[locale]/resources/[...slug].astro @@ -1,28 +1,29 @@ --- import { getCollection, render } from "astro:content" -import Resources from "@/layouts/Resources.astro" -import BaseLayout from "@/layouts/BaseLayout.astro"; -import Sidebar from "@polymech/astro-base/components/sidebar/Sidebar.astro" -import MobileToggle from "@polymech/astro-base/components/sidebar/MobileToggle.astro" -import { getSidebarConfig } from '@polymech/astro-base/config/sidebar'; -import ResourceCard from "@polymech/astro-base/components/resources/ResourceCard.astro"; +import Resources from "../../../layouts/Resources.astro" +import BaseLayout from "../../../layouts/BaseLayout.astro"; +import Sidebar from "../../../components/sidebar/Sidebar.astro" +import MobileToggle from "../../../components/sidebar/MobileToggle.astro" +import { getSidebarConfig } from '../../../components/sidebar/config'; +import ResourceCard from "../../../components/resources/ResourceCard.astro"; -import { generateBreadcrumbs, calculateReadingTime, getStaticPaths_fs } from '@polymech/astro-base/base/collections'; +import { generateBreadcrumbs, calculateReadingTime, getStaticPaths_fs } from '../../../base/collections'; -import { translate } from "@polymech/astro-base/base/i18n.js"; -import Translate from "@polymech/astro-base/components/i18n.astro"; -import { I18N_SOURCE_LANGUAGE } from "config/config.js"; +import {translate } from "../../../base/i18n.js"; +import Translate from "../../../components/i18n.astro"; +import { I18N_SOURCE_LANGUAGE } from "../../../app/config.js"; const collectionName = 'resources'; const collectionDescription = 'Discover insights, tutorials, and best practices from our collection of technical articles and resources.'; -import { PolymechInstance } from '@polymech/astro-base/registry'; +import { PolymechInstance } from '../../../registry'; + export async function getStaticPaths() { const config = PolymechInstance.getConfig(); const collectionName = 'resources'; - const paths = await getStaticPaths_fs(getCollection, collectionName, config.LANGUAGES_PROD, config.COLLECTION_FILTERS); + const paths = await getStaticPaths_fs(getCollection, collectionName, config.core.languages_prod, { }); // Add root path for each language - config.LANGUAGES_PROD?.forEach((lang) => { + config.core.languages_prod?.forEach((lang) => { paths.push({ params: { locale: lang diff --git a/packages/polymech/src/pages/[locale]/resources/slug.astro b/packages/polymech/src/pages/[locale]/resources/slug.astro index e5184ae..e7438a7 100644 --- a/packages/polymech/src/pages/[locale]/resources/slug.astro +++ b/packages/polymech/src/pages/[locale]/resources/slug.astro @@ -1,30 +1,31 @@ --- import { getCollection, render } from "astro:content" -import Resources from "@/layouts/Resources.astro" -import BaseLayout from "@/layouts/BaseLayout.astro"; -import Sidebar from "@polymech/astro-base/components/sidebar/Sidebar.astro" -import MobileToggle from "@polymech/astro-base/components/sidebar/MobileToggle.astro" -import { getSidebarConfig } from '@polymech/astro-base/config/sidebar'; -import ResourceCard from "@/components/resources/ResourceCard.astro"; -import { LANGUAGES_PROD, COLLECTION_FILTERS } from "config/config.js" +import Resources from "../../../layouts/Resources.astro" +import BaseLayout from "../../../layouts/BaseLayout.astro"; +import Sidebar from "../../../components/sidebar/Sidebar.astro" +import MobileToggle from "../../../components/sidebar/MobileToggle.astro" -import { generateBreadcrumbs, calculateReadingTime, getStaticPaths_fs } from '@polymech/astro-base/base/collections'; +import { getSidebarConfig } from '../../../config/sidebar'; + +import ResourceCard from "../../../components/resources/ResourceCard.astro"; + + +import { generateBreadcrumbs, calculateReadingTime, getStaticPaths_fs } from '../../../base/collections'; import { translate } from "@polymech/astro-base/base/i18n.js"; import Translate from "@polymech/astro-base/components/i18n.astro"; -import { I18N_SOURCE_LANGUAGE } from "config/config.js"; + +import { I18N_SOURCE_LANGUAGE } from "../../../app/config.js"; const collectionName = 'resources'; const collectionDescription = 'Discover insights, tutorials, and best practices from our collection of technical articles and resources.'; import { PolymechInstance } from '@polymech/astro-base/registry'; export async function getStaticPaths() { - debugger; const config = PolymechInstance.getConfig(); const collectionName = 'resources'; - const paths = await getStaticPaths_fs(getCollection, collectionName, LANGUAGES_PROD, COLLECTION_FILTERS); - + const paths = await getStaticPaths_fs(getCollection, collectionName, config.core.languages_prod, {}); // Add root path for each language - LANGUAGES_PROD.forEach((lang) => { + config.core.languages_prod.forEach((lang) => { paths.push({ params: { locale: lang, diff --git a/packages/polymech/src/pages/[locale]/resources/tags/[tag].astro b/packages/polymech/src/pages/[locale]/resources/tags/[tag].astro index 75bda7a..1d06089 100644 --- a/packages/polymech/src/pages/[locale]/resources/tags/[tag].astro +++ b/packages/polymech/src/pages/[locale]/resources/tags/[tag].astro @@ -1,84 +1,95 @@ --- -import Resources from "@/layouts/Resources.astro"; -import ResourceCard from "@/components/resources/ResourceCard.astro"; +import Resources from "../../../../layouts/Resources.astro"; +import ResourceCard from "../../../../components/resources/ResourceCard.astro"; import { getCollection } from "astro:content"; -import { LANGUAGES_PROD } from "config/config.js"; -import Translate from "@polymech/astro-base/components/i18n.astro"; +import { LANGUAGES_PROD } from "../../../../app/config.js"; +import Translate from "../../../../components/i18n.astro"; export async function getStaticPaths() { const allPosts = await getCollection("resources"); const uniqueTags = [ ...new Set(allPosts.map((post) => post.data.tags).flat()), ]; - + const paths: any[] = []; - + // Generate paths for each locale and tag combination LANGUAGES_PROD.forEach((locale) => { uniqueTags.forEach((tag) => { const filteredPosts = allPosts.filter((post) => - post.data.tags.includes(tag) + post.data.tags.includes(tag), ); - + paths.push({ - params: { + params: { locale, - tag + tag, }, - props: { + props: { posts: filteredPosts, locale, - tag + tag, }, }); }); }); - + return paths; } const { tag, locale } = Astro.params; const { posts } = Astro.props; -const collectionName = posts.length > 0 ? posts[0].collection : 'resources'; +const collectionName = posts.length > 0 ? posts[0].collection : "resources"; --- -
- {posts.map((post) => ( - - ))} + { + posts.map((post) => ( + + )) + }
- +
- - - + + Back to All Tags diff --git a/packages/polymech/src/pages/[locale]/store/[...path].astro b/packages/polymech/src/pages/[locale]/store/[...path].astro index 4cd72f7..979afb8 100644 --- a/packages/polymech/src/pages/[locale]/store/[...path].astro +++ b/packages/polymech/src/pages/[locale]/store/[...path].astro @@ -1,12 +1,13 @@ --- import StoreLayout from "@/layouts/StoreLayout.astro"; import { getCollection } from "astro:content"; -import { LANGUAGES_PROD } from "config/config.js"; -import StoreEntries from "@/components/store/StoreEntries.astro"; -import BaseLayout from "@/layouts/BaseLayout.astro"; -import Wrapper from "@/components/containers/Wrapper.astro"; -import Translate from "@polymech/astro-base/components/i18n.astro"; -import { slugify } from "@/base/strings.js"; +import { LANGUAGES_PROD } from "../../../app/config.js"; + +import StoreEntries from "../../../components/store/StoreEntries.astro"; +import BaseLayout from "../../../layouts/BaseLayout.astro"; +import Wrapper from "../../../components/containers/Wrapper.astro"; +import Translate from "../../../components/i18n.astro"; +import { slugify } from "../../../base/strings.js"; export async function getStaticPaths() { const view = "store"; diff --git a/packages/polymech/src/pages/index.astro b/packages/polymech/src/pages/index.astro index 37d25ae..8b7c621 100644 --- a/packages/polymech/src/pages/index.astro +++ b/packages/polymech/src/pages/index.astro @@ -1,25 +1,28 @@ --- -import BaseLayout from "@/layouts/BaseLayout.astro" -import { getCollection } from "astro:content" -import StoreEntries from "@/components/store/StoreEntries.astro" -const allProducts = await getCollection("store") -const locale = Astro.currentLocale || "en" +import BaseLayout from "../layouts/BaseLayout.astro"; +import { getCollection } from "astro:content"; + +import StoreEntries from "../components/store/StoreEntries.astro"; + +const allProducts = await getCollection("store"); +const locale = Astro.currentLocale || "en"; --- - + +
- { allProducts.map((post) => (
- -
diff --git a/packages/polymech/src/registry.ts b/packages/polymech/src/registry.ts index 3e4fc64..94069c3 100644 --- a/packages/polymech/src/registry.ts +++ b/packages/polymech/src/registry.ts @@ -1,3 +1,4 @@ +import { AppConfig } from './app/config.schema.js' interface PolymechConfig { // Config groups matching app-config.json site?: any; @@ -87,7 +88,7 @@ if (!G.__MYPAGES_CONFIG__) { class PolymechRegistry { private static instance: PolymechRegistry; - private config: PolymechConfig; + private config: AppConfig; private callbacks: Record = {}; constructor() { @@ -103,19 +104,19 @@ class PolymechRegistry { } // Set configuration from host app - setConfig(config: PolymechConfig) { + setConfig(config: AppConfig) { // Merge the new config into the existing one and update the global store. const newConfig = { ...this.config, ...config }; this.config = newConfig; G.__MYPAGES_CONFIG__ = newConfig; // Trigger callbacks - this.config.callbacks?.onConfigUpdate?.(this.config); + (this.config as any).callbacks?.onConfigUpdate?.(this.config); this.emit('configUpdate', { newConfig: this.config }); } // Get configuration in components - getConfig(): PolymechConfig { + getConfig(): AppConfig { // The config property is now always synced with the global store. return this.config; } @@ -136,9 +137,10 @@ class PolymechRegistry { // Convenience getters // Convenience getters (Mapping new config structure to old accessors if needed, or just helpers) - get productCategory() { return this.config.productCategory || 'Unknown'; } + get languages() { return this.config.core?.languages || ['en']; } get LANGUAGES_PROD() { return this.config.core?.languages_prod || ['en']; } + get COLLECTION_FILTERS() { return {}; } // products was string[]? in old config it was string[], now it's an object config.products // Old: get products() { return this.config.products || []; } // We can leave 'products' as the category list if it exists in 'site' or somewhere? @@ -146,8 +148,6 @@ class PolymechRegistry { // If the old getter meant 'list of product categories', that's not in the new config yet? // Let's assume accessing raw config is preferred now. - get apiEndpoints() { return this.config.apiEndpoints || {}; } - get COLLECTION_FILTERS() { return this.config.COLLECTION_FILTERS || {}; } } export const PolymechInstance = PolymechRegistry.getInstance(); diff --git a/packages/polymech/src/utils/path-resolution.ts b/packages/polymech/src/utils/path-resolution.ts index a4ce1c5..fce8e2e 100644 --- a/packages/polymech/src/utils/path-resolution.ts +++ b/packages/polymech/src/utils/path-resolution.ts @@ -1,9 +1,9 @@ import fs from 'fs'; import path from 'path'; -import { resolveVariables, resolve } from '@polymech/commons' + // --- Debug Configuration --- const enableDebugSuccess = false; -const enableDebugErrors = false; +const enableDebugErrors = false; /** * Checks if a given file path exists and is a file. @@ -72,7 +72,7 @@ export function resolveImagePath(src: string, entryPath?: string, astroUrl?: URL const pathSegments = astroUrl.pathname.split('/').filter(p => p); const hasLocale = pathSegments.length > 0 && /^[a-z]{2}$/.test(pathSegments[0]); if (hasLocale) pathSegments.shift(); - + if (pathSegments.length >= 1) { const contentDirGuess = isFolderUrl ? pathSegments.join('/') : pathSegments.slice(0, -1).join('/'); basePath = path.join(process.cwd(), 'src', 'content', contentDirGuess); @@ -88,7 +88,7 @@ export function resolveImagePath(src: string, entryPath?: string, astroUrl?: URL } // Parent Directory Check: If not found, check one level - + // if (enableDebugErrors) console.warn(`[resolveImagePath] [WARN-${strategy}] Not found in "${basePath}". Checking parent directory.`); const parentBasePath = path.resolve(basePath, '..'); resolvedPath = checkFilePath(parentBasePath, src); @@ -101,7 +101,7 @@ export function resolveImagePath(src: string, entryPath?: string, astroUrl?: URL console.warn(`[resolveImagePath] [WARN-${strategy}] Final path check failed for "${src}". Base path checked: "${basePath}", Parent path checked: "${parentBasePath}"`); } } - + if (enableDebugErrors) { console.error(`[resolveImagePath] [FAILURE] Could not resolve relative path "${src}". Returning original.`); } diff --git a/packages/polymech/tsconfig.json b/packages/polymech/tsconfig.json index 244aa48..90fd960 100644 --- a/packages/polymech/tsconfig.json +++ b/packages/polymech/tsconfig.json @@ -12,6 +12,7 @@ "isolatedModules": true, // Astro will directly run your TypeScript code, no transpilation needed. "outDir": "./dist", + "rootDir": "src", "esModuleInterop": true, "skipLibCheck": true, "baseUrl": ".", @@ -43,9 +44,14 @@ }, "include": [ ".astro/types.d.ts", - "**/*.ts", - "**/*.tsx", - "**/*.astro" + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.astro" + ], + "exclude": [ + "src/components/sidebar/**/*", + "src/config/astro-config.ts", + "src/components/polymech/renderer.ts" ], "files": [ "src/index.ts" diff --git a/packages/polymech/vitest.config.ts b/packages/polymech/vitest.config.ts new file mode 100644 index 0000000..8f55c70 --- /dev/null +++ b/packages/polymech/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + resolve: { + alias: + { + "src/*": "/src/*", + "app/*": "/src/app/*", + }, + }, +}); \ No newline at end of file