@newlogic-digital/core 4.0.0-next.9 → 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.
- package/bin/newlogic-core.js +16 -0
- package/eslint-stylistic.json +380 -0
- package/icons/simpleicons/apple.svg +3 -0
- package/icons/simpleicons/facebook.svg +3 -0
- package/icons/simpleicons/google.svg +3 -0
- package/icons/simpleicons/instagram.svg +3 -0
- package/icons/simpleicons/linkedin.svg +1 -0
- package/icons/simpleicons/messenger.svg +3 -0
- package/icons/simpleicons/threads.svg +3 -0
- package/icons/simpleicons/whatsapp.svg +3 -0
- package/icons/simpleicons/x.svg +3 -0
- package/icons/simpleicons/youtube.svg +3 -0
- package/icons/solid/newlogic-logomark.svg +3 -0
- package/icons/solid/newlogic-logotype.svg +11 -0
- package/index.js +38 -33
- package/package.json +32 -18
- package/skills/figma-implement-design/SKILL.md +246 -0
- package/skills/figma-implement-design/agents/openai.yaml +14 -0
- package/skills/figma-implement-design/assets/figma-small.svg +3 -0
- package/skills/figma-implement-design/assets/figma.png +0 -0
- package/skills/figma-implement-design/assets/icon.svg +28 -0
- package/skills/newlogic-ui/SKILL.md +33 -0
- package/skills/newlogic-ui/references/assets-guide.md +126 -0
- package/skills/newlogic-ui/references/project-guide.md +25 -0
- package/skills/newlogic-ui/references/scripting-guide.md +38 -0
- package/skills/newlogic-ui/references/styling-guide.md +75 -0
- package/skills/newlogic-ui/references/templating-guide.md +106 -0
- package/skills/newlogic-ui/references/theme-guide.md +23 -0
- package/src/createEslintStylisticConfig.js +16 -0
- package/src/linkAgentSkills.js +83 -0
- package/stylelint-config.json +16 -0
- package/types/index.d.ts +16 -15
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Styling Guide
|
|
2
|
+
|
|
3
|
+
## General
|
|
4
|
+
|
|
5
|
+
- ALWAYS prefer Tailwind utilities before writing custom CSS.
|
|
6
|
+
- Use custom CSS for defaults, complex states, or component-specific behavior that should NOT live in templates.
|
|
7
|
+
- Follow nearby files before introducing a new styling pattern.
|
|
8
|
+
- Prefer responsive utilities such as `sm:`, `md:`, and `lg:` in templates. Use `@custom-media` only when writing custom CSS.
|
|
9
|
+
|
|
10
|
+
**Custom breakpoint example:**
|
|
11
|
+
|
|
12
|
+
```css
|
|
13
|
+
.my-component {
|
|
14
|
+
padding: 1rem;
|
|
15
|
+
|
|
16
|
+
@media (--media-lg) {
|
|
17
|
+
padding: 2rem;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## UI Components
|
|
23
|
+
|
|
24
|
+
- Winduum-based UI components live in `src/styles/components/(ui)/`.
|
|
25
|
+
- UI component defaults belong in their CSS files, NOT in template utility piles.
|
|
26
|
+
- Define base sizing, padding, radius, font defaults, and default colors in CSS for UI components.
|
|
27
|
+
- In templates, only small layout utilities are allowed on UI components, such as width, flex, gap, order, or spacing adjustments.
|
|
28
|
+
- Do NOT redefine a UI component's base look directly in templates.
|
|
29
|
+
- Do NOT restyle existing `x-*` UI components from a large level CSS file when the change is really a button, badge, control, field, pagination, or other UI-component concern.
|
|
30
|
+
- If a Figma page introduces a new shared UI look, extend the relevant file in `src/styles/components/(ui)/` instead of creating specific overrides from a parent component for that component.
|
|
31
|
+
|
|
32
|
+
## Non-UI Components
|
|
33
|
+
|
|
34
|
+
- Regular non-UI components SHOULD be styled entirely with Tailwind utilities in the template by default.
|
|
35
|
+
- For non-UI components, prefer Tailwind even when the template gets longer. A longer utility-based template is still preferred over creating component CSS too early.
|
|
36
|
+
- Create component CSS for non-UI components ONLY when there is styling logic that genuinely should not live in the template, such as complex selectors, state relationships, pseudo-element composition, browser-specific behavior, or similarly non-trivial logic that cannot be expressed cleanly with Tailwind utilities alone.
|
|
37
|
+
- Do NOT create component CSS just to group utilities, shorten markup, or move ordinary layout/spacing/typography rules out of the template.
|
|
38
|
+
- Treat non-UI component CSS as a true last resort. It should be used only in genuinely exceptional cases, not as a convenience or organizational preference.
|
|
39
|
+
- If a non-UI component reaches that exceptional threshold and needs CSS, follow the `data-part` pattern for internal styling instead of inventing extra internal class names.
|
|
40
|
+
- Avoid large level CSS files that absorb layout, typography, and UI and other component styling at the same time. If a page file starts becoming the source of truth for `x-*` components, move that logic back into `(ui)` CSS and keep the page mostly utility-driven.
|
|
41
|
+
|
|
42
|
+
## Tokens And Units
|
|
43
|
+
|
|
44
|
+
- ALWAYS use theme tokens such as `text-primary`, `bg-main`, or `text-body-foreground` before raw color values.
|
|
45
|
+
- If the design needs a new default token, update `src/styles/theme/main.css`.
|
|
46
|
+
- Do NOT use `px` units, except `1px` or `2px` borders when needed.
|
|
47
|
+
|
|
48
|
+
## Component Parts
|
|
49
|
+
|
|
50
|
+
- This section applies primarily to non-UI components when CSS is truly unavoidable.
|
|
51
|
+
- Use `data-part` for stylable internal parts.
|
|
52
|
+
- Do NOT create extra part class names such as `x-card-header` or `x-hero-content` when `data-part` is sufficient.
|
|
53
|
+
- For non-UI components, `data-part` is the required internal styling pattern whenever an exceptional CSS case is justified.
|
|
54
|
+
|
|
55
|
+
**Preferred part pattern:**
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<div class="x-my-component">
|
|
59
|
+
<div data-part="header">...</div>
|
|
60
|
+
<div data-part="content">...</div>
|
|
61
|
+
</div>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
.x-my-component {
|
|
66
|
+
[data-part="header"] {
|
|
67
|
+
/* complex styles */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Winduum Extensions
|
|
73
|
+
|
|
74
|
+
- Inspect the imported Winduum files in the component CSS to see which custom properties are available.
|
|
75
|
+
- Extend Winduum components through their existing imports and local CSS layers instead of re-implementing them from scratch.
|
|
@@ -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,20 +1,21 @@
|
|
|
1
1
|
interface Input {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
assets?: string[]
|
|
3
|
+
pages?: string[]
|
|
4
|
+
emails?: string[]
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export interface PluginUserConfig {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
20
21
|
}
|