@newlogic-digital/core 4.0.0-rc.1 → 4.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/bin/newlogic-core.js +16 -0
  2. package/eslint-stylistic.json +380 -0
  3. package/icons/simpleicons/apple.svg +3 -0
  4. package/icons/simpleicons/facebook.svg +3 -0
  5. package/icons/simpleicons/google.svg +3 -0
  6. package/icons/simpleicons/instagram.svg +3 -0
  7. package/icons/simpleicons/linkedin.svg +1 -0
  8. package/icons/simpleicons/messenger.svg +3 -0
  9. package/icons/simpleicons/threads.svg +3 -0
  10. package/icons/simpleicons/whatsapp.svg +3 -0
  11. package/icons/simpleicons/x.svg +3 -0
  12. package/icons/simpleicons/youtube.svg +3 -0
  13. package/icons/solid/newlogic-logomark.svg +3 -0
  14. package/icons/solid/newlogic-logotype.svg +11 -0
  15. package/index.js +13 -5
  16. package/package.json +23 -11
  17. package/skills/figma-implement-design/SKILL.md +246 -0
  18. package/skills/figma-implement-design/agents/openai.yaml +14 -0
  19. package/skills/figma-implement-design/assets/figma-small.svg +3 -0
  20. package/skills/figma-implement-design/assets/figma.png +0 -0
  21. package/skills/figma-implement-design/assets/icon.svg +28 -0
  22. package/skills/newlogic-ui/SKILL.md +33 -0
  23. package/skills/newlogic-ui/references/assets-guide.md +126 -0
  24. package/skills/newlogic-ui/references/project-guide.md +25 -0
  25. package/skills/newlogic-ui/references/scripting-guide.md +38 -0
  26. package/skills/newlogic-ui/references/styling-guide.md +75 -0
  27. package/skills/newlogic-ui/references/templating-guide.md +106 -0
  28. package/skills/newlogic-ui/references/theme-guide.md +23 -0
  29. package/src/createEslintStylisticConfig.js +16 -0
  30. package/src/linkAgentSkills.js +83 -0
  31. package/stylelint-config.json +16 -0
  32. package/types/index.d.ts +17 -19
@@ -0,0 +1,106 @@
1
+ # Templating Guide
2
+
3
+ ## Layout
4
+
5
+ - Use `src/templates/layouts/default.latte` unless the user explicitly asks for another layout.
6
+ - Do NOT create a custom layout when the default layout already supports the change.
7
+
8
+ ## Data Sources
9
+
10
+ - Global data lives in `src/data/main.json`.
11
+ - In this repo, global layout sections are typically defined through `head` and `foot` arrays in `src/data/main.json`.
12
+ - Page data lives in `src/pages/*.json` and inherits global data.
13
+ - Section rendering is handled through `src/templates/utils/sections.latte`.
14
+ - Components referenced from page JSON are passed as `$control`.
15
+ - In this repo, `src/pages/*.json` is the composition layer for whole pages. Prefer assembling a page there instead of creating a wrapper `*Page.latte` component that just nests the entire page structure.
16
+ - Preserve the existing `head` and `foot` layout structure unless the user explicitly asks to change the layout contract.
17
+ - If a Figma page includes a site header or site footer, implement those designs in the existing `components/header/Header.latte` and `components/footer/Footer.latte` flow rather than moving them into `body`.
18
+
19
+ **Global layout data example:**
20
+
21
+ ```json
22
+ {
23
+ "head": [
24
+ { "src": "components/header/Header.latte" }
25
+ ],
26
+ "foot": [
27
+ { "src": "components/footer/Footer.latte" }
28
+ ]
29
+ }
30
+ ```
31
+
32
+ **Layout asset access example:**
33
+
34
+ ```latte
35
+ <link n:foreach="$assets->css->all as $url" href="{$url|asset}" rel="stylesheet">
36
+ <script src="{$assets->js->main|asset}" type="module"></script>
37
+ ```
38
+
39
+ ## JSON Rules
40
+
41
+ - Do NOT store CSS class strings in JSON.
42
+ - JSON should contain semantic values and content, NOT presentation classes.
43
+ - If a template depends on an optional flag such as `active`, `dropdown`, or variant switches, define that flag explicitly in JSON.
44
+ - Keep repeated global UI data in `src/data/main.json` rather than duplicating it across page JSON files.
45
+
46
+ ## Latte Rules
47
+
48
+ - Prefer direct access to existing variables such as `$control` and global layout data.
49
+ - Keep ad hoc `{var ...}` usage to a minimum.
50
+ - Use `{default}` for optional fallback values when needed.
51
+ - Do NOT combine `class` and `n:class` on the same element. Use one `n:class` expression that includes the base classes.
52
+
53
+ **`n:class` pattern:**
54
+
55
+ ```latte
56
+ <a n:class="'base classes ' . ($isActive ? 'active' : 'idle')">Link</a>
57
+ ```
58
+
59
+ **`{default}` pattern:**
60
+
61
+ ```latte
62
+ {default $disabled = false}
63
+ ```
64
+
65
+ ## Components
66
+
67
+ - Put reusable page sections in `src/templates/components/`.
68
+ - Keep component file names in PascalCase.
69
+ - If a component is rendered from page JSON, assume `$control` is the primary input object unless the existing local pattern clearly does something else.
70
+ - Match the current folder conventions such as `(sections)`, `(ui)`, `header/`, `footer/`, `dialog/`, or `cookieconsent/` before introducing a new grouping.
71
+ - Do NOT create a monolithic page wrapper component when the page can be expressed as multiple body sections in JSON.
72
+ - Prefer one component per visible section or repeated block, then compose those sections from `src/pages/*.json`.
73
+ - If an existing component already matches the Figma element, reuse that component instead of creating a specific duplicate.
74
+ - If a Figma element maps to an existing `(ui)` component such as `Pagination.latte`, `Button`, `Dialog`, `Toast`, or similar, extend that existing component if needed; do NOT create parallel specific versions like `ArticlesPagination.latte` unless the user explicitly asks for a separate component.
75
+
76
+ **Page JSON to component flow:**
77
+
78
+ ```json
79
+ {
80
+ "body": [
81
+ {
82
+ "src": "components/HeroSection.latte",
83
+ "heading": "Welcome",
84
+ "buttonText": "Get Started"
85
+ }
86
+ ]
87
+ }
88
+ ```
89
+
90
+ ```latte
91
+ {foreach $sections as $section}
92
+ {include ('../' . $section->src), control => $section}
93
+ {/foreach}
94
+ ```
95
+
96
+ ```latte
97
+ <section class="x-hero-section">
98
+ <h1 n:if="isset($control->heading)">{$control->heading}</h1>
99
+ </section>
100
+ ```
101
+
102
+ **Direct include pattern:**
103
+
104
+ ```latte
105
+ {include 'components/Button.latte', text: 'Click me'}
106
+ ```
@@ -0,0 +1,23 @@
1
+ # Theme Guide
2
+
3
+ ## Theme Files
4
+
5
+ - Main website theme tokens live in `src/styles/theme/main.css`.
6
+ - Keep website theme defaults in `@theme`.
7
+ - Extend the existing token system before inventing component-local hardcoded values.
8
+
9
+ ## Local Rules
10
+
11
+ - ALWAYS prefer semantic tokens over raw values in templates and components.
12
+ - If the design introduces a new shared color, spacing, or layout default, add or adjust the token in `src/styles/theme/main.css`.
13
+ - Reuse existing tokens such as `primary`, `main`, `body`, and status colors before creating new ones.
14
+ - Keep theme changes centralized instead of scattering hardcoded values across multiple component files.
15
+
16
+ **Common token usage:**
17
+
18
+ ```html
19
+ <div class="bg-primary text-primary-foreground">Primary Button</div>
20
+ <div class="bg-main text-main-foreground">Dark Section</div>
21
+ <div class="max-w-(--container-width)">Constrained content</div>
22
+ <div class="x-button accent-main">Primary text</div>
23
+ ```
@@ -0,0 +1,16 @@
1
+ import stylistic from '@stylistic/eslint-plugin'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
7
+ const outputPath = path.resolve(scriptDir, '..', 'eslint-stylistic.json')
8
+
9
+ fs.writeFileSync(outputPath, JSON.stringify({
10
+ rules: {
11
+ ...stylistic.configs.recommended.rules,
12
+ },
13
+ jsPlugins: [
14
+ '@stylistic/eslint-plugin',
15
+ ],
16
+ }, null, 2))
@@ -0,0 +1,83 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { styleText } from 'node:util'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { getPackageInfo } from 'vituum/utils/common.js'
6
+
7
+ const IS_WIN32 = process.platform === 'win32'
8
+ const { name } = getPackageInfo(new URL('../package.json', import.meta.url).href)
9
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
10
+ const packageRoot = path.resolve(scriptDir, '..')
11
+ const sourceSkillsDir = path.join(packageRoot, 'skills')
12
+ const projectRoot = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : null
13
+
14
+ function isSameSymlinkTarget(targetPath, expectedSourcePath) {
15
+ const currentTarget = fs.readlinkSync(targetPath)
16
+ const resolvedTarget = path.resolve(path.dirname(targetPath), currentTarget)
17
+
18
+ return resolvedTarget === expectedSourcePath
19
+ }
20
+
21
+ function getExistingTargetStat(targetPath) {
22
+ try {
23
+ return fs.lstatSync(targetPath)
24
+ }
25
+ catch (error) {
26
+ if (error?.code === 'ENOENT') {
27
+ return null
28
+ }
29
+
30
+ throw error
31
+ }
32
+ }
33
+
34
+ function createSkillSymlink(sourcePath, targetPath) {
35
+ const symlinkTarget = IS_WIN32
36
+ ? sourcePath
37
+ : path.relative(path.dirname(targetPath), sourcePath)
38
+ const symlinkType = IS_WIN32 ? 'junction' : 'dir'
39
+
40
+ fs.symlinkSync(symlinkTarget, targetPath, symlinkType)
41
+ }
42
+
43
+ if (!projectRoot || projectRoot === packageRoot || !fs.existsSync(sourceSkillsDir)) {
44
+ process.exit(0)
45
+ }
46
+
47
+ const targetSkillsDir = path.join(projectRoot, '.agents', 'skills')
48
+ const skillEntries = fs.readdirSync(sourceSkillsDir, { withFileTypes: true })
49
+ .filter(entry => entry.isDirectory())
50
+
51
+ if (skillEntries.length === 0) {
52
+ process.exit(0)
53
+ }
54
+
55
+ fs.mkdirSync(targetSkillsDir, { recursive: true })
56
+
57
+ let linkedCount = 0
58
+
59
+ for (const entry of skillEntries) {
60
+ const sourcePath = path.join(sourceSkillsDir, entry.name)
61
+ const targetPath = path.join(targetSkillsDir, entry.name)
62
+ const targetStat = getExistingTargetStat(targetPath)
63
+
64
+ if (targetStat) {
65
+ if (!targetStat.isSymbolicLink()) {
66
+ console.warn(`${styleText(['cyan', 'bold'], name)} ${styleText('yellow', `Skipping skill "${entry.name}" because "${targetPath}" already exists and is not a symlink.`)}`)
67
+ continue
68
+ }
69
+
70
+ if (isSameSymlinkTarget(targetPath, sourcePath)) {
71
+ continue
72
+ }
73
+
74
+ fs.unlinkSync(targetPath)
75
+ }
76
+
77
+ createSkillSymlink(sourcePath, targetPath)
78
+ linkedCount += 1
79
+ }
80
+
81
+ if (linkedCount > 0) {
82
+ console.info(`${styleText(['cyan', 'bold'], name)} ${styleText('green', `Linked ${linkedCount} skill${linkedCount === 1 ? '' : 's'} into "${targetSkillsDir}".`)}`)
83
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": [
3
+ "@stylistic/stylelint-config",
4
+ "stylelint-config-standard"
5
+ ],
6
+ "rules": {
7
+ "at-rule-no-unknown": [true, {"ignoreAtRules": ["layer", "tailwind", "theme", "utility", "variant", "custom-variant", "source"]}],
8
+ "length-zero-no-unit": [true, {"ignore": ["custom-properties"]}],
9
+ "number-max-precision": [4, { "ignoreProperties": "letter-spacing" }],
10
+ "property-no-unknown": [true, { "ignoreProperties": ["/^mso-/"]} ],
11
+ "import-notation": "string",
12
+ "media-feature-range-notation": null,
13
+ "nesting-selector-no-missing-scoping-root": null,
14
+ "no-invalid-position-declaration": null
15
+ }
16
+ }
package/types/index.d.ts CHANGED
@@ -1,23 +1,21 @@
1
- import {HeroiconsOptions} from "@newlogic-digital/vite-plugin-heroicons";
2
-
3
1
  interface Input {
4
- assets?: string[]
5
- pages?: string[]
6
- emails?: string[]
2
+ assets?: string[]
3
+ pages?: string[]
4
+ emails?: string[]
7
5
  }
8
6
 
9
7
  export interface PluginUserConfig {
10
- mode?: 'development' | 'production' | 'emails' | string
11
- format?: string[]
12
- input?: Input
13
- cert?: string
14
- codeSplitting?: import('rolldown').OutputOptions['codeSplitting']
15
- vituum?: import('vituum').UserConfig,
16
- css?: import('vite').CSSOptions
17
- cssInline?: import('@vituum/vite-plugin-css-inline').PluginUserConfig
18
- send?: import('@vituum/vite-plugin-send').PluginUserConfig
19
- tailwindcss?: import('@tailwindcss/vite').PluginOptions
20
- latte?: import('@vituum/vite-plugin-latte').PluginUserConfig
21
- twig?: import('@vituum/vite-plugin-twig').PluginUserConfig
22
- heroicons?: import('@newlogic-digital/vite-plugin-heroicons').HeroiconsOptions
23
- }
8
+ mode?: 'development' | 'production' | 'emails' | string
9
+ format?: string[]
10
+ input?: Input
11
+ cert?: string
12
+ codeSplitting?: import('rolldown').OutputOptions['codeSplitting']
13
+ vituum?: import('vituum').UserConfig
14
+ css?: import('vite').CSSOptions
15
+ cssInline?: import('@vituum/vite-plugin-css-inline').PluginUserConfig
16
+ send?: import('@vituum/vite-plugin-send').PluginUserConfig
17
+ tailwindcss?: import('@tailwindcss/vite').PluginOptions
18
+ latte?: import('@vituum/vite-plugin-latte').PluginUserConfig
19
+ twig?: import('@vituum/vite-plugin-twig').PluginUserConfig
20
+ heroicons?: import('@newlogic-digital/vite-plugin-heroicons').HeroiconsOptions
21
+ }