@newlogic-digital/cli 1.5.0-next.1 → 1.5.0-next.2
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/index.mjs
CHANGED
|
@@ -6,10 +6,72 @@ import blocks from './src/commands/blocks/index.mjs'
|
|
|
6
6
|
import { styleText } from 'node:util'
|
|
7
7
|
import { version, name } from './src/utils.mjs'
|
|
8
8
|
|
|
9
|
+
const knownCommands = ['init', 'cms', 'blocks']
|
|
10
|
+
|
|
9
11
|
function normalizeOptionName(name) {
|
|
10
12
|
return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
function getLevenshteinDistance(left, right) {
|
|
16
|
+
const distances = Array.from({ length: left.length + 1 }, () => Array(right.length + 1).fill(0))
|
|
17
|
+
|
|
18
|
+
for (let row = 0; row <= left.length; row++) {
|
|
19
|
+
distances[row][0] = row
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (let column = 0; column <= right.length; column++) {
|
|
23
|
+
distances[0][column] = column
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (let row = 1; row <= left.length; row++) {
|
|
27
|
+
for (let column = 1; column <= right.length; column++) {
|
|
28
|
+
const substitutionCost = left[row - 1] === right[column - 1] ? 0 : 1
|
|
29
|
+
|
|
30
|
+
distances[row][column] = Math.min(
|
|
31
|
+
distances[row - 1][column] + 1,
|
|
32
|
+
distances[row][column - 1] + 1,
|
|
33
|
+
distances[row - 1][column - 1] + substitutionCost,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return distances[left.length][right.length]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getSuggestedCommand(command) {
|
|
42
|
+
const normalizedCommand = `${command ?? ''}`.trim().toLowerCase()
|
|
43
|
+
|
|
44
|
+
if (!normalizedCommand) {
|
|
45
|
+
return undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const suggestion = knownCommands
|
|
49
|
+
.map(candidate => ({ candidate, distance: getLevenshteinDistance(normalizedCommand, candidate) }))
|
|
50
|
+
.sort((left, right) => left.distance - right.distance)[0]
|
|
51
|
+
|
|
52
|
+
if (suggestion && suggestion.distance <= 2) {
|
|
53
|
+
return suggestion.candidate
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function printUnknownCommand(command) {
|
|
60
|
+
const suggestion = getSuggestedCommand(command)
|
|
61
|
+
const lines = [
|
|
62
|
+
`${styleText(['red', 'bold'], 'error')} Unknown command ${styleText(['yellow', 'bold'], `"${command}"`)}`,
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
if (suggestion) {
|
|
66
|
+
lines.push(`${styleText(['cyan', 'bold'], 'hint')} Did you mean ${styleText(['green', 'bold'], `"${suggestion}"`)}?`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
lines.push(`${styleText(['white', 'bold'], 'available')} ${knownCommands.map(command => styleText('green', command)).join(', ')}`)
|
|
70
|
+
lines.push(`${styleText(['cyan', 'bold'], 'help')} Run ${styleText('green', 'newlogic')} to see full usage`)
|
|
71
|
+
|
|
72
|
+
console.log(lines.join('\n'))
|
|
73
|
+
}
|
|
74
|
+
|
|
13
75
|
function parseCommandArgs(args) {
|
|
14
76
|
const positionals = []
|
|
15
77
|
const options = {}
|
|
@@ -97,6 +159,8 @@ if (!command) {
|
|
|
97
159
|
${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', 'header-nav-left hero-floating-text')}
|
|
98
160
|
${styleText('green', 'newlogic blocks update')}
|
|
99
161
|
`)
|
|
162
|
+
|
|
163
|
+
process.exit(0)
|
|
100
164
|
}
|
|
101
165
|
|
|
102
166
|
if (command === 'init') {
|
|
@@ -122,3 +186,8 @@ if (command === 'blocks') {
|
|
|
122
186
|
|
|
123
187
|
await blocks(action, names)
|
|
124
188
|
}
|
|
189
|
+
|
|
190
|
+
if (command && !knownCommands.includes(command)) {
|
|
191
|
+
printUnknownCommand(command)
|
|
192
|
+
process.exit(1)
|
|
193
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<section class="x-article-grid-horizontal grid grid-cols-container gap-y-12 md:gap-y-16 py-20 md:py-24 lg:py-28">
|
|
2
|
+
<div class="flex items-end gap-x-10 gap-y-6 w-full justify-between max-md:flex-col">
|
|
3
|
+
<div class="flex flex-col w-full lg:flex-1/2 items-start max-w-161">
|
|
4
|
+
<div class="x-badge mb-1 accent-main-secondary muted">
|
|
5
|
+
Section title
|
|
6
|
+
</div>
|
|
7
|
+
<h2 class="x-heading lg:lg mb-6">
|
|
8
|
+
Attention-grabbing medium length section headline
|
|
9
|
+
</h2>
|
|
10
|
+
<div class="x-text w-full">
|
|
11
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
12
|
+
Suspendisse varius enim in eros elementum tristique.
|
|
13
|
+
Duis cursus, mi quis viverra ornare, eros dolor interdum nulla.
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
<a href="#" class="x-button lg max-md:mr-auto">
|
|
17
|
+
View all
|
|
18
|
+
<svg class="me-auto size-5" aria-hidden="true">
|
|
19
|
+
<use href="#heroicons-mini/arrow-right"/>
|
|
20
|
+
</svg>
|
|
21
|
+
</a>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
24
|
+
{foreach range(1,$control->itemsCount ?? 6) as $i}
|
|
25
|
+
{include './ArticleItem.latte', itemVariant => $control->itemVariant, showAuthor => $control->showAuthor, lastHidden => true, mutedBadge => $control->itemVariant !== 'filled'}
|
|
26
|
+
{/foreach}
|
|
27
|
+
</div>
|
|
28
|
+
</section>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{default $lastHidden = false}
|
|
2
|
+
{default $itemVariant = 'basic'}
|
|
3
|
+
{default $mutedBadge = false}
|
|
4
|
+
{default $showAuthor = false}
|
|
5
|
+
|
|
6
|
+
<a
|
|
7
|
+
n:class="'x-article-item group flex flex-col', $lastHidden ? 'max-md:last:hidden lg:last:hidden'"
|
|
8
|
+
href="/article/detail.html"
|
|
9
|
+
>
|
|
10
|
+
<picture
|
|
11
|
+
n:class="
|
|
12
|
+
'x-image w-full before:skeleton aspect-310/207 md:aspect-310/207 lg:aspect-418/279 overflow-hidden',
|
|
13
|
+
$itemVariant === 'basic' ? 'rounded-2xl',
|
|
14
|
+
$itemVariant === 'outlined' ? 'rounded-t-2xl border-x border-t border-body-secondary',
|
|
15
|
+
$itemVariant === 'filled' ? 'rounded-t-2xl',
|
|
16
|
+
"
|
|
17
|
+
>
|
|
18
|
+
<source srcset="{=placeholder(345,431)}" media="(width < {$media->sm})">
|
|
19
|
+
<img
|
|
20
|
+
class="size-full object-cover group-hocus:scale-105 transition-transform"
|
|
21
|
+
src="{=placeholder(532,655)}"
|
|
22
|
+
alt=" " width="532" height="655" loading="lazy"
|
|
23
|
+
>
|
|
24
|
+
</picture>
|
|
25
|
+
<div
|
|
26
|
+
n:class="
|
|
27
|
+
'flex flex-col items-start pt-6 grow',
|
|
28
|
+
$itemVariant === 'outlined' ? 'rounded-b-2xl border-x border-b border-body-secondary px-6 pb-4',
|
|
29
|
+
$itemVariant === 'filled' ? 'bg-primary/5 px-6 pb-4 rounded-b-2xl',
|
|
30
|
+
"
|
|
31
|
+
>
|
|
32
|
+
<div class="flex gap-2 flex-wrap mb-3">
|
|
33
|
+
<div n:class="'x-badge sm', $mutedBadge ? 'muted' : ''">Article category</div>
|
|
34
|
+
<div class="x-badge sm muted bg-transparent" n:if="!$showAuthor">5 min read</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="x-heading xs mb-4 tracking-[-0.5px]">
|
|
37
|
+
Article title goes here
|
|
38
|
+
</div>
|
|
39
|
+
<div class="x-text text-main-secondary line-clamp-3 mb-4">
|
|
40
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.
|
|
41
|
+
</div>
|
|
42
|
+
<div class="grid grid-cols-[auto_1fr] mb-4 gap-x-4" n:if="$showAuthor">
|
|
43
|
+
<picture class="x-image before:skeleton size-12 rounded-full aspect-square shrink-0 row-span-2 overflow-hidden">
|
|
44
|
+
<img class="object-cover" src="{=placeholder(48,48)}" alt=" " width="48" height="48" loading="lazy">
|
|
45
|
+
</picture>
|
|
46
|
+
<span class="x-text sm font-medium self-end">Author Name</span>
|
|
47
|
+
<div class="flex gap-4">
|
|
48
|
+
<span class="x-text xs text-main-tertiary font-medium">04.12.2025</span>
|
|
49
|
+
<span class="x-text xs text-main-tertiary font-medium">5 min read</span>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<span class="x-button ghosted pl-1 mt-auto">
|
|
53
|
+
Read more
|
|
54
|
+
<svg class="me-auto size-5 group-hocus:translate-x-1 transition-transform" aria-hidden="true">
|
|
55
|
+
<use href="#heroicons-mini/arrow-right"/>
|
|
56
|
+
</svg>
|
|
57
|
+
</span>
|
|
58
|
+
</div>
|
|
59
|
+
</a>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<header class="x-header-nav-right h-(--x-header-height) grid grid-cols-container bg-body-primary sticky top-0 z-40">
|
|
2
|
+
<div class="flex items-center gap-1.5 md:gap-3">
|
|
3
|
+
<a href="#" class="shrink-0 max-lg:mr-auto lg:mr-7">
|
|
4
|
+
<img class="w-25 h-8" src="{placeholder(100,32)}" loading="lazy" alt="Logo">
|
|
5
|
+
</a>
|
|
6
|
+
<nav class="flex items-center flex-wrap justify-start gap-x-1 max-lg:hidden mr-auto">
|
|
7
|
+
<div class="x-popover trigger-hover group" n:foreach="range(1,4) as $item">
|
|
8
|
+
<a href="#" class="x-text x-link sm font-medium py-1 px-3 flex items-center gap-1.5">
|
|
9
|
+
Menu item {$iterator->counter}
|
|
10
|
+
<svg class="size-4 transition group-hocus:-scale-y-100" n:if="$iterator->last">
|
|
11
|
+
<use href="#heroicons-solid/chevron-down" />
|
|
12
|
+
</svg>
|
|
13
|
+
</a>
|
|
14
|
+
<div
|
|
15
|
+
n:class="
|
|
16
|
+
'x-nav-popover x-popover-content bottom-end border border-body-secondary shadow-lg min-w-55',
|
|
17
|
+
'm-1.5 p-4 flex flex-col gap-1 before:-top-2.5 before:h-2.5'
|
|
18
|
+
"
|
|
19
|
+
n:if="$iterator->last"
|
|
20
|
+
>
|
|
21
|
+
<a href="#" class="x-text x-link sm font-medium py-1 flex items-center gap-1.5" n:foreach="range(1,4) as $item">
|
|
22
|
+
Menu item
|
|
23
|
+
</a>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</nav>
|
|
27
|
+
<div class="x-popover trigger-focus group">
|
|
28
|
+
<button class="x-text x-link sm font-medium py-1 px-3 flex items-center gap-1.5" type="button" tabindex="0">
|
|
29
|
+
<img
|
|
30
|
+
class="aspect-4/3 size-4"
|
|
31
|
+
src="https://cdn.jsdelivr.net/npm/flag-icons@7.5.0/flags/1x1/gb.svg"
|
|
32
|
+
alt="at"
|
|
33
|
+
loading="lazy"
|
|
34
|
+
>
|
|
35
|
+
EN
|
|
36
|
+
<svg class="size-4 transition group-focus-within:-scale-y-100">
|
|
37
|
+
<use href="#heroicons-solid/chevron-down" />
|
|
38
|
+
</svg>
|
|
39
|
+
</button>
|
|
40
|
+
<div class="x-popover-content bottom-end border border-body-secondary shadow-lg m-1.5 p-4 flex flex-col gap-1">
|
|
41
|
+
<a href="#" class="x-text x-link sm font-medium py-1 flex items-center gap-1.5" n:foreach="range(1,4) as $item">
|
|
42
|
+
<img
|
|
43
|
+
class="aspect-4/3 size-4"
|
|
44
|
+
src="https://cdn.jsdelivr.net/npm/flag-icons@7.5.0/flags/1x1/gb.svg"
|
|
45
|
+
alt="at"
|
|
46
|
+
loading="lazy"
|
|
47
|
+
>
|
|
48
|
+
English
|
|
49
|
+
</a>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<a href="#" class="x-button sm max-md:hidden">
|
|
53
|
+
Call to action
|
|
54
|
+
</a>
|
|
55
|
+
<button
|
|
56
|
+
class="x-button square sm lg:hidden group swap"
|
|
57
|
+
type="button"
|
|
58
|
+
data-invoke-action="x-drawer#toggle"
|
|
59
|
+
data-invoke-target="#navDrawer"
|
|
60
|
+
aria-controls="navDrawer"
|
|
61
|
+
aria-expanded="false"
|
|
62
|
+
>
|
|
63
|
+
<svg class="size-5 shrink-0 not-group-aria-expanded:opacity-100 group-aria-expanded:rotate-45" aria-hidden="true">
|
|
64
|
+
<use href="#heroicons-solid/bars-3"></use>
|
|
65
|
+
</svg>
|
|
66
|
+
<svg class="size-5 shrink-0 not-group-aria-expanded:-rotate-45 group-aria-expanded:opacity-100" aria-hidden="true">
|
|
67
|
+
<use href="#heroicons-solid/x-mark"></use>
|
|
68
|
+
</svg>
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
</header>
|