From 9cd1a491b9a83e3ff6f303d06e3462c1dd683405 Mon Sep 17 00:00:00 2001 From: Omar Ibrahim Date: Wed, 11 Mar 2026 11:41:48 -0500 Subject: [PATCH 01/55] refactor: utilize nuxt layers for configuration, shared features, and environment management --- .gitignore | 5 + apps/docs/.env | 15 +- apps/docs/.env.development | 16 -- apps/docs/.env.example | 21 +++ apps/docs/app/app.config.ts | 1 + apps/docs/app/assets/styles/tailwind.css | 1 + apps/docs/app/components/Announcer.vue | 8 +- apps/docs/app/components/ClientNavbar.vue | 17 +- .../PrimitiveCatalog/PrimitiveCatalog.vue | 8 +- apps/docs/app/composables/configuration.ts | 31 ---- apps/docs/app/layouts/default.vue | 14 +- apps/docs/app/pages/[...slug].vue | 16 +- apps/docs/app/pages/index.vue | 23 ++- apps/docs/env.public.ts | 40 ----- apps/docs/nuxt.config.ts | 131 ++------------ apps/docs/package.json | 1 + apps/docs/runtime.config.ts | 19 ++ apps/learn/.env | 12 +- apps/learn/.env.development | 15 -- apps/learn/.env.example | 16 ++ apps/learn/app/assets/styles/tailwind.css | 1 + apps/learn/app/composables/configuration.ts | 25 --- apps/learn/app/layouts/default.vue | 11 +- .../pages/learning-paths/[path]/[...slug].vue | 8 +- apps/learn/env.public.ts | 27 --- apps/learn/nuxt.config.ts | 168 +----------------- apps/learn/package.json | 1 + apps/netlogo/.env.example | 16 ++ apps/nettango/.env | 16 +- apps/nettango/.env.development | 7 - apps/nettango/.env.example | 16 ++ apps/nettango/nuxt.config.ts | 91 +--------- apps/nettango/package.json | 1 + package.json | 18 +- packages/nuxt-core/.env | 16 +- packages/nuxt-core/.env.development | 11 -- packages/nuxt-core/.env.example | 12 ++ .../nuxt-core/app/assets/website-meta.json | 22 --- .../nuxt-core/app/components/ClientNavbar.vue | 87 ++++----- .../app/composables/configuration.ts | 27 --- .../nuxt-core/app/composables/useWebsite.ts | 15 +- .../layers/mdc/app/components/MDCButton.vue | 9 + .../mdc/app/components/MDCContainer.vue | 5 + .../mdc/app/components/MDCErrorBanner.vue | 19 ++ .../layers/mdc/app/components/MDCIcon.vue | 10 ++ .../app/components/MDCUnstylizedHeading.vue | 13 ++ .../mdc/app/components/NetLogoCommand.vue | 5 + packages/nuxt-core/layers/mdc/nuxt.config.ts | 13 ++ .../app/components/MDCPrimitive.vue | 16 ++ .../app/components/PrimTooltip.vue | 21 ++- .../app/composables/usePrimitive.ts | 62 +++++++ .../primitive-tooltip/content.config.ts | 20 +++ .../layers/primitive-tooltip/nuxt.config.ts | 9 + .../nuxt-core}/markdown.config.ts | 144 ++++++++------- packages/nuxt-core/nuxt.config.ts | 32 +++- packages/nuxt-core/package.json | 9 +- packages/nuxt-core/runtime.config.schema.ts | 28 +++ yarn.lock | 152 ++++------------ 58 files changed, 690 insertions(+), 883 deletions(-) delete mode 100644 apps/docs/.env.development create mode 100644 apps/docs/.env.example create mode 100644 apps/docs/app/app.config.ts delete mode 100644 apps/docs/app/composables/configuration.ts delete mode 100644 apps/docs/env.public.ts create mode 100644 apps/docs/runtime.config.ts delete mode 100644 apps/learn/.env.development create mode 100644 apps/learn/.env.example delete mode 100644 apps/learn/app/composables/configuration.ts delete mode 100644 apps/learn/env.public.ts create mode 100644 apps/netlogo/.env.example delete mode 100644 apps/nettango/.env.development create mode 100644 apps/nettango/.env.example delete mode 100644 packages/nuxt-core/.env.development create mode 100644 packages/nuxt-core/.env.example delete mode 100644 packages/nuxt-core/app/assets/website-meta.json delete mode 100644 packages/nuxt-core/app/composables/configuration.ts create mode 100644 packages/nuxt-core/layers/mdc/app/components/MDCButton.vue create mode 100644 packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue create mode 100644 packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue create mode 100644 packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue create mode 100644 packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue create mode 100644 packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue create mode 100644 packages/nuxt-core/layers/mdc/nuxt.config.ts create mode 100644 packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue rename {apps/learn => packages/nuxt-core/layers/primitive-tooltip}/app/components/PrimTooltip.vue (87%) create mode 100644 packages/nuxt-core/layers/primitive-tooltip/app/composables/usePrimitive.ts create mode 100644 packages/nuxt-core/layers/primitive-tooltip/content.config.ts create mode 100644 packages/nuxt-core/layers/primitive-tooltip/nuxt.config.ts rename {apps/docs/lib/docs => packages/nuxt-core}/markdown.config.ts (56%) create mode 100644 packages/nuxt-core/runtime.config.schema.ts diff --git a/.gitignore b/.gitignore index 046c3210..23bef708 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,8 @@ packages/mustache/test-dist/ # should not be tracked GITIGNORE_* GITIGNORE_*/**/* + +.env +.env.local +.env.development +.env.production diff --git a/apps/docs/.env b/apps/docs/.env index 5f50f61a..3ef9e00e 100644 --- a/apps/docs/.env +++ b/apps/docs/.env @@ -1,16 +1,21 @@ +NUXT_TELEMETRY_DISABLED=true + PROJECT_ROOT="." +REPO_ROOT=../.. +VERSIONS_SRC="/versions.json" +EXTENSIONS_DIR="$REPO_ROOT/external/extensions" PRODUCT_NAME="NetLogo Documentation" +PRODUCT_DESCRIPTION="The official documentation for the NetLogo modeling environment, including user manuals, tutorials, and reference materials." +PRODUCT_KEYWORDS="NetLogo, Documentation, User Manual, Tutorials, Reference, Agent-Based Modeling, Simulation, Programming, Modeling Environment" PRODUCT_VERSION="7.0.3" PRODUCT_DISPLAY_NAME="7.0.3" PRODUCT_BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%SZ) PRODUCT_WEBSITE="https://docs.netlogo.org" -VERSIONS_SRC="/versions.json" - -REPO_ROOT=../.. -EXTENSIONS_DIR="$REPO_ROOT/external/extensions" - BUILD_LATEST=${BUILD_LATEST:-true} BUILD_REPO="git@github.com:NetLogo/docs.git" BUILD_BRANCH="main" + +# Enable for Development +NUXT_DEV_TOOLS=true diff --git a/apps/docs/.env.development b/apps/docs/.env.development deleted file mode 100644 index 9cf7197c..00000000 --- a/apps/docs/.env.development +++ /dev/null @@ -1,16 +0,0 @@ -# Development environment variables for better HMR -NUXT_DEV_TOOLS=true -NUXT_TELEMETRY_DISABLED=true - -PRODUCT_NAME="NetLogo Documentation" -PRODUCT_VERSION="7.0.3" -PRODUCT_DISPLAY_NAME="7.0.3" -PRODUCT_BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%SZ) -PRODUCT_WEBSITE="https://docs.netlogo.org" - -VERSIONS_SRC="/versions.json" - -REPO_ROOT=../.. -EXTENSIONS_DIR="$REPO_ROOT/external/extensions" - -BASE_PATH="" diff --git a/apps/docs/.env.example b/apps/docs/.env.example new file mode 100644 index 00000000..a2c3e98a --- /dev/null +++ b/apps/docs/.env.example @@ -0,0 +1,21 @@ +NUXT_TELEMETRY_DISABLED=true + +PROJECT_ROOT="." +REPO_ROOT=../.. +VERSIONS_SRC="/versions.json" +EXTENSIONS_DIR="$REPO_ROOT/external/extensions" + +PRODUCT_NAME="NetLogo Documentation" +PRODUCT_DESCRIPTION="The official documentation for the NetLogo modeling environment, including user manuals, tutorials, and reference materials." +PRODUCT_KEYWORDS="NetLogo, Documentation, User Manual, Tutorials, Reference, Agent-Based Modeling, Simulation, Programming, Modeling Environment" +PRODUCT_VERSION="7.0.3" +PRODUCT_DISPLAY_NAME="7.0.3" +PRODUCT_BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%SZ) +PRODUCT_WEBSITE="https://docs.netlogo.org" + +BUILD_LATEST=${BUILD_LATEST:-true} +BUILD_REPO="git@github.com:NetLogo/docs.git" +BUILD_BRANCH="main" + +# Enable for Development +# NUXT_DEV_TOOLS=true diff --git a/apps/docs/app/app.config.ts b/apps/docs/app/app.config.ts new file mode 100644 index 00000000..b2d0682c --- /dev/null +++ b/apps/docs/app/app.config.ts @@ -0,0 +1 @@ +export default defineAppConfig({}); diff --git a/apps/docs/app/assets/styles/tailwind.css b/apps/docs/app/assets/styles/tailwind.css index 2ccb9883..c790a779 100644 --- a/apps/docs/app/assets/styles/tailwind.css +++ b/apps/docs/app/assets/styles/tailwind.css @@ -6,4 +6,5 @@ @import 'tw-animate-css'; @source "../../../../../packages/vue-ui/src"; +@source "../../../../../packages/nuxt-core/"; @source "../../../content/**/*.md"; diff --git a/apps/docs/app/components/Announcer.vue b/apps/docs/app/components/Announcer.vue index bb8b603c..357fce1e 100644 --- a/apps/docs/app/components/Announcer.vue +++ b/apps/docs/app/components/Announcer.vue @@ -31,14 +31,18 @@ const fetcher = async () => { const { data: announcements } = await useLazyAsyncData('announcements', fetcher, { server: false }); const route = useRoute(); -const productInfo = useProductInfo(); +const { + public: { + website: { productVersion }, + }, +} = useRuntimeConfig(); const toast = useToast(); const visibleAnnouncements = computed(() => { if (!announcements.value) return []; return announcements.value.filter((item) => { - return item.appliesTo(route.path, productInfo.productVersion); + return item.appliesTo(route.path, productVersion); }); }); diff --git a/apps/docs/app/components/ClientNavbar.vue b/apps/docs/app/components/ClientNavbar.vue index 3a979316..e8ceccc5 100644 --- a/apps/docs/app/components/ClientNavbar.vue +++ b/apps/docs/app/components/ClientNavbar.vue @@ -28,7 +28,7 @@ @@ -57,8 +57,11 @@ import { useMediaQuery } from '@vueuse/core'; import { onMounted, ref, watch } from 'vue'; import { onVersionChange, pullVersionsFromSource } from '~~/shared/versions'; -const productInfo = useProductInfo(); -const runtimeInfo = useRuntimeInfo(); +const { + public: { + website: { productWebsite, productVersion, versionsSrc }, + }, +} = useRuntimeConfig(); interface NavbarLink { title: string; @@ -174,7 +177,7 @@ const arePathnamesCongruent = (windowPathname: string, candidatePathname: string pathname .split('/') .filter((p) => p.length > 0) - .filter((p) => p !== productInfo.productVersion) + .filter((p) => p !== productVersion) .map((p) => p.replace(/\$/, '')) .map((p) => p.trim().split('#')[0] ?? '') .join('/'); @@ -196,7 +199,7 @@ const isLinkParentActive = (link: NavbarLink, currentPath: string): boolean => { // Version selection const versions = ref>({ - [productInfo.productVersion]: { displayName: productInfo.productVersion }, + [productVersion]: { displayName: productVersion }, '7.0.2': { displayName: '7.0.2' }, '7.0.1': { displayName: '7.0.1' }, '7.0.0': { displayName: '7.0.0' }, @@ -223,14 +226,14 @@ const versions = ref>({ '1.0': { disabled: true }, }); -const selectedVersion = ref(productInfo.productVersion); +const selectedVersion = ref(productVersion); onMounted(() => { if (import.meta.client) { updateActiveStates(); handleMediaQueryChange(); setTimeout(async () => { - versions.value = await pullVersionsFromSource(versions.value, runtimeInfo.versionsSrc); + versions.value = await pullVersionsFromSource(versions.value, versionsSrc); }, 0); } }); diff --git a/apps/docs/app/components/PrimitiveCatalog/PrimitiveCatalog.vue b/apps/docs/app/components/PrimitiveCatalog/PrimitiveCatalog.vue index 19b52dc3..6a7f4814 100644 --- a/apps/docs/app/components/PrimitiveCatalog/PrimitiveCatalog.vue +++ b/apps/docs/app/components/PrimitiveCatalog/PrimitiveCatalog.vue @@ -28,7 +28,11 @@ import { wrapCacheLocalStorage } from '@repo/utils/lib/storage/cached-local-stor import { removeHtmlExtension } from '~/utils/url'; import type { CatalogItemData, PrimitiveCatalogProps, SideCatalogItem } from './types'; -const productInfo = useProductInfo(); +const { + public: { + website: { productVersion }, + }, +} = useRuntimeConfig(); const { dictionaryDisplayName, dictionaryHomeDirectory, indexFileURI, currentItemId, currentItemLabel, primRoot } = defineProps(); @@ -69,7 +73,7 @@ const { error, } = await useLazyAsyncData( indexFileURI, - wrapCacheLocalStorage([productInfo.productVersion, 'primitive-catalog', indexFileURI].join('-'), null, () => + wrapCacheLocalStorage([productVersion, 'primitive-catalog', indexFileURI].join('-'), null, () => fetcher(indexFileURI), ), { server: false }, diff --git a/apps/docs/app/composables/configuration.ts b/apps/docs/app/composables/configuration.ts deleted file mode 100644 index 7e54e7ac..00000000 --- a/apps/docs/app/composables/configuration.ts +++ /dev/null @@ -1,31 +0,0 @@ -function getEnvironmentVariable(key: string, defaultValue: T, showWarning: boolean = true): T { - const { public: config } = useRuntimeConfig(); - const value = (config[key] as T | undefined) ?? (process.env[key] as T | undefined); - - if (showWarning && !value) { - console.warn(`Environment variable ${key} is not set. Using default value: ${defaultValue}`); - } - - return value ?? defaultValue; -} - -function useProductInfo() { - return { - productName: getEnvironmentVariable('PRODUCT_NAME', 'NetLogo Documentation'), - productVersion: getEnvironmentVariable('PRODUCT_VERSION', '7.0.3'), - productDisplayName: getEnvironmentVariable('PRODUCT_DISPLAY_NAME', '7.0.3'), - productBuildDate: getEnvironmentVariable('PRODUCT_BUILD_DATE', new Date().toISOString()), - productWebsite: getEnvironmentVariable('PRODUCT_WEBSITE', 'https://docs.netlogo.org'), - isBeta: getEnvironmentVariable('PRODUCT_VERSION', '7.0.3').toLowerCase().includes('beta'), - }; -} - -function useRuntimeInfo() { - const productInfo = useProductInfo(); - return { - noAutogen: getEnvironmentVariable('NO_AUTOGEN', 'false', false), - versionsSrc: productInfo.productWebsite + getEnvironmentVariable('VERSIONS_SRC', '/versions.json'), - }; -} - -export { getEnvironmentVariable, useProductInfo, useRuntimeInfo }; diff --git a/apps/docs/app/layouts/default.vue b/apps/docs/app/layouts/default.vue index d0fa642d..ebb3332b 100644 --- a/apps/docs/app/layouts/default.vue +++ b/apps/docs/app/layouts/default.vue @@ -11,14 +11,18 @@ diff --git a/apps/docs/env.public.ts b/apps/docs/env.public.ts deleted file mode 100644 index c9b28cfa..00000000 --- a/apps/docs/env.public.ts +++ /dev/null @@ -1,40 +0,0 @@ -const publicEnvironmentVariablesKeys = [ - 'PRODUCT_NAME', - 'PRODUCT_VERSION', - 'PRODUCT_BUILD_DATE', - 'PRODUCT_DISPLAY_NAME', - 'PRODUCT_WEBSITE', - 'NO_AUTOGEN', - 'VERSIONS_SRC', -] as const; - -const NOT_REQUIRED_ENV_VARS = new Set(['NO_AUTOGEN']); - -const publicEnvironmentVariables = Object.fromEntries( - publicEnvironmentVariablesKeys.map((key) => [key, process.env[key]]), -); - -export function verifyEnvironmentVariables() { - for (const key of publicEnvironmentVariablesKeys) { - if (NOT_REQUIRED_ENV_VARS.has(key)) continue; - const res = process.env[key]; - if (!res || res.length === 0) { - throw new Error(`Missing required environment variable: ${key}`); - } - } - - const productVersion = process.env['PRODUCT_VERSION'] as string; - if (!/^\d/.test(productVersion)) { - throw new Error(`PRODUCT_VERSION must start with a digit: ${productVersion}`); - } - - const productWebsite = process.env['PRODUCT_WEBSITE'] as string; - if (productWebsite.endsWith('/')) { - throw new Error(`PRODUCT_WEBSITE must not end with a slash: ${productWebsite}`); - } - if (!/^https?:\/\//.test(productWebsite)) { - throw new Error(`PRODUCT_WEBSITE must start with http:// or https://: ${productWebsite}`); - } -} - -export { publicEnvironmentVariables }; diff --git a/apps/docs/nuxt.config.ts b/apps/docs/nuxt.config.ts index cf78de57..1fe9df0d 100644 --- a/apps/docs/nuxt.config.ts +++ b/apps/docs/nuxt.config.ts @@ -1,18 +1,16 @@ -import { deepMerge } from '@repo/utils/std/objects'; -import tailwindcss from '@tailwindcss/vite'; +import { addNuxtContentAssetsRoot } from '@repo/netlogo-docs/helpers'; +import type { DefineNuxtConfig } from 'nuxt/config'; import { getDocumentedExtensionBuilders } from '@repo/netlogo-docs/extension-docs'; -import { addNuxtContentAssetsRoot, getRoutes } from '@repo/netlogo-docs/helpers'; +import { deepMerge } from '@repo/utils/std/objects'; +import pdfOverrides from './nuxt.config.pdf'; +import { websiteConfigSchema } from './runtime.config'; + +import * as MarkdownConfig from '@repo/nuxt-core/markdown.config'; import autogenConfig from './lib/docs/autogen.config'; -import * as MarkdownConfig from './lib/docs/markdown.config'; import runDocsAutogen from './lib/docs/runDocsAutogen'; -import type { DefineNuxtConfig } from 'nuxt/config'; -import { publicEnvironmentVariables, verifyEnvironmentVariables } from './env.public'; -import pdfOverrides from './nuxt.config.pdf'; -import { vueUiSrc, vueUiStyles } from './turbo'; - type NuxtConfigInput = Parameters[0]; const basePath = process.env['BASE_PATH'] ?? '/'; @@ -22,69 +20,18 @@ const optionalPdfLayer = isUsingPdfConfig ? pdfOverrides : {}; if (isUsingPdfConfig) { console.info('[repo] Running with PDF generation configuration overrides'); } - -// https://nuxt.com/docs/api/configuration/nuxt-config - export default defineNuxtConfig( deepMerge( { - compatibilityDate: '2025-07-15', + extends: ['@repo/nuxt-core/nuxt.config.ts'], + app: { baseURL: basePath, - rootId: '__netlogo', - }, - devtools: { enabled: true }, - ssr: true, - // prettier-ignore - modules: [ - '@nuxtjs/sitemap', // Adds sitemap.xml - '@repo/nuxt-content-assets', // Local asset loading based on relative paths in Markdowns - '@nuxt/content', // Query, navigation, search, and rendering of Markdown files - '@nuxt/ui', // Reka-UI library for Nuxt - '@nuxt/icon', // Optimized icons with iconify - 'nuxt-svgo', // SVG loader from file - '@nuxt/eslint', // Linter - 'nuxt-gtag', // Google - 'nuxt-og-image', // Dynamic Open Graph image generation - 'nuxt-link-checker', // Link checking post-build - ], - site: { url: 'https://docs.netlogo.org', name: process.env['PRODUCT_NAME'] }, - css: ['~/assets/styles/main.scss', '~/assets/styles/tailwind.css', vueUiStyles], - colorMode: { - preference: 'light', - }, - - gtag: { - id: 'G-ZET3KSPLMC', - }, - - imports: { - autoImport: true, - transform: { - exclude: [/\bnode_modules\b/, /\b\.git\b/], - }, - }, - - $development: { - experimental: { - payloadExtraction: false, - }, }, - icon: { - mode: 'css', - cssLayer: 'base', - }, + ssr: true, components: [ - { - path: vueUiSrc, - global: true, - pattern: '**/*.vue', - ignore: ['**/examples/*.vue', '**/tests/*.vue'], - pathPrefix: false, - watch: true, - }, { path: '~/components', global: true, @@ -95,55 +42,22 @@ export default defineNuxtConfig( }, ], - ignore: ['.build/', '.latest/', '.static/', '.preview/'], - - svgo: { - customComponent: 'SvgImport', + gtag: { + id: 'G-ZET3KSPLMC', }, vite: { - plugins: [tailwindcss()], optimizeDeps: { include: ['@repo/vue-ui', ...MarkdownConfig.externalImports], }, - server: { - hmr: { - overlay: true, - }, - watch: { usePolling: true }, - }, }, content: { build: MarkdownConfig.buildOptions, - renderer: { - anchorLinks: false, - }, - watch: { enabled: false }, - }, - - contentAssets: { - imageSize: 'style attrs', - contentExtensions: 'md', - debug: true, - overrideStaticDimensions: false, - }, - - ogImage: { - defaults: { - extension: 'jpeg', - sharp: { - quality: 70, - }, - }, }, linkChecker: { excludeLinks: ['/*.pdf', `${basePath}NetLogo_User_Manual.pdf`], - skipInspections: ['no-baseless', 'no-underscores', 'trailing-slash'], - report: { - html: process.env['CHECK'] === 'true', - }, }, runtimeConfig: { @@ -152,20 +66,15 @@ export default defineNuxtConfig( title: ext.fullName, href: `/${ext.name.toLowerCase()}`, })), - ...publicEnvironmentVariables, + website: websiteConfigSchema.parse(process.env), }, }, hooks: { async ready() { - verifyEnvironmentVariables(); - - console.info(`[repo] Using @repo/vue-ui source path: ${vueUiSrc}`); - console.info(`[repo] Using @repo/vue-ui styles path: ${vueUiStyles}`); - - const noAutogen = process.env['NO_AUTOGEN'] === 'true'; - if (noAutogen === true) return; - await runDocsAutogen(); + if (process.env['NO_AUTOGEN'] !== 'true') { + await runDocsAutogen(); + } }, 'content:file:beforeParse'(ctx) { addNuxtContentAssetsRoot(ctx.file); @@ -173,15 +82,7 @@ export default defineNuxtConfig( }, nitro: { - static: true, - serveStatic: true, baseURL: basePath, - prerender: { - autoSubfolderIndex: false, - crawlLinks: true, - concurrency: 1, - routes: await getRoutes(), - }, }, }, optionalPdfLayer, diff --git a/apps/docs/package.json b/apps/docs/package.json index 7a20218a..3f3bad58 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -47,6 +47,7 @@ "@repo/typescript-config": "0.0.0", "@repo/utils": "0.0.0", "@repo/vue-ui": "1.0.0", + "@repo/nuxt-core": "0.0.0", "@tailwindcss/postcss": "^4.1.13", "@tailwindcss/vite": "^4.1.18", "@vueuse/core": "^14.1.0", diff --git a/apps/docs/runtime.config.ts b/apps/docs/runtime.config.ts new file mode 100644 index 00000000..9bf91b4b --- /dev/null +++ b/apps/docs/runtime.config.ts @@ -0,0 +1,19 @@ +import { websiteConfigSchema as rootWebsiteConfigSchema } from '@repo/nuxt-core/runtime.config.schema'; +import z from 'zod'; + +const extraWebsiteConfig = z + .object({ + VERSIONS_SRC: z.string().default('/versions.json'), + }) + .transform((data) => ({ + versionsSrc: data.VERSIONS_SRC, + })); + +const websiteConfigSchema = rootWebsiteConfigSchema + .transform((data) => ({ + ...data, + productIsBeta: data.productVersion.toLowerCase().includes('beta'), + })) + .and(extraWebsiteConfig); + +export { websiteConfigSchema }; diff --git a/apps/learn/.env b/apps/learn/.env index ff5c203f..598990f1 100644 --- a/apps/learn/.env +++ b/apps/learn/.env @@ -1,11 +1,15 @@ +NUXT_DEV_TOOLS=true +NUXT_TELEMETRY_DISABLED=true + PROJECT_ROOT="." +REPO_ROOT=../.. PRODUCT_NAME="NetLogo Learn Guide" +PRODUCT_DESCRIPTION="A comprehensive guide to learning NetLogo, the multi-agent programmable modeling environment." +PRODUCT_LONG_DESCRIPTION="The official learning resources for NetLogo, the multi-agent programmable modeling environment. Explore tutorials, documentation, and guides to get started with NetLogo and enhance your modeling skills." +PRODUCT_KEYWORDS="NetLogo, NetLogo Web, NetLogo 3D, Hubnet Web, Agent-based Modeling, Turtles, Learn, Guide, Tutorials, Documentation, Multi-agent modeling, Programming environment" +PRODUCT_BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%SZ) PRODUCT_WEBSITE="https://learn.netlogo.org" - -REPO_ROOT=../.. -EXTENSIONS_DIR="$REPO_ROOT/external/extensions" - BUILD_REPO="https://github.com/NetLogo/Helio.git" BUILD_BRANCH="deploy/learn" diff --git a/apps/learn/.env.development b/apps/learn/.env.development deleted file mode 100644 index 20016179..00000000 --- a/apps/learn/.env.development +++ /dev/null @@ -1,15 +0,0 @@ -# Development environment variables for better HMR -NUXT_DEV_TOOLS=true -NUXT_TELEMETRY_DISABLED=true - -PROJECT_ROOT="." - -PRODUCT_NAME="NetLogo Learn Guide" -PRODUCT_WEBSITE="https://learn.netlogo.org" - - -REPO_ROOT=../.. -EXTENSIONS_DIR="$REPO_ROOT/external/extensions" - -BUILD_REPO="https://github.com/NetLogo/Helio.git" -BUILD_BRANCH="deploy/learn" diff --git a/apps/learn/.env.example b/apps/learn/.env.example new file mode 100644 index 00000000..017b3265 --- /dev/null +++ b/apps/learn/.env.example @@ -0,0 +1,16 @@ +# Enable for Development +# NUXT_DEV_TOOLS=true +NUXT_TELEMETRY_DISABLED=true + +PROJECT_ROOT="." +REPO_ROOT=../.. + +PRODUCT_NAME="NetLogo Learn Guide" +PRODUCT_DESCRIPTION="A comprehensive guide to learning NetLogo, the multi-agent programmable modeling environment." +PRODUCT_LONG_DESCRIPTION="The official learning resources for NetLogo, the multi-agent programmable modeling environment. Explore tutorials, documentation, and guides to get started with NetLogo and enhance your modeling skills." +PRODUCT_KEYWORDS="NetLogo, NetLogo Web, NetLogo 3D, Hubnet Web, Agent-based Modeling, Turtles, Learn, Guide, Tutorials, Documentation, Multi-agent modeling, Programming environment" +PRODUCT_BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%SZ) +PRODUCT_WEBSITE="https://learn.netlogo.org" + +BUILD_REPO="https://github.com/NetLogo/Helio.git" +BUILD_BRANCH="deploy/learn" diff --git a/apps/learn/app/assets/styles/tailwind.css b/apps/learn/app/assets/styles/tailwind.css index 2ccb9883..c790a779 100644 --- a/apps/learn/app/assets/styles/tailwind.css +++ b/apps/learn/app/assets/styles/tailwind.css @@ -6,4 +6,5 @@ @import 'tw-animate-css'; @source "../../../../../packages/vue-ui/src"; +@source "../../../../../packages/nuxt-core/"; @source "../../../content/**/*.md"; diff --git a/apps/learn/app/composables/configuration.ts b/apps/learn/app/composables/configuration.ts deleted file mode 100644 index d25bfe90..00000000 --- a/apps/learn/app/composables/configuration.ts +++ /dev/null @@ -1,25 +0,0 @@ -function getEnvironmentVariable(key: string, defaultValue: T, showWarning: boolean = true): T { - const { public: config } = useRuntimeConfig(); - const value = (config[key] as T | undefined) ?? (process.env[key] as T | undefined); - - if (showWarning && !value) { - console.warn(`Environment variable ${key} is not set. Using default value: ${defaultValue}`); - } - - return value ?? defaultValue; -} - -function useProductInfo() { - return { - productName: getEnvironmentVariable('PRODUCT_NAME', 'NetLogo Learning'), - productWebsite: getEnvironmentVariable('PRODUCT_WEBSITE', 'https://learn.netlogo.org'), - }; -} - -function useRuntimeInfo() { - return { - noAutogen: getEnvironmentVariable('NO_AUTOGEN', 'false', false), - }; -} - -export { getEnvironmentVariable, useProductInfo, useRuntimeInfo }; diff --git a/apps/learn/app/layouts/default.vue b/apps/learn/app/layouts/default.vue index c4b4da00..0cbe2198 100644 --- a/apps/learn/app/layouts/default.vue +++ b/apps/learn/app/layouts/default.vue @@ -10,11 +10,14 @@ + + + + diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue b/packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue new file mode 100644 index 00000000..f7c84b6c --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue @@ -0,0 +1,5 @@ + diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue b/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue new file mode 100644 index 00000000..1c0c061b --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue @@ -0,0 +1,19 @@ + + + diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue b/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue new file mode 100644 index 00000000..e2926165 --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue @@ -0,0 +1,10 @@ + + + diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue b/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue new file mode 100644 index 00000000..a37c9da9 --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue @@ -0,0 +1,13 @@ + + + diff --git a/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue b/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue new file mode 100644 index 00000000..9858fff7 --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue @@ -0,0 +1,5 @@ + diff --git a/packages/nuxt-core/layers/mdc/nuxt.config.ts b/packages/nuxt-core/layers/mdc/nuxt.config.ts new file mode 100644 index 00000000..b5c3267a --- /dev/null +++ b/packages/nuxt-core/layers/mdc/nuxt.config.ts @@ -0,0 +1,13 @@ +export default defineNuxtConfig({ + mdc: { + components: { + map: { + icon: "MDCIcon", + container: "MDCContainer", + errorBanner: "MDCErrorBanner", + button: "MDCButton", + netlogoCommand: "NetLogoCommand", + }, + }, + }, +}); diff --git a/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue b/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue new file mode 100644 index 00000000..4919d504 --- /dev/null +++ b/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue @@ -0,0 +1,16 @@ + + + diff --git a/apps/learn/app/components/PrimTooltip.vue b/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue similarity index 87% rename from apps/learn/app/components/PrimTooltip.vue rename to packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue index 89b6bc90..9773fffb 100644 --- a/apps/learn/app/components/PrimTooltip.vue +++ b/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue @@ -1,4 +1,5 @@ diff --git a/apps/learn/app/components/mdc/components.ts b/apps/learn/app/components/mdc/components.ts deleted file mode 100644 index 1e56ff0c..00000000 --- a/apps/learn/app/components/mdc/components.ts +++ /dev/null @@ -1,17 +0,0 @@ -import MDCButton from './MDCButton.vue'; -import MDCContainer from './MDCContainer.vue'; -import MDCErrorBanner from './MDCErrorBanner.vue'; -import MDCIcon from './MDCIcon.vue'; -import MDCPrimitive from './MDCPrimitive.vue'; -import NetLogoCommand from './NetLogoCommand.vue'; - -const MDCComponents = { - Button: MDCButton, - Container: MDCContainer, - Icon: MDCIcon, - NetLogoCommand: NetLogoCommand, - ErrorBanner: MDCErrorBanner, - Primitive: MDCPrimitive, -}; - -export default MDCComponents; diff --git a/apps/learn/app/composables/usePrimitive.ts b/apps/learn/app/composables/usePrimitive.ts deleted file mode 100644 index 2264e58a..00000000 --- a/apps/learn/app/composables/usePrimitive.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Primitives } from '@repo/common-data'; - -export const usePrimitive = async ({ name }: { name: string }) => { - const { data, pending, error } = await useAsyncData(`primitive-${name}`, () => queryCollection('primitives').all(), { - deep: false, - server: true, - dedupe: 'defer', - transform: async (allPrimitivesData) => { - const primitives = Primitives.getInstance(allPrimitivesData[0]?.primitives ?? []); - const rawPrimitive = { ...primitives.getPrimByName(name) }; - - return rawPrimitive || null; - }, - }); - - const primitive = computed(() => { - if (!data.value) return null; - return data.value; - }); - - return { - primitive, - pending, - error, - }; -}; diff --git a/apps/nettango/app/assets/website-logo.ts b/apps/nettango/app/assets/website-logo.ts new file mode 100644 index 00000000..b320cc63 --- /dev/null +++ b/apps/nettango/app/assets/website-logo.ts @@ -0,0 +1,2 @@ +import WebsiteLogo from "@repo/vue-ui/assets/brands/NetTango-Logo.svg"; +export { WebsiteLogo }; diff --git a/packages/nuxt-core/app/components/ClientFooter.vue b/packages/nuxt-core/app/components/ClientFooter.vue index 4ba93372..2f2c526b 100644 --- a/packages/nuxt-core/app/components/ClientFooter.vue +++ b/packages/nuxt-core/app/components/ClientFooter.vue @@ -17,7 +17,6 @@ diff --git a/apps/learn/app/components/mdc/MDCButton.vue b/packages/nuxt-core/layers/mdc/app/components/MDCButton.global.vue similarity index 100% rename from apps/learn/app/components/mdc/MDCButton.vue rename to packages/nuxt-core/layers/mdc/app/components/MDCButton.global.vue diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCButton.vue b/packages/nuxt-core/layers/mdc/app/components/MDCButton.vue deleted file mode 100644 index ded2d246..00000000 --- a/packages/nuxt-core/layers/mdc/app/components/MDCButton.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue b/packages/nuxt-core/layers/mdc/app/components/MDCContainer.global.vue similarity index 100% rename from packages/nuxt-core/layers/mdc/app/components/MDCContainer.vue rename to packages/nuxt-core/layers/mdc/app/components/MDCContainer.global.vue diff --git a/apps/learn/app/components/mdc/MDCErrorBanner.vue b/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.global.vue similarity index 100% rename from apps/learn/app/components/mdc/MDCErrorBanner.vue rename to packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.global.vue diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue b/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue deleted file mode 100644 index 1c0c061b..00000000 --- a/packages/nuxt-core/layers/mdc/app/components/MDCErrorBanner.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/apps/learn/app/components/mdc/MDCIcon.vue b/packages/nuxt-core/layers/mdc/app/components/MDCIcon.global.vue similarity index 100% rename from apps/learn/app/components/mdc/MDCIcon.vue rename to packages/nuxt-core/layers/mdc/app/components/MDCIcon.global.vue diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue b/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue deleted file mode 100644 index e2926165..00000000 --- a/packages/nuxt-core/layers/mdc/app/components/MDCIcon.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.global.vue b/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.global.vue new file mode 100644 index 00000000..c27e9d82 --- /dev/null +++ b/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.global.vue @@ -0,0 +1,13 @@ + + + diff --git a/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue b/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue deleted file mode 100644 index a37c9da9..00000000 --- a/packages/nuxt-core/layers/mdc/app/components/MDCUnstylizedHeading.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/apps/learn/app/components/mdc/NetLogoCommand.vue b/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.global.vue similarity index 100% rename from apps/learn/app/components/mdc/NetLogoCommand.vue rename to packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.global.vue diff --git a/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue b/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue deleted file mode 100644 index 9858fff7..00000000 --- a/packages/nuxt-core/layers/mdc/app/components/NetLogoCommand.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/packages/nuxt-core/layers/mdc/nuxt.config.ts b/packages/nuxt-core/layers/mdc/nuxt.config.ts index b5c3267a..d899f9d7 100644 --- a/packages/nuxt-core/layers/mdc/nuxt.config.ts +++ b/packages/nuxt-core/layers/mdc/nuxt.config.ts @@ -2,11 +2,11 @@ export default defineNuxtConfig({ mdc: { components: { map: { - icon: "MDCIcon", - container: "MDCContainer", - errorBanner: "MDCErrorBanner", - button: "MDCButton", - netlogoCommand: "NetLogoCommand", + Icon: "MDCIcon", + Container: "MDCContainer", + ErrorBanner: "MDCErrorBanner", + Button: "MDCButton", + NetlogoCommand: "NetLogoCommand", }, }, }, diff --git a/apps/learn/app/components/mdc/MDCPrimitive.vue b/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.global.vue similarity index 100% rename from apps/learn/app/components/mdc/MDCPrimitive.vue rename to packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.global.vue diff --git a/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue b/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue deleted file mode 100644 index 4919d504..00000000 --- a/packages/nuxt-core/layers/primitive-tooltip/app/components/MDCPrimitive.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue b/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue index 9773fffb..62531cfb 100644 --- a/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue +++ b/packages/nuxt-core/layers/primitive-tooltip/app/components/PrimTooltip.vue @@ -1,5 +1,4 @@ - - {{ props.name }} + + {{ + props.name + }} @@ -108,15 +122,14 @@ * TODO: * - [ ] Reduce memory footprint * - [ ] Fix hydration issues - * - [ ] Figure out why MDC can't see the components */ -import { escapeHTML } from '@repo/utils/std/string'; -import { useNoPrimitive } from '../composables/usePrimitive'; +import { escapeHTML } from "@repo/utils/std/string"; +import { useNoPrimitive } from "../composables/usePrimitive"; defineOptions({ // Allowing client-side renderer to avoid SSR // hydration issues in the development server. - client: import.meta.dev ? true : false, + client: false, }); type Props = { @@ -125,18 +138,18 @@ type Props = { const props = defineProps(); -const isDisabled = inject('prim-tooltip-disabled', false); +const isNested = inject("prim-tooltip-nested", false); +provide("prim-tooltip-nested", true); -const { primitive } = isDisabled ? useNoPrimitive() : await usePrimitive({ name: props.name }); +const isDisabled = inject("prim-tooltip-disabled", false); -const isNested = inject('prim-tooltip-nested', false); -provide('prim-tooltip-nested', true); +const { primitive } = isDisabled ? useNoPrimitive() : await usePrimitive({ name: props.name }); const examples = computed(() => { return `
${ primitive.value?.examples ?.map( - (ex) => ` + (ex: string) => ` ${escapeHTML(ex)} @@ -144,12 +157,12 @@ const examples = computed(() => { `, ) - .join('') ?? '' + .join("") ?? "" }
`; }); const external = computed(() => { - return primitive.value?.url?.startsWith('http'); + return primitive.value?.url?.startsWith("http"); }); diff --git a/packages/nuxt-core/layers/primitive-tooltip/app/composables/usePrimitive.ts b/packages/nuxt-core/layers/primitive-tooltip/app/composables/usePrimitive.ts index 1c97fb30..4dec325f 100644 --- a/packages/nuxt-core/layers/primitive-tooltip/app/composables/usePrimitive.ts +++ b/packages/nuxt-core/layers/primitive-tooltip/app/composables/usePrimitive.ts @@ -1,25 +1,49 @@ import { Primitives } from "@repo/common-data"; +type Primitive = ReturnType | null; let primitives: Primitives | undefined = undefined; + +function convertRelativeMarkdownLinksToAbsolute(markdown: string, baseUrl: string): string { + const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g; + const convertedMarkdown = markdown.replace(markdownLinkRegex, (match, text, url) => { + if (!url.startsWith("http://") && !url.startsWith("https://")) { + const absoluteUrl = new URL(url, baseUrl).href; + return `[${text}](${absoluteUrl})`; + } + return match; + }); + + return convertedMarkdown; +} + +function parsePrimitive(prim: Primitive): Primitive { + if (!prim) return null; + if (prim.description) { + prim.description = convertRelativeMarkdownLinksToAbsolute( + prim.description, + "https://docs.netlogo.org/", + ); + } + + return prim; +} + export const usePrimitive = async ({ name }: { name: string }) => { if (import.meta.dev) { - if (typeof primitives === "undefined") { - const { data } = await useAsyncData("primitives", () => queryCollection("primitives").all(), { - deep: false, - server: true, - dedupe: "defer", - }); - - if (data.value) { - primitives = Primitives.getInstance(data.value[0]?.primitives ?? []); - } + const { data } = await useAsyncData("primitives", () => queryCollection("primitives").all(), { + deep: false, + server: true, + dedupe: "defer", + }); + + if (data.value) { + primitives = Primitives.getInstance(data.value[0]?.primitives ?? []); } + const prim = parsePrimitive(primitives?.getPrimByName(name)); + return { - primitive: computed(() => { - if (!primitives) return null; - return primitives.getPrimByName(name); - }), + primitive: computed(() => prim), pending: computed(() => typeof primitives === "undefined" && !primitives), error: computed(() => null), }; @@ -34,9 +58,9 @@ export const usePrimitive = async ({ name }: { name: string }) => { dedupe: "defer", transform: async (allPrimitivesData) => { const primitives = Primitives.getInstance(allPrimitivesData[0]?.primitives ?? []); - const rawPrimitive = { ...primitives.getPrimByName(name) }; + const prim = parsePrimitive(primitives.getPrimByName(name)); - return rawPrimitive || null; + return prim ?? null; }, }, ); diff --git a/packages/nuxt-core/nuxt.config.ts b/packages/nuxt-core/nuxt.config.ts index fb727400..3b921a8a 100644 --- a/packages/nuxt-core/nuxt.config.ts +++ b/packages/nuxt-core/nuxt.config.ts @@ -155,7 +155,14 @@ export const nuxtBaseConfig: NuxtBaseConfig = { linkChecker: { excludeLinks: ["/*.pdf"], - skipInspections: ["no-baseless", "no-underscores", "trailing-slash"], + skipInspections: [ + "no-baseless", + "no-underscores", + "trailing-slash", + "absolute-site-urls", + "no-uppercase-chars", + "no-non-ascii-chars", + ], report: { html: process.env["CHECK"] === "true", }, diff --git a/packages/vue-ui/src/components/nuxt/mdc/ProseA.vue b/packages/vue-ui/src/components/nuxt/mdc/ProseA.vue index 347d9838..66222fdd 100644 --- a/packages/vue-ui/src/components/nuxt/mdc/ProseA.vue +++ b/packages/vue-ui/src/components/nuxt/mdc/ProseA.vue @@ -5,21 +5,30 @@ + + diff --git a/apps/netlogo/app/composables/useNavigation.ts b/apps/netlogo/app/composables/useNavigation.ts index ab671647..2682fa6f 100644 --- a/apps/netlogo/app/composables/useNavigation.ts +++ b/apps/netlogo/app/composables/useNavigation.ts @@ -41,22 +41,25 @@ export function useNavigation() { }); }); - /** - * Get footer navigation items (items with in_footer = true) - */ - const footerLinks = computed(() => { - const links: Array<{ title: string; href: string }> = []; - navigationSections.value.forEach((section) => { - section.items - .filter((item) => item.in_footer) - .forEach((item) => { - links.push({ + const footerSections = computed(() => { + return navigationSections.value + .map((section) => { + const links = section.items + .filter((item) => item.in_footer) + .map((item) => ({ title: item.display_title, href: item.url, - }); - }); - }); - return links; + external: false, + })); + + return links.length > 0 + ? { + title: section.name, + links, + } + : null; + }) + .filter((section) => section !== null); }); /** @@ -83,7 +86,7 @@ export function useNavigation() { return { navigationSections, navbarLinks, - footerLinks, + footerSections, isLoading, error, fetchNavigation, From 0d1d47bbcc181619c9a233d19c641d7e53bb3a2f Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Fri, 23 Jan 2026 09:55:27 -0600 Subject: [PATCH 07/55] Add intro section onto index page --- apps/netlogo/app/components/Intro.vue | 82 +++++++++++++++++++++++++++ apps/netlogo/app/pages/index.vue | 18 +++++- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 apps/netlogo/app/components/Intro.vue diff --git a/apps/netlogo/app/components/Intro.vue b/apps/netlogo/app/components/Intro.vue new file mode 100644 index 00000000..318347e7 --- /dev/null +++ b/apps/netlogo/app/components/Intro.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/apps/netlogo/app/pages/index.vue b/apps/netlogo/app/pages/index.vue index 007c6332..2a480670 100644 --- a/apps/netlogo/app/pages/index.vue +++ b/apps/netlogo/app/pages/index.vue @@ -1,11 +1,25 @@ From 563b5f58e5d257e31909a8a024854b673f8997c8 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Thu, 29 Jan 2026 00:49:43 -0600 Subject: [PATCH 08/55] Add News and Social Media section on main page --- apps/netlogo/app/app.config.ts | 2 +- apps/netlogo/app/assets/styles/main.scss | 18 ++- apps/netlogo/app/components/ClientFooter.vue | 2 - apps/netlogo/app/components/Intro.vue | 19 ++- apps/netlogo/app/components/Newsfeed.vue | 144 +++++++++++++++++++ apps/netlogo/app/pages/index.vue | 18 ++- apps/netlogo/nuxt.config.ts | 15 ++ 7 files changed, 194 insertions(+), 24 deletions(-) create mode 100644 apps/netlogo/app/components/Newsfeed.vue diff --git a/apps/netlogo/app/app.config.ts b/apps/netlogo/app/app.config.ts index dc0faedf..6ff6ae89 100644 --- a/apps/netlogo/app/app.config.ts +++ b/apps/netlogo/app/app.config.ts @@ -6,7 +6,7 @@ export default defineAppConfig({ }, container: { - base: "max-w-[110ch] mx-auto px-0 mx-auto px-[var(--space-xl)] lg:px-0", + base: "max-w-[150ch] mx-auto px-0 mx-auto px-[var(--space-xl)] lg:px-0", }, breadcrumb: { diff --git a/apps/netlogo/app/assets/styles/main.scss b/apps/netlogo/app/assets/styles/main.scss index c68670f2..462b17e5 100644 --- a/apps/netlogo/app/assets/styles/main.scss +++ b/apps/netlogo/app/assets/styles/main.scss @@ -1,14 +1,22 @@ -@use 'sass:meta'; +@use "sass:meta"; @layer theme, base, components, website, utilities; @layer utilities { - @include meta.load-css('@repo/tailwind-config/scss/utilities.scss'); + @include meta.load-css("@repo/tailwind-config/scss/utilities.scss"); } @layer website { - @include meta.load-css('@repo/tailwind-config/scss/normalize.scss'); - @include meta.load-css('@repo/tailwind-config/scss/docs-theme.scss'); + @include meta.load-css("@repo/tailwind-config/scss/normalize.scss"); + + h1, + h2, + h3, + h4, + h5 { + margin-bottom: 0; + } + // @include meta.load-css('@repo/tailwind-config/scss/docs-theme.scss'); } -@include meta.load-css('@repo/vue-ui/styles.scss'); +@include meta.load-css("@repo/vue-ui/styles.scss"); diff --git a/apps/netlogo/app/components/ClientFooter.vue b/apps/netlogo/app/components/ClientFooter.vue index d28a47c1..7826575b 100644 --- a/apps/netlogo/app/components/ClientFooter.vue +++ b/apps/netlogo/app/components/ClientFooter.vue @@ -35,10 +35,8 @@ const currentYear = ref(new Date().getFullYear()); const hrefAriaLabel = computed(() => `Navigate to the homepage of ${meta.value.name}`); -// Fetch footer navigation from Directus const { footerSections, fetchNavigation } = useNavigation(); -// Calculate span based on number of sections (remaining space after brand section) const calculateSpan = (sectionCount: number) => { if (sectionCount === 0) return 10; return Math.floor(10 / sectionCount); diff --git a/apps/netlogo/app/components/Intro.vue b/apps/netlogo/app/components/Intro.vue index 318347e7..80ae92eb 100644 --- a/apps/netlogo/app/components/Intro.vue +++ b/apps/netlogo/app/components/Intro.vue @@ -20,23 +20,21 @@

- + --> + 100% Free
- +
@@ -47,6 +45,7 @@ + + diff --git a/apps/netlogo/app/pages/index.vue b/apps/netlogo/app/pages/index.vue index 2a480670..5065bb02 100644 --- a/apps/netlogo/app/pages/index.vue +++ b/apps/netlogo/app/pages/index.vue @@ -1,25 +1,31 @@ diff --git a/apps/netlogo/nuxt.config.ts b/apps/netlogo/nuxt.config.ts index cd69a855..573d539a 100644 --- a/apps/netlogo/nuxt.config.ts +++ b/apps/netlogo/nuxt.config.ts @@ -12,5 +12,20 @@ export default defineNuxtConfig( backendUrl: process.env.PUBLIC_BACKEND_URL || "https://backend.netlogo.org", }, }, + app: { + head: { + script: [ + { + src: "https://unpkg.com/bsky-embed/dist/bsky-embed.es.js", + type: "module", + }, + ], + }, + }, + vue: { + compilerOptions: { + isCustomElement: (tag: string) => tag === "bsky-embed", + }, + }, }), ); From 957cc0ca35c8fbcf2cc0241b4e27817e3d1035b5 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Thu, 29 Jan 2026 01:56:22 -0600 Subject: [PATCH 09/55] Fix initial Directus loading issue with async functions --- apps/netlogo/app/components/ClientFooter.vue | 5 +-- apps/netlogo/app/components/ClientNavbar.vue | 20 ++-------- apps/netlogo/app/composables/useNavigation.ts | 40 +++++-------------- apps/netlogo/app/pages/index.vue | 26 +++++------- 4 files changed, 27 insertions(+), 64 deletions(-) diff --git a/apps/netlogo/app/components/ClientFooter.vue b/apps/netlogo/app/components/ClientFooter.vue index 7826575b..597207d5 100644 --- a/apps/netlogo/app/components/ClientFooter.vue +++ b/apps/netlogo/app/components/ClientFooter.vue @@ -35,16 +35,15 @@ const currentYear = ref(new Date().getFullYear()); const hrefAriaLabel = computed(() => `Navigate to the homepage of ${meta.value.name}`); -const { footerSections, fetchNavigation } = useNavigation(); +const { footerSections } = await useNavigation(); const calculateSpan = (sectionCount: number) => { if (sectionCount === 0) return 10; return Math.floor(10 / sectionCount); }; -onMounted(async () => { +onMounted(() => { currentYear.value = new Date().getFullYear(); - await fetchNavigation(); }); diff --git a/apps/netlogo/app/components/ClientNavbar.vue b/apps/netlogo/app/components/ClientNavbar.vue index d969e3e2..358ab5c8 100644 --- a/apps/netlogo/app/components/ClientNavbar.vue +++ b/apps/netlogo/app/components/ClientNavbar.vue @@ -65,19 +65,10 @@ const handleMediaQueryChange = (): void => { } }; -// Use the navigation composable to fetch from Directus -const { navbarLinks: apiNavbarLinks, fetchNavigation, isLoading } = useNavigation(); - -// Default fallback navigation (shown while loading or on error) -const defaultNavbarLinks: NavbarLink[] = [ - { - title: "Home", - href: "/", - }, -]; +const { navbarLinks: apiNavbarLinks } = await useNavigation(); -// Reactive navbar links that update once API data is loaded -const navbarLinks = ref(defaultNavbarLinks); +// Reactive navbar links with active states +const navbarLinks = ref(apiNavbarLinks.value); const updateActiveStates = () => { navbarRef.value?.blur(); @@ -119,7 +110,6 @@ const isLinkParentActive = (link: NavbarLink, currentPath: string): boolean => { ); }; -// Watch for API data to load and update navbarLinks watch( apiNavbarLinks, (newLinks) => { @@ -131,10 +121,8 @@ watch( { immediate: true }, ); -onMounted(async () => { +onMounted(() => { if (import.meta.client) { - // Fetch navigation data from Directus - await fetchNavigation(); updateActiveStates(); handleMediaQueryChange(); } diff --git a/apps/netlogo/app/composables/useNavigation.ts b/apps/netlogo/app/composables/useNavigation.ts index 2682fa6f..3e1104de 100644 --- a/apps/netlogo/app/composables/useNavigation.ts +++ b/apps/netlogo/app/composables/useNavigation.ts @@ -9,14 +9,18 @@ export interface NavbarLink { active?: boolean; } -/** - * Composable to fetch and manage navigation data from the Directus backend - */ -export function useNavigation() { +export async function useNavigation() { const config = useRuntimeConfig(); const navigationSections = ref([]); - const isLoading = ref(true); - const error = ref(null); + + const { data } = await useAsyncData("nav-data", async () => { + const api = new NetLogoAPI(config.public.backendUrl as string); + return await api.getNavigationData(); + }); + + if (data.value) { + navigationSections.value = data.value.navigation_sections; + } /** * Transform API navigation sections into NavbarLink format @@ -62,33 +66,9 @@ export function useNavigation() { .filter((section) => section !== null); }); - /** - * Fetch navigation data from the Directus backend - */ - async function fetchNavigation() { - isLoading.value = true; - error.value = null; - - try { - const api = new NetLogoAPI(config.public.backendUrl as string); - const data = await api.getNavigationData(); - navigationSections.value = data.navigation_sections; - } catch (e) { - console.error("Failed to fetch navigation data:", e); - error.value = e instanceof Error ? e : new Error("Unknown error"); - // Fallback to default navigation - navigationSections.value = []; - } finally { - isLoading.value = false; - } - } - return { navigationSections, navbarLinks, footerSections, - isLoading, - error, - fetchNavigation, }; } diff --git a/apps/netlogo/app/pages/index.vue b/apps/netlogo/app/pages/index.vue index 5065bb02..2ea6f29c 100644 --- a/apps/netlogo/app/pages/index.vue +++ b/apps/netlogo/app/pages/index.vue @@ -7,25 +7,21 @@ From 753ed39dc9f022041adbfcf2907849be2f65599e Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Fri, 30 Jan 2026 11:46:27 -0600 Subject: [PATCH 10/55] Add in Get NetLogo and Community sections on home page --- apps/netlogo/app/app.config.ts | 33 +----- apps/netlogo/app/app.vue | 4 +- apps/netlogo/app/components/Community.vue | 79 +++++++++++++ apps/netlogo/app/components/GetNetLogo.vue | 78 +++++++++++++ apps/netlogo/app/components/Intro.vue | 74 ++++++------ apps/netlogo/app/components/Newsfeed.vue | 130 +++++++++++---------- apps/netlogo/app/pages/index.vue | 12 +- 7 files changed, 276 insertions(+), 134 deletions(-) create mode 100644 apps/netlogo/app/components/Community.vue create mode 100644 apps/netlogo/app/components/GetNetLogo.vue diff --git a/apps/netlogo/app/app.config.ts b/apps/netlogo/app/app.config.ts index 6ff6ae89..2fb4f73a 100644 --- a/apps/netlogo/app/app.config.ts +++ b/apps/netlogo/app/app.config.ts @@ -6,38 +6,7 @@ export default defineAppConfig({ }, container: { - base: "max-w-[150ch] mx-auto px-0 mx-auto px-[var(--space-xl)] lg:px-0", - }, - - breadcrumb: { - slots: { - list: "[&_li]:m-0! p-0", - }, - }, - - contentNavigation: { - slots: { - list: "mx-0 px-2 lg:mt-[var(--block-top)]", - listWithChildren: "px-0", - }, - }, - contentToc: { - slots: { - root: "px-0! w-full -mx-0", - trailing: "hidden", - title: - "w-full px-[var(--space-lg)] py-2 bg-[var(--secondary-heading-background-color)] text-[var(--secondary-heading-text-color)] w-full", - }, - }, - pageAside: { - slots: { - root: "pt-0", - }, - }, - blogPost: { - slots: { - footer: "p-4 sm:p-6", - }, + base: "max-w-[150ch] px-4 lg:px-12 mx-auto", }, }, }); diff --git a/apps/netlogo/app/app.vue b/apps/netlogo/app/app.vue index 81018a76..c90826e6 100644 --- a/apps/netlogo/app/app.vue +++ b/apps/netlogo/app/app.vue @@ -3,7 +3,9 @@ - + + + diff --git a/apps/netlogo/app/components/Community.vue b/apps/netlogo/app/components/Community.vue new file mode 100644 index 00000000..f9516bf5 --- /dev/null +++ b/apps/netlogo/app/components/Community.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/apps/netlogo/app/components/GetNetLogo.vue b/apps/netlogo/app/components/GetNetLogo.vue new file mode 100644 index 00000000..3cab1988 --- /dev/null +++ b/apps/netlogo/app/components/GetNetLogo.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/apps/netlogo/app/components/Intro.vue b/apps/netlogo/app/components/Intro.vue index 80ae92eb..82199cd4 100644 --- a/apps/netlogo/app/components/Intro.vue +++ b/apps/netlogo/app/components/Intro.vue @@ -1,46 +1,50 @@ From a25fed1e102e6bafd59d0ddda65eabe755d28e34 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 3 Feb 2026 23:19:02 -0600 Subject: [PATCH 11/55] Fix Intro section with appropriate turtles and NetLogo Icon --- apps/netlogo/app/components/Intro.vue | 44 +++++++++++-------- .../vue-ui/assets/brands/intro-turtles.svg | 26 +++++++++++ packages/vue-ui/assets/brands/logo-text.svg | 4 ++ 3 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 packages/vue-ui/assets/brands/intro-turtles.svg create mode 100644 packages/vue-ui/assets/brands/logo-text.svg diff --git a/apps/netlogo/app/components/Intro.vue b/apps/netlogo/app/components/Intro.vue index 82199cd4..645fd296 100644 --- a/apps/netlogo/app/components/Intro.vue +++ b/apps/netlogo/app/components/Intro.vue @@ -2,40 +2,47 @@
-
+
-
- -
- NetLogo - - Simulate, Explore, Understand - +
+ +
+
-
-

+

+

{{ description }}

-
-
+
+
- - 100% Free + 100% Free
-
@@ -48,7 +55,8 @@ + + diff --git a/apps/netlogo/app/pages/index.vue b/apps/netlogo/app/pages/index.vue index 388c5045..ce319ed5 100644 --- a/apps/netlogo/app/pages/index.vue +++ b/apps/netlogo/app/pages/index.vue @@ -1,5 +1,5 @@
diff --git a/apps/netlogo/app/components/GetNetLogo.vue b/apps/netlogo/app/components/GetNetLogo.vue index 1187154b..d9833c76 100644 --- a/apps/netlogo/app/components/GetNetLogo.vue +++ b/apps/netlogo/app/components/GetNetLogo.vue @@ -37,15 +37,15 @@
From 00f02e470d3c24a50c0f415de18e9dad6b780f85 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 10 Feb 2026 02:48:08 -0600 Subject: [PATCH 18/55] Add contact page with Directus content --- .../app/components/contact/ContactSection.vue | 24 +++++++++++++++++++ apps/netlogo/app/pages/contact.vue | 18 ++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 apps/netlogo/app/components/contact/ContactSection.vue create mode 100644 apps/netlogo/app/pages/contact.vue diff --git a/apps/netlogo/app/components/contact/ContactSection.vue b/apps/netlogo/app/components/contact/ContactSection.vue new file mode 100644 index 00000000..7abb6936 --- /dev/null +++ b/apps/netlogo/app/components/contact/ContactSection.vue @@ -0,0 +1,24 @@ + + + diff --git a/apps/netlogo/app/pages/contact.vue b/apps/netlogo/app/pages/contact.vue new file mode 100644 index 00000000..79c57583 --- /dev/null +++ b/apps/netlogo/app/pages/contact.vue @@ -0,0 +1,18 @@ + + + From b42ba3f5c57b4012606e3f7e06df6a64aa8e10df Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 10 Feb 2026 11:03:23 -0600 Subject: [PATCH 19/55] Fix metadata of contact page --- apps/netlogo/app/pages/contact.vue | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/netlogo/app/pages/contact.vue b/apps/netlogo/app/pages/contact.vue index 79c57583..06014f61 100644 --- a/apps/netlogo/app/pages/contact.vue +++ b/apps/netlogo/app/pages/contact.vue @@ -7,6 +7,14 @@ diff --git a/apps/netlogo/app/pages/announcements.vue b/apps/netlogo/app/pages/announcements.vue new file mode 100644 index 00000000..f87f9612 --- /dev/null +++ b/apps/netlogo/app/pages/announcements.vue @@ -0,0 +1,24 @@ + + + From 89871303c7493ffcf8cfd0ce18ac3ced63c8405a Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 17 Feb 2026 02:18:50 -0600 Subject: [PATCH 21/55] Implement about page with scoped styling --- .../app/components/about/AboutSection.vue | 49 +++++++++++++++++++ apps/netlogo/app/pages/about.vue | 24 +++++++++ 2 files changed, 73 insertions(+) create mode 100644 apps/netlogo/app/components/about/AboutSection.vue create mode 100644 apps/netlogo/app/pages/about.vue diff --git a/apps/netlogo/app/components/about/AboutSection.vue b/apps/netlogo/app/components/about/AboutSection.vue new file mode 100644 index 00000000..af726e11 --- /dev/null +++ b/apps/netlogo/app/components/about/AboutSection.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/apps/netlogo/app/pages/about.vue b/apps/netlogo/app/pages/about.vue new file mode 100644 index 00000000..309b94c1 --- /dev/null +++ b/apps/netlogo/app/pages/about.vue @@ -0,0 +1,24 @@ + + + From 3253e45dbf21ba48142f4c96b646a8d94bf9e1c5 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 17 Feb 2026 02:32:16 -0600 Subject: [PATCH 22/55] Fix responsiveness of videos --- apps/netlogo/app/components/about/AboutSection.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/netlogo/app/components/about/AboutSection.vue b/apps/netlogo/app/components/about/AboutSection.vue index af726e11..a8fa5aa7 100644 --- a/apps/netlogo/app/components/about/AboutSection.vue +++ b/apps/netlogo/app/components/about/AboutSection.vue @@ -45,5 +45,8 @@ defineProps<{ :deep(iframe) { margin-top: 1rem; + width: 100%; + aspect-ratio: 16 / 9; + height: auto; } From f2124d350e5e0d38a99fe9a01542a999bdc34785 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Wed, 18 Feb 2026 13:13:39 -0600 Subject: [PATCH 23/55] Create official news page --- .../app/components/news/NewsSection.vue | 56 +++++++++++++++++++ apps/netlogo/app/pages/news.vue | 24 ++++++++ 2 files changed, 80 insertions(+) create mode 100644 apps/netlogo/app/components/news/NewsSection.vue create mode 100644 apps/netlogo/app/pages/news.vue diff --git a/apps/netlogo/app/components/news/NewsSection.vue b/apps/netlogo/app/components/news/NewsSection.vue new file mode 100644 index 00000000..c50f7bea --- /dev/null +++ b/apps/netlogo/app/components/news/NewsSection.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/netlogo/app/pages/news.vue b/apps/netlogo/app/pages/news.vue new file mode 100644 index 00000000..65c422e5 --- /dev/null +++ b/apps/netlogo/app/pages/news.vue @@ -0,0 +1,24 @@ + + + From e07f8ff2104d8bd3af7432d3a041b90a0b248fe6 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Mon, 23 Feb 2026 13:30:23 -0600 Subject: [PATCH 24/55] Implement campaign page --- apps/netlogo/app/pages/campaign.vue | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 apps/netlogo/app/pages/campaign.vue diff --git a/apps/netlogo/app/pages/campaign.vue b/apps/netlogo/app/pages/campaign.vue new file mode 100644 index 00000000..e42d4931 --- /dev/null +++ b/apps/netlogo/app/pages/campaign.vue @@ -0,0 +1,24 @@ + + + From 22c769a75c2fa5f4aac85c7775356d0886037bac Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 24 Feb 2026 00:44:56 -0600 Subject: [PATCH 25/55] Fix campaign page title layout --- apps/netlogo/app/components/about/AboutSection.vue | 3 ++- apps/netlogo/app/pages/campaign.vue | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/netlogo/app/components/about/AboutSection.vue b/apps/netlogo/app/components/about/AboutSection.vue index a8fa5aa7..9749e5a3 100644 --- a/apps/netlogo/app/components/about/AboutSection.vue +++ b/apps/netlogo/app/components/about/AboutSection.vue @@ -21,10 +21,11 @@ defineProps<{ :deep(h1) { font-size: 2.5rem; - line-height: 2.5rem; + line-height: 3rem; font-weight: 500; margin-top: 1.5rem; margin-bottom: 1rem; + /* text-align: center; */ } :deep(h2) { diff --git a/apps/netlogo/app/pages/campaign.vue b/apps/netlogo/app/pages/campaign.vue index e42d4931..7125cb74 100644 --- a/apps/netlogo/app/pages/campaign.vue +++ b/apps/netlogo/app/pages/campaign.vue @@ -10,9 +10,7 @@ import NetLogoAPI from "~/utils/api"; useHead({ title: "NetLogo Center Campaign", titleTemplate: "%s", - meta: [ - { name: "description", content: "About The NetLogo Center Campaign" }, - ], + meta: [{ name: "description", content: "About The NetLogo Center Campaign" }], }); const config = useRuntimeConfig(); @@ -22,3 +20,9 @@ const { data: campaignData } = await useAsyncData("campaign-data", async () => { return await api.getCampaignContent(); }); + + From bcd0ce269659b391e6c3b35fb5c982fab71d1d78 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 24 Feb 2026 02:47:50 -0600 Subject: [PATCH 26/55] Implement donate page --- .../components/downloads/DonationSection.vue | 47 +++++++++++++++++++ apps/netlogo/app/pages/donate.vue | 24 ++++++++++ 2 files changed, 71 insertions(+) create mode 100644 apps/netlogo/app/components/downloads/DonationSection.vue create mode 100644 apps/netlogo/app/pages/donate.vue diff --git a/apps/netlogo/app/components/downloads/DonationSection.vue b/apps/netlogo/app/components/downloads/DonationSection.vue new file mode 100644 index 00000000..4f22a153 --- /dev/null +++ b/apps/netlogo/app/components/downloads/DonationSection.vue @@ -0,0 +1,47 @@ + + + diff --git a/apps/netlogo/app/pages/donate.vue b/apps/netlogo/app/pages/donate.vue new file mode 100644 index 00000000..a6e42d17 --- /dev/null +++ b/apps/netlogo/app/pages/donate.vue @@ -0,0 +1,24 @@ + + + From cc0329d37228a44f0135ea63e9c8142d5691b63b Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Tue, 24 Feb 2026 13:36:08 -0600 Subject: [PATCH 27/55] Create download thank you page --- .../components/downloads/ThankYouSection.vue | 40 +++++++++++++++++++ apps/netlogo/app/pages/thankyou.vue | 23 +++++++++++ 2 files changed, 63 insertions(+) create mode 100644 apps/netlogo/app/components/downloads/ThankYouSection.vue create mode 100644 apps/netlogo/app/pages/thankyou.vue diff --git a/apps/netlogo/app/components/downloads/ThankYouSection.vue b/apps/netlogo/app/components/downloads/ThankYouSection.vue new file mode 100644 index 00000000..fd8cc91f --- /dev/null +++ b/apps/netlogo/app/components/downloads/ThankYouSection.vue @@ -0,0 +1,40 @@ + + + diff --git a/apps/netlogo/app/pages/thankyou.vue b/apps/netlogo/app/pages/thankyou.vue new file mode 100644 index 00000000..9486c274 --- /dev/null +++ b/apps/netlogo/app/pages/thankyou.vue @@ -0,0 +1,23 @@ + + + From 71f59960c1ccae91040659aeed2f91a23b4ac2bd Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Wed, 25 Feb 2026 00:48:53 -0600 Subject: [PATCH 28/55] Create base download page with proper access to navigator --- apps/netlogo/app/pages/download.vue | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 apps/netlogo/app/pages/download.vue diff --git a/apps/netlogo/app/pages/download.vue b/apps/netlogo/app/pages/download.vue new file mode 100644 index 00000000..f2703b10 --- /dev/null +++ b/apps/netlogo/app/pages/download.vue @@ -0,0 +1,29 @@ + + + From b28d7163e7d92a3be00cdcd2d56ecd6ea7ebd43d Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Wed, 25 Feb 2026 12:16:56 -0600 Subject: [PATCH 29/55] Base framework of download page for windows --- apps/netlogo/app/pages/downloads/windows.vue | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 apps/netlogo/app/pages/downloads/windows.vue diff --git a/apps/netlogo/app/pages/downloads/windows.vue b/apps/netlogo/app/pages/downloads/windows.vue new file mode 100644 index 00000000..5cf959cc --- /dev/null +++ b/apps/netlogo/app/pages/downloads/windows.vue @@ -0,0 +1,35 @@ + + + From 8e1d6d55e0b8b7588c799fbc06babe4fd5c3a917 Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Wed, 25 Feb 2026 13:03:23 -0600 Subject: [PATCH 30/55] Implement machine help section with manual link styling --- .../downloads/DownloadMachineHelp.vue | 34 +++++++++++++++++++ apps/netlogo/app/pages/downloads/windows.vue | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 apps/netlogo/app/components/downloads/DownloadMachineHelp.vue diff --git a/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue b/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue new file mode 100644 index 00000000..8c0d6039 --- /dev/null +++ b/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue @@ -0,0 +1,34 @@ + + + diff --git a/apps/netlogo/app/pages/downloads/windows.vue b/apps/netlogo/app/pages/downloads/windows.vue index 5cf959cc..437828c8 100644 --- a/apps/netlogo/app/pages/downloads/windows.vue +++ b/apps/netlogo/app/pages/downloads/windows.vue @@ -3,7 +3,7 @@ - Date: Wed, 25 Feb 2026 13:49:16 -0600 Subject: [PATCH 31/55] Add in download section framework with updated CCL links --- .../downloads/DownloadMachineHelp.vue | 48 +++++++++-------- .../components/downloads/DownloadSection.vue | 54 +++++++++++++++++++ 2 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 apps/netlogo/app/components/downloads/DownloadSection.vue diff --git a/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue b/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue index 8c0d6039..1d8c1d9a 100644 --- a/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue +++ b/apps/netlogo/app/components/downloads/DownloadMachineHelp.vue @@ -1,27 +1,29 @@ From f099d6d7b23debe78fc4c99f048efa1b6cbbb6cc Mon Sep 17 00:00:00 2001 From: danielwong0115 Date: Thu, 26 Feb 2026 01:30:38 -0600 Subject: [PATCH 32/55] Initial implementation of download form --- .../app/components/downloads/DownloadForm.vue | 280 ++++++++++++++++++ .../components/downloads/DownloadSection.vue | 2 +- 2 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 apps/netlogo/app/components/downloads/DownloadForm.vue diff --git a/apps/netlogo/app/components/downloads/DownloadForm.vue b/apps/netlogo/app/components/downloads/DownloadForm.vue new file mode 100644 index 00000000..7d63fcba --- /dev/null +++ b/apps/netlogo/app/components/downloads/DownloadForm.vue @@ -0,0 +1,280 @@ +