directify-cli 1.0.0 → 1.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "directify-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Official CLI tool for Directify - manage your directories, listings, categories, tags, and articles from the command line.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -0,0 +1,187 @@
1
+ import { Command } from 'commander';
2
+ import { api, resolveDirectory } from '../utils/api.js';
3
+ import { printTable, printJson, printSuccess, printError } from '../utils/output.js';
4
+ import ora from 'ora';
5
+
6
+ const pages = new Command('pages').description('Manage custom pages');
7
+
8
+ pages
9
+ .command('list')
10
+ .alias('ls')
11
+ .description('List all custom pages')
12
+ .option('-d, --directory <id>', 'Directory ID')
13
+ .option('--json', 'Output as JSON')
14
+ .action(async (opts) => {
15
+ const spinner = ora('Fetching pages...').start();
16
+ try {
17
+ const dir = resolveDirectory(opts);
18
+ const data = await api.get(`/directories/${dir}/pages`);
19
+ spinner.stop();
20
+ if (opts.json) {
21
+ printJson(data);
22
+ } else {
23
+ const items = data.data || data;
24
+ printTable(items, [
25
+ { key: 'id', label: 'ID' },
26
+ { key: 'title', label: 'Title', maxWidth: 40 },
27
+ { key: 'slug', label: 'Slug', maxWidth: 25 },
28
+ { key: 'placement', label: 'Placement' },
29
+ { key: 'is_published', label: 'Published' },
30
+ { key: 'order', label: 'Order' },
31
+ ]);
32
+ if (data.meta) {
33
+ console.log(`\nPage ${data.meta.current_page} of ${data.meta.last_page} (${data.meta.total} total)`);
34
+ }
35
+ }
36
+ } catch (err) {
37
+ spinner.stop();
38
+ printError(err.message);
39
+ process.exit(1);
40
+ }
41
+ });
42
+
43
+ pages
44
+ .command('get <id>')
45
+ .description('Get a specific page')
46
+ .option('-d, --directory <id>', 'Directory ID')
47
+ .action(async (id, opts) => {
48
+ try {
49
+ const dir = resolveDirectory(opts);
50
+ const data = await api.get(`/directories/${dir}/pages/${id}`);
51
+ printJson(data.data || data);
52
+ } catch (err) {
53
+ printError(err.message);
54
+ process.exit(1);
55
+ }
56
+ });
57
+
58
+ pages
59
+ .command('create')
60
+ .description('Create a new custom page')
61
+ .requiredOption('--title <title>', 'Page title')
62
+ .option('--slug <slug>', 'URL slug (auto-generated from title if not set)')
63
+ .option('--markdown <text>', 'Page content in markdown')
64
+ .option('--placement <type>', 'Where the link appears: navbar, footer, sidebar, unlisted (default: unlisted)')
65
+ .option('--order <n>', 'Sort order for navigation', '0')
66
+ .option('--seo-title <text>', 'SEO title')
67
+ .option('--seo-description <text>', 'SEO description')
68
+ .option('--external-url <url>', 'External URL (makes this a link, not a page)')
69
+ .option('--new-tab', 'Open external links in new tab')
70
+ .option('--unpublished', 'Create as unpublished')
71
+ .option('-d, --directory <id>', 'Directory ID')
72
+ .action(async (opts) => {
73
+ const spinner = ora('Creating page...').start();
74
+ try {
75
+ const dir = resolveDirectory(opts);
76
+ const body = { title: opts.title };
77
+ if (opts.slug) body.slug = opts.slug;
78
+ if (opts.markdown) body.markdown = opts.markdown;
79
+ if (opts.placement) body.placement = opts.placement;
80
+ if (opts.order) body.order = parseInt(opts.order, 10);
81
+ if (opts.externalUrl) {
82
+ body.is_external = true;
83
+ body.external_url = opts.externalUrl;
84
+ }
85
+ if (opts.newTab) body.new_tab = true;
86
+ if (opts.seoTitle || opts.seoDescription) {
87
+ body.seo = {};
88
+ if (opts.seoTitle) body.seo.title = opts.seoTitle;
89
+ if (opts.seoDescription) body.seo.description = opts.seoDescription;
90
+ }
91
+ body.is_published = !opts.unpublished;
92
+
93
+ const data = await api.post(`/directories/${dir}/pages`, body);
94
+ spinner.stop();
95
+ const result = data.data || data;
96
+ printSuccess(`Page created: ${result.title} (ID: ${result.id})`);
97
+ } catch (err) {
98
+ spinner.stop();
99
+ printError(err.message);
100
+ process.exit(1);
101
+ }
102
+ });
103
+
104
+ pages
105
+ .command('update <id>')
106
+ .description('Update a custom page')
107
+ .option('--title <title>', 'Page title')
108
+ .option('--slug <slug>', 'URL slug')
109
+ .option('--markdown <text>', 'Page content in markdown')
110
+ .option('--placement <type>', 'Where the link appears: navbar, footer, sidebar, unlisted')
111
+ .option('--order <n>', 'Sort order for navigation')
112
+ .option('--seo-title <text>', 'SEO title')
113
+ .option('--seo-description <text>', 'SEO description')
114
+ .option('--external-url <url>', 'External URL')
115
+ .option('--new-tab <bool>', 'Open in new tab (true/false)')
116
+ .option('--published <bool>', 'Published status (true/false)')
117
+ .option('-d, --directory <id>', 'Directory ID')
118
+ .action(async (id, opts) => {
119
+ const spinner = ora('Updating page...').start();
120
+ try {
121
+ const dir = resolveDirectory(opts);
122
+ const body = {};
123
+ if (opts.title) body.title = opts.title;
124
+ if (opts.slug) body.slug = opts.slug;
125
+ if (opts.markdown) body.markdown = opts.markdown;
126
+ if (opts.placement) body.placement = opts.placement;
127
+ if (opts.order !== undefined) body.order = parseInt(opts.order, 10);
128
+ if (opts.externalUrl) {
129
+ body.is_external = true;
130
+ body.external_url = opts.externalUrl;
131
+ }
132
+ if (opts.newTab !== undefined) body.new_tab = opts.newTab === 'true';
133
+ if (opts.published !== undefined) body.is_published = opts.published === 'true';
134
+ if (opts.seoTitle || opts.seoDescription) {
135
+ body.seo = {};
136
+ if (opts.seoTitle) body.seo.title = opts.seoTitle;
137
+ if (opts.seoDescription) body.seo.description = opts.seoDescription;
138
+ }
139
+
140
+ const data = await api.put(`/directories/${dir}/pages/${id}`, body);
141
+ spinner.stop();
142
+ printSuccess(`Page updated: ${data.data?.title || data.title}`);
143
+ } catch (err) {
144
+ spinner.stop();
145
+ printError(err.message);
146
+ process.exit(1);
147
+ }
148
+ });
149
+
150
+ pages
151
+ .command('delete <id>')
152
+ .description('Delete a custom page')
153
+ .option('-d, --directory <id>', 'Directory ID')
154
+ .action(async (id, opts) => {
155
+ const spinner = ora('Deleting page...').start();
156
+ try {
157
+ const dir = resolveDirectory(opts);
158
+ await api.delete(`/directories/${dir}/pages/${id}`);
159
+ spinner.stop();
160
+ printSuccess(`Page ${id} deleted.`);
161
+ } catch (err) {
162
+ spinner.stop();
163
+ printError(err.message);
164
+ process.exit(1);
165
+ }
166
+ });
167
+
168
+ pages
169
+ .command('toggle <id>')
170
+ .description('Toggle page published/unpublished status')
171
+ .option('-d, --directory <id>', 'Directory ID')
172
+ .action(async (id, opts) => {
173
+ const spinner = ora('Toggling page...').start();
174
+ try {
175
+ const dir = resolveDirectory(opts);
176
+ const data = await api.patch(`/directories/${dir}/pages/${id}/toggle`);
177
+ spinner.stop();
178
+ const result = data.data || data;
179
+ printSuccess(`Page "${result.title}" is now ${result.is_published ? 'published' : 'unpublished'}.`);
180
+ } catch (err) {
181
+ spinner.stop();
182
+ printError(err.message);
183
+ process.exit(1);
184
+ }
185
+ });
186
+
187
+ export default pages;
package/src/index.js CHANGED
@@ -9,6 +9,7 @@ import tags from './commands/tags.js';
9
9
  import fields from './commands/fields.js';
10
10
  import listings from './commands/listings.js';
11
11
  import articles from './commands/articles.js';
12
+ import pages from './commands/pages.js';
12
13
 
13
14
  const program = new Command();
14
15
 
@@ -25,5 +26,6 @@ program.addCommand(tags);
25
26
  program.addCommand(fields);
26
27
  program.addCommand(listings);
27
28
  program.addCommand(articles);
29
+ program.addCommand(pages);
28
30
 
29
31
  program.parse();