tsoft-cli 3.12.0 → 3.12.1
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/CHANGELOG.md +5 -0
- package/locales/en.json +2 -0
- package/locales/tr.json +2 -0
- package/package.json +1 -1
- package/src/commands/theme-dev.js +2 -1
- package/src/commands/theme.js +15 -7
- package/src/ui/theme-choice.js +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,11 @@ All notable changes to T-Soft CLI will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.12.1] - 2026-08-08
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Theme lists no longer call two different things "active". Standing inside a theme directory and running `tsoft theme use` named that theme on one line and then marked a different one as active in the list below it. The mark was reading which theme is published on the storefront, while the line above was reading the theme you are working on — both were correct, and both were called active. The theme you are working on is now marked `(Selected)` and the one your customers see is marked `(Published)`, so a list can show both without the two contradicting each other. `theme list`, `theme pull` and `theme dev` use the same two marks.
|
|
12
|
+
|
|
8
13
|
## [3.12.0] - 2026-08-05
|
|
9
14
|
|
|
10
15
|
### Added
|
package/locales/en.json
CHANGED
|
@@ -133,6 +133,8 @@
|
|
|
133
133
|
"theme.use.select_title": "🎯 Theme Selection",
|
|
134
134
|
"theme.use.set": "✓ Active theme set: {{name}}",
|
|
135
135
|
"theme.use.folder": "Folder: {{folder}}",
|
|
136
|
+
"theme.mark.selected": "(Selected)",
|
|
137
|
+
"theme.mark.published": "(Published)",
|
|
136
138
|
"push.no_active_theme": "No active theme found.",
|
|
137
139
|
"push.usage": "Usage: tsoft theme push <theme-name>",
|
|
138
140
|
"push.use_tip": "Or set an active theme with \"tsoft theme use <theme-name>\".",
|
package/locales/tr.json
CHANGED
|
@@ -133,6 +133,8 @@
|
|
|
133
133
|
"theme.use.select_title": "🎯 Tema Seçimi",
|
|
134
134
|
"theme.use.set": "✓ Aktif tema ayarlandı: {{name}}",
|
|
135
135
|
"theme.use.folder": "Klasör: {{folder}}",
|
|
136
|
+
"theme.mark.selected": "(Seçili)",
|
|
137
|
+
"theme.mark.published": "(Yayında)",
|
|
136
138
|
"push.no_active_theme": "Aktif tema bulunamadı.",
|
|
137
139
|
"push.usage": "Kullanim: tsoft theme push <theme-name>",
|
|
138
140
|
"push.use_tip": "veya \"tsoft theme use <theme-name>\" ile aktif tema ayarlayın.",
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import chokidar from 'chokidar';
|
|
|
7
7
|
import {createApiClient} from '../api-client.js';
|
|
8
8
|
import open from 'open';
|
|
9
9
|
import {normalizeStoreDomain, slugify, setActiveTheme, getActiveTheme, getActiveStore, getWorkspaceRoot} from '../storage.js';
|
|
10
|
+
import {decorateThemeName} from '../ui/theme-choice.js';
|
|
10
11
|
import {brandedConfirm, brandedSelect, showWarning, showError, showInfo} from '../ui/prompt-wrapper.js';
|
|
11
12
|
import {themeSectionMenuCommand} from './theme-section.js';
|
|
12
13
|
import { t } from '../i18n.js';
|
|
@@ -397,7 +398,7 @@ export async function themeDevCommand(themeName) {
|
|
|
397
398
|
|
|
398
399
|
console.log();
|
|
399
400
|
const themeChoices = themes.map(theme => ({
|
|
400
|
-
name:
|
|
401
|
+
name: decorateThemeName(theme, themeSlug),
|
|
401
402
|
value: theme,
|
|
402
403
|
description: theme.description || `Klasör: ${theme.theme_folder}`
|
|
403
404
|
}));
|
package/src/commands/theme.js
CHANGED
|
@@ -5,8 +5,9 @@ import {createWriteStream} from 'fs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import AdmZip from 'adm-zip';
|
|
7
7
|
import {createApiClient} from '../api-client.js';
|
|
8
|
-
import {normalizeStoreDomain, slugify, setActiveTheme, getActiveStore, getWorkspaceRoot, getWorkspaceContext} from '../storage.js';
|
|
8
|
+
import {normalizeStoreDomain, slugify, setActiveTheme, getActiveTheme, getActiveStore, getWorkspaceRoot, getWorkspaceContext} from '../storage.js';
|
|
9
9
|
import {brandedConfirm, brandedSelect, brandedSearch, showWarning} from '../ui/prompt-wrapper.js';
|
|
10
|
+
import {themeLabels, decorateThemeName} from '../ui/theme-choice.js';
|
|
10
11
|
import { isJsonMode, jsonOut } from '../output-mode.js';
|
|
11
12
|
import { mapError } from '../errors/error-mapper.js';
|
|
12
13
|
import { t } from '../i18n.js';
|
|
@@ -48,13 +49,16 @@ export async function themeListCommand() {
|
|
|
48
49
|
|
|
49
50
|
console.log(chalk.bold.cyan(t('theme.count', { count: themes.length }) + '\n'));
|
|
50
51
|
|
|
52
|
+
const localTheme = await getActiveTheme();
|
|
53
|
+
|
|
51
54
|
themes.forEach((theme) => {
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
+
const labels = themeLabels(theme, localTheme);
|
|
56
|
+
const indicator = labels.includes('selected')
|
|
57
|
+
? chalk.cyan('●')
|
|
58
|
+
: (labels.includes('published') ? chalk.green('●') : chalk.gray('○'));
|
|
55
59
|
const description = theme.description ? chalk.gray(` - ${theme.description}`) : '';
|
|
56
60
|
|
|
57
|
-
console.log(`${
|
|
61
|
+
console.log(`${indicator} ${decorateThemeName(theme, localTheme)}${description}`);
|
|
58
62
|
console.log(chalk.gray(` ${t('theme.folder_label')} ${theme.theme_folder || theme.alias}`));
|
|
59
63
|
console.log();
|
|
60
64
|
});
|
|
@@ -349,8 +353,10 @@ export async function themePullCommand() {
|
|
|
349
353
|
return;
|
|
350
354
|
}
|
|
351
355
|
|
|
356
|
+
const localTheme = await getActiveTheme();
|
|
357
|
+
|
|
352
358
|
const themeChoices = themes.map(theme => ({
|
|
353
|
-
name:
|
|
359
|
+
name: decorateThemeName(theme, localTheme),
|
|
354
360
|
value: theme,
|
|
355
361
|
description: theme.description || `${t('theme.folder_label')} ${theme.theme_folder}`
|
|
356
362
|
}));
|
|
@@ -463,8 +469,10 @@ export async function themeUseCommand(themeName = null) {
|
|
|
463
469
|
process.exit(1);
|
|
464
470
|
}
|
|
465
471
|
} else {
|
|
472
|
+
const localTheme = await getActiveTheme();
|
|
473
|
+
|
|
466
474
|
const themeChoices = themes.map(theme => ({
|
|
467
|
-
name:
|
|
475
|
+
name: decorateThemeName(theme, localTheme),
|
|
468
476
|
value: theme,
|
|
469
477
|
description: theme.description || `${t('theme.folder_label')} ${theme.theme_folder}`,
|
|
470
478
|
keywords: [theme.theme_folder, theme.alias].filter(Boolean),
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { slugify } from '../storage.js';
|
|
3
|
+
import { t } from '../i18n.js';
|
|
4
|
+
|
|
5
|
+
export function themeLabels(theme, selectedTheme) {
|
|
6
|
+
const labels = [];
|
|
7
|
+
|
|
8
|
+
const folder = theme.theme_folder || theme.alias;
|
|
9
|
+
|
|
10
|
+
if (selectedTheme && (folder === selectedTheme || slugify(theme.name) === selectedTheme)) {
|
|
11
|
+
labels.push('selected');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (theme.active) {
|
|
15
|
+
labels.push('published');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return labels;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function decorateThemeName(theme, selectedTheme) {
|
|
22
|
+
const labels = themeLabels(theme, selectedTheme);
|
|
23
|
+
|
|
24
|
+
const name = labels.includes('selected')
|
|
25
|
+
? chalk.bold.cyan(theme.name)
|
|
26
|
+
: chalk.white(theme.name);
|
|
27
|
+
|
|
28
|
+
const marks = labels.map(label => label === 'selected'
|
|
29
|
+
? chalk.cyan(t('theme.mark.selected'))
|
|
30
|
+
: chalk.green(t('theme.mark.published')));
|
|
31
|
+
|
|
32
|
+
return [name, chalk.gray(`v${theme.version}`), ...marks].join(' ');
|
|
33
|
+
}
|