aztomiq 1.0.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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/bin/aztomiq.js +336 -0
  4. package/bin/create-aztomiq.js +77 -0
  5. package/package.json +58 -0
  6. package/scripts/analyze-screenshots.js +217 -0
  7. package/scripts/build.js +39 -0
  8. package/scripts/builds/admin.js +17 -0
  9. package/scripts/builds/assets.js +167 -0
  10. package/scripts/builds/cache.js +48 -0
  11. package/scripts/builds/config.js +31 -0
  12. package/scripts/builds/data.js +210 -0
  13. package/scripts/builds/pages.js +288 -0
  14. package/scripts/builds/playground-examples.js +50 -0
  15. package/scripts/builds/templates.js +118 -0
  16. package/scripts/builds/utils.js +37 -0
  17. package/scripts/create-bug-tracker.js +277 -0
  18. package/scripts/deploy.js +135 -0
  19. package/scripts/feedback-generator.js +102 -0
  20. package/scripts/ui-test.js +624 -0
  21. package/scripts/utils/extract-examples.js +44 -0
  22. package/scripts/utils/migrate-icons.js +67 -0
  23. package/src/includes/breadcrumbs.ejs +100 -0
  24. package/src/includes/cloud-tags.ejs +120 -0
  25. package/src/includes/footer.ejs +37 -0
  26. package/src/includes/generator.ejs +226 -0
  27. package/src/includes/head.ejs +73 -0
  28. package/src/includes/header-data-only.ejs +43 -0
  29. package/src/includes/header.ejs +71 -0
  30. package/src/includes/layout.ejs +68 -0
  31. package/src/includes/legacy-banner.ejs +19 -0
  32. package/src/includes/mega-menu.ejs +80 -0
  33. package/src/includes/schema.ejs +20 -0
  34. package/src/templates/manifest.json.ejs +30 -0
  35. package/src/templates/readme-dist.md.ejs +58 -0
  36. package/src/templates/robots.txt.ejs +4 -0
  37. package/src/templates/sitemap.xml.ejs +69 -0
  38. package/src/templates/sw.js.ejs +78 -0
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Screenshot Layout Analyzer
5
+ * Analyzes all screenshots to verify layout consistency
6
+ */
7
+
8
+ const fs = require('fs').promises;
9
+ const path = require('path');
10
+
11
+ const SCREENSHOTS_DIR = './ui-test-results/screenshots';
12
+ const OUTPUT_FILE = './ui-test-results/layout-analysis.md';
13
+
14
+ async function analyzeScreenshots() {
15
+ console.log('🔍 Analyzing screenshots for layout consistency...\n');
16
+
17
+ const files = await fs.readdir(SCREENSHOTS_DIR);
18
+ const desktopScreenshots = files.filter(f => f.includes('_desktop.png'));
19
+ const mobileScreenshots = files.filter(f => f.includes('_mobile.png'));
20
+
21
+ console.log(`📊 Found ${desktopScreenshots.length} desktop screenshots`);
22
+ console.log(`📱 Found ${mobileScreenshots.length} mobile screenshots\n`);
23
+
24
+ // Group by page type
25
+ const pages = {
26
+ home: [],
27
+ tools: [],
28
+ master: [],
29
+ static: []
30
+ };
31
+
32
+ desktopScreenshots.forEach(file => {
33
+ const name = file.replace('_desktop.png', '');
34
+
35
+ // Remove leading underscores and parse
36
+ const cleanName = name.replace(/^_+/, '');
37
+
38
+ if (cleanName === 'vi_' || cleanName === 'en_' || cleanName === 'vi' || cleanName === 'en') {
39
+ // Homepage
40
+ pages.home.push(name);
41
+ } else if (cleanName.includes('master')) {
42
+ // Master tools
43
+ pages.master.push(name);
44
+ } else if (cleanName.includes('about') || cleanName.includes('privacy') || cleanName.includes('terms') || cleanName.includes('categories')) {
45
+ // Static pages
46
+ pages.static.push(name);
47
+ } else {
48
+ // Regular tools
49
+ pages.tools.push(name);
50
+ }
51
+ });
52
+
53
+ // Generate report
54
+ let report = `# 📸 Layout Analysis Report
55
+
56
+ **Generated**: ${new Date().toLocaleString()}
57
+ **Total Screenshots**: ${desktopScreenshots.length * 2} (desktop + mobile)
58
+
59
+ ---
60
+
61
+ ## 📊 SCREENSHOT BREAKDOWN
62
+
63
+ | Category | Count | Files |
64
+ |----------|-------|-------|
65
+ | **Homepage** | ${pages.home.length} | ${pages.home.slice(0, 3).join(', ')}... |
66
+ | **Tools** | ${pages.tools.length} | ${pages.tools.slice(0, 3).join(', ')}... |
67
+ | **Master Tools** | ${pages.master.length} | ${pages.master.join(', ')} |
68
+ | **Static Pages** | ${pages.static.length} | ${pages.static.join(', ')} |
69
+
70
+ ---
71
+
72
+ ## 🎯 LAYOUT CONSISTENCY CHECKLIST
73
+
74
+ ### Expected Layout (1400px max-width)
75
+
76
+ All pages should show:
77
+ - ✅ Header aligned at 1400px
78
+ - ✅ Content container at 1400px
79
+ - ✅ Clear borders on containers
80
+ - ✅ Consistent spacing (2rem)
81
+ - ✅ No horizontal overflow
82
+
83
+ ### Manual Review Required
84
+
85
+ Please review screenshots for:
86
+
87
+ #### 1. **Container Alignment**
88
+ Check that header and content align perfectly:
89
+ \`\`\`
90
+ ┌─────────────────────────────────────────────┐
91
+ │ Header (1400px) ← Should align │
92
+ ├─────────────────────────────────────────────┤
93
+ │ Content (1400px) ← Should align │
94
+ └─────────────────────────────────────────────┘
95
+ \`\`\`
96
+
97
+ #### 2. **Border Visibility**
98
+ All containers should have:
99
+ - Clear 1px border
100
+ - Border radius (12px)
101
+ - Box shadow
102
+
103
+ #### 3. **Spacing Consistency**
104
+ - 2rem padding inside containers
105
+ - 2rem gap between elements
106
+ - 2rem margin top/bottom
107
+
108
+ #### 4. **Master Tools Layout**
109
+ Should show sidebar + content:
110
+ \`\`\`
111
+ ┌────────┐ ┌──────────────┐
112
+ │Sidebar │ │ Content │
113
+ │(250px) │ │ (flex) │
114
+ └────────┘ └──────────────┘
115
+ \`\`\`
116
+
117
+ ---
118
+
119
+ ## 📁 SCREENSHOTS TO REVIEW
120
+
121
+ ### Homepage (${pages.home.length} screenshots)
122
+ ${pages.home.map(name => `- [ ] \`${name}\``).join('\n')}
123
+
124
+ ### Tools (${pages.tools.length} screenshots)
125
+ ${pages.tools.map(name => `- [ ] \`${name}\``).join('\n')}
126
+
127
+ ### Master Tools (${pages.master.length} screenshots)
128
+ ${pages.master.map(name => `- [ ] \`${name}\``).join('\n')}
129
+
130
+ ### Static Pages (${pages.static.length} screenshots)
131
+ ${pages.static.map(name => `- [ ] \`${name}\``).join('\n')}
132
+
133
+ ---
134
+
135
+ ## 🔍 REVIEW PROCESS
136
+
137
+ 1. **Open screenshots folder**:
138
+ \`\`\`bash
139
+ open ui-test-results/screenshots/
140
+ \`\`\`
141
+
142
+ 2. **Compare desktop vs mobile**:
143
+ - Desktop should show full layout
144
+ - Mobile should stack vertically
145
+ - Both should maintain borders
146
+
147
+ 3. **Check alignment**:
148
+ - Use ruler/guides in image viewer
149
+ - Verify 1400px max-width
150
+ - Check header/content alignment
151
+
152
+ 4. **Look for issues**:
153
+ - Horizontal overflow
154
+ - Missing borders
155
+ - Inconsistent spacing
156
+ - Broken layouts
157
+
158
+ ---
159
+
160
+ ## ✅ EXPECTED RESULTS
161
+
162
+ After layout unification, all pages should:
163
+
164
+ 1. **Perfect Alignment** ✅
165
+ - Header at 1400px
166
+ - Content at 1400px
167
+ - Footer at 1400px
168
+
169
+ 2. **Clear Borders** ✅
170
+ - All containers bordered
171
+ - Consistent border color
172
+ - Rounded corners
173
+
174
+ 3. **Consistent Spacing** ✅
175
+ - 2rem padding standard
176
+ - 2rem gaps
177
+ - No cramped layouts
178
+
179
+ 4. **Responsive** ✅
180
+ - Desktop: Full layout
181
+ - Mobile: Stacked layout
182
+ - Borders maintained
183
+
184
+ ---
185
+
186
+ ## 📝 NOTES
187
+
188
+ - Screenshots are at 1400x900 (desktop) and 375x667 (mobile)
189
+ - All screenshots taken with latest CSS changes
190
+ - Review both light and dark mode if applicable
191
+ - Check for any visual regressions
192
+
193
+ ---
194
+
195
+ **Status**: Ready for manual review
196
+ **Action**: Open screenshots and verify layout consistency
197
+ **Report**: Mark checkboxes as you review each screenshot
198
+ `;
199
+
200
+ await fs.writeFile(OUTPUT_FILE, report);
201
+ console.log(`✅ Analysis report generated: ${OUTPUT_FILE}\n`);
202
+
203
+ // Print summary
204
+ console.log('📊 SUMMARY');
205
+ console.log('─'.repeat(50));
206
+ console.log(`Total Pages: ${desktopScreenshots.length}`);
207
+ console.log(` - Homepage: ${pages.home.length}`);
208
+ console.log(` - Tools: ${pages.tools.length}`);
209
+ console.log(` - Master Tools: ${pages.master.length}`);
210
+ console.log(` - Static: ${pages.static.length}`);
211
+ console.log('─'.repeat(50));
212
+ console.log(`\n💡 Next: Review screenshots in ${SCREENSHOTS_DIR}`);
213
+ console.log(`📄 Full report: ${OUTPUT_FILE}\n`);
214
+ }
215
+
216
+ // Run
217
+ analyzeScreenshots().catch(console.error);
@@ -0,0 +1,39 @@
1
+ const fs = require('fs-extra');
2
+ const { paths, isSecure, forceRebuild } = require('./builds/config');
3
+ const { saveCache } = require('./builds/cache');
4
+ const { buildAssets } = require('./builds/assets');
5
+ const { buildPages } = require('./builds/pages');
6
+ const { buildTemplates, createRootRedirect, copyRootFiles } = require('./builds/templates');
7
+ // const { buildAdmin } = require('./builds/admin');
8
+
9
+ (async () => {
10
+ console.time('🚀 Build Duration');
11
+ console.log(`🚀 Starting build (Secure Mode: ${isSecure ? 'ON' : 'OFF'})...`);
12
+
13
+ if (forceRebuild) {
14
+ try {
15
+ console.time("🧹 Cleaned dist folder");
16
+ await fs.emptyDir(paths.DIST);
17
+ console.timeEnd("🧹 Cleaned dist folder");
18
+ } catch (e) { }
19
+ } else {
20
+ await fs.ensureDir(paths.DIST);
21
+ }
22
+
23
+ try {
24
+ await buildAssets();
25
+ await buildPages();
26
+ // await buildAdmin();
27
+ await createRootRedirect();
28
+ await buildTemplates();
29
+ await copyRootFiles();
30
+
31
+ saveCache();
32
+ console.log('✅ Build complete!');
33
+ } catch (err) {
34
+ console.error('❌ Build Failed:', err);
35
+ process.exit(1);
36
+ }
37
+
38
+ console.timeEnd('🚀 Build Duration');
39
+ })();
@@ -0,0 +1,17 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { paths } = require('./config');
4
+
5
+ async function buildAdmin() {
6
+ const adminSrc = path.join(paths.SRC, 'admin');
7
+ const adminDist = path.join(paths.DIST, 'admin');
8
+
9
+ if (fs.existsSync(adminSrc)) {
10
+ console.log('🛡️ Building Admin Panel...');
11
+ await fs.ensureDir(adminDist);
12
+ await fs.copy(adminSrc, adminDist);
13
+ console.log('✅ Admin Panel copied.');
14
+ }
15
+ }
16
+
17
+ module.exports = { buildAdmin };
@@ -0,0 +1,167 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+ const { paths, isSecure } = require('./config');
5
+ const { hasChanged } = require('./cache');
6
+ const { getHash } = require('./utils');
7
+
8
+ const ASSET_HASHES = {};
9
+ function getAssetHash(relPath) {
10
+ if (ASSET_HASHES[relPath]) return ASSET_HASHES[relPath];
11
+ const fullPath = path.join(paths.DIST, relPath);
12
+ if (fs.existsSync(fullPath)) {
13
+ const content = fs.readFileSync(fullPath);
14
+ const hash = getHash(content).substring(0, 8);
15
+ ASSET_HASHES[relPath] = hash;
16
+ return hash;
17
+ }
18
+ return '';
19
+ }
20
+
21
+ function minifyJs(src, dest) {
22
+ try {
23
+ execSync(`npx terser "${src}" --compress --mangle --output "${dest}"`);
24
+ } catch (e) {
25
+ console.error(`Minify failed ${src}, copy raw`);
26
+ fs.copySync(src, dest);
27
+ }
28
+ }
29
+
30
+ function processJs(srcPath, destPath, fileName) {
31
+ if (hasChanged(srcPath) || !fs.existsSync(destPath)) {
32
+ if (isSecure) {
33
+ console.time(`📦 Obfuscating JS: ${fileName}`);
34
+ try {
35
+ const cmd = `npx javascript-obfuscator "${srcPath}" --output "${destPath}" \
36
+ --compact true --control-flow-flattening true --control-flow-flattening-threshold 0.5 \
37
+ --dead-code-injection true --identifier-names-generator hexadecimal \
38
+ --rename-globals true --string-array true --string-array-threshold 0.5 \
39
+ --transform-object-keys true`;
40
+ execSync(cmd);
41
+ } catch (e) {
42
+ console.error(`Obfuscation failed for ${fileName}, fallback to minify.`);
43
+ minifyJs(srcPath, destPath);
44
+ }
45
+ console.timeEnd(`📦 Obfuscating JS: ${fileName}`);
46
+ } else {
47
+ console.time(`📄 Copying JS: ${fileName}`);
48
+ fs.copySync(srcPath, destPath);
49
+ console.timeEnd(`📄 Copying JS: ${fileName}`);
50
+ }
51
+ }
52
+ }
53
+
54
+ async function buildAssets() {
55
+ const cssSrc = path.join(paths.SRC, 'assets', 'css');
56
+ const jsSrc = path.join(paths.SRC, 'assets', 'js');
57
+ const featuresDir = path.join(paths.SRC, 'features');
58
+ const cssDist = path.join(paths.ASSETS_DIST, 'css');
59
+ const jsDist = path.join(paths.ASSETS_DIST, 'js');
60
+ const featuresDist = path.join(paths.ASSETS_DIST, 'features');
61
+
62
+ await fs.ensureDir(paths.ASSETS_DIST);
63
+ await fs.ensureDir(cssDist);
64
+ await fs.ensureDir(jsDist);
65
+ await fs.ensureDir(featuresDist);
66
+
67
+ console.time('🎨 Assets Build');
68
+
69
+ // 0. Copy all raw assets (images, fonts, vendor, etc)
70
+ const assetsSrc = path.join(paths.SRC, 'assets');
71
+ if (fs.existsSync(assetsSrc)) {
72
+ const items = fs.readdirSync(assetsSrc);
73
+ for (const item of items) {
74
+ if (['css', 'js'].includes(item)) continue;
75
+ const srcPath = path.join(assetsSrc, item);
76
+ const destPath = path.join(paths.ASSETS_DIST, item);
77
+ if (hasChanged(srcPath, 'assets-copy/', false)) {
78
+ await fs.copy(srcPath, destPath);
79
+ hasChanged(srcPath, 'assets-copy/', true);
80
+ }
81
+ }
82
+ }
83
+
84
+ // 1. Global CSS
85
+ if (await fs.pathExists(cssSrc)) {
86
+ const files = await fs.readdir(cssSrc);
87
+ for (const file of files) {
88
+ if (!file.endsWith('.css')) continue;
89
+ const srcPath = path.join(cssSrc, file);
90
+ const destPath = path.join(cssDist, file);
91
+ if (hasChanged(srcPath) || !fs.existsSync(destPath)) {
92
+ if (isSecure) {
93
+ console.time(`🎨 Minifying Global CSS: ${file}`);
94
+ try { execSync(`npx clean-css-cli -o "${destPath}" "${srcPath}"`); }
95
+ catch (e) { await fs.copy(srcPath, destPath); }
96
+ console.timeEnd(`🎨 Minifying Global CSS: ${file}`);
97
+ } else {
98
+ console.time(`🎨 Copying Global CSS: ${file}`);
99
+ await fs.copy(srcPath, destPath);
100
+ console.timeEnd(`🎨 Copying Global CSS: ${file}`);
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ // 2. Global JS
107
+ if (await fs.pathExists(jsSrc)) {
108
+ const files = await fs.readdir(jsSrc);
109
+ for (const file of files) {
110
+ if (!file.endsWith('.js')) continue;
111
+ const srcPath = path.join(jsSrc, file);
112
+ const destPath = path.join(jsDist, file);
113
+ processJs(srcPath, destPath, file);
114
+ }
115
+ }
116
+
117
+ // 3. Feature Assets
118
+ if (await fs.pathExists(featuresDir)) {
119
+ const features = await fs.readdir(featuresDir);
120
+ for (const feature of features) {
121
+ const featDir = path.join(featuresDir, feature);
122
+ if (!(await fs.stat(featDir)).isDirectory()) continue;
123
+
124
+ const featDistDir = path.join(featuresDist, feature);
125
+ await fs.ensureDir(featDistDir);
126
+
127
+ // Feature CSS
128
+ const cssPath = path.join(featDir, 'style.css');
129
+ if (fs.existsSync(cssPath)) {
130
+ const destPath = path.join(featDistDir, 'style.css');
131
+ if (hasChanged(cssPath) || !fs.existsSync(destPath)) {
132
+ if (isSecure) {
133
+ console.time(`🎨 Minifying Feature CSS: ${feature}/style.css`);
134
+ try { execSync(`npx clean-css-cli -o "${destPath}" "${cssPath}"`); }
135
+ catch (e) { await fs.copy(cssPath, destPath); }
136
+ console.timeEnd(`🎨 Minifying Feature CSS: ${feature}/style.css`);
137
+ } else {
138
+ console.time(`🎨 Copying Feature CSS: ${feature}/style.css`);
139
+ await fs.copy(cssPath, destPath);
140
+ console.timeEnd(`🎨 Copying Feature CSS: ${feature}/style.css`);
141
+ }
142
+ }
143
+ }
144
+
145
+ // Feature JS
146
+ const files = fs.readdirSync(featDir);
147
+ for (const file of files) {
148
+ if (file.endsWith('.js') && file !== 'toolConfig.js') {
149
+ const jsSrcPath = path.join(featDir, file);
150
+ const jsDestPath = path.join(featDistDir, file);
151
+ processJs(jsSrcPath, jsDestPath, `${feature}/${file}`);
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ // 4. Special: Building Playground Examples from folders
158
+ const { buildPlaygroundExamples } = require('./playground-examples');
159
+ await buildPlaygroundExamples();
160
+
161
+ console.timeEnd('🎨 Assets Build');
162
+ }
163
+
164
+ module.exports = {
165
+ getAssetHash,
166
+ buildAssets
167
+ };
@@ -0,0 +1,48 @@
1
+ const fs = require('fs-extra');
2
+ const yaml = require('js-yaml');
3
+ const path = require('path');
4
+ const { paths, isSecure, forceRebuild } = require('./config');
5
+ const { getHash } = require('./utils');
6
+
7
+ let buildCache = {};
8
+
9
+ if (fs.existsSync(paths.CACHE_FILE)) {
10
+ try {
11
+ buildCache = yaml.load(fs.readFileSync(paths.CACHE_FILE, 'utf8')) || {};
12
+ } catch (e) {
13
+ console.warn("⚠️ Failed to load build cache, starting fresh.");
14
+ }
15
+ }
16
+
17
+ function hasChanged(filePath, keyPrefix = '', update = true) {
18
+ if (forceRebuild) return true;
19
+ if (!fs.existsSync(filePath)) return true;
20
+ if (fs.statSync(filePath).isDirectory()) return true;
21
+
22
+ const content = fs.readFileSync(filePath);
23
+ const currentHash = getHash(content);
24
+
25
+ // Separate cache for dev and prod
26
+ const modePrefix = isSecure ? 'prod/' : 'dev/';
27
+ const relPath = path.relative(paths.SRC, filePath);
28
+ const cacheKey = modePrefix + keyPrefix + relPath;
29
+
30
+ if (buildCache[cacheKey] !== currentHash) {
31
+ if (update) buildCache[cacheKey] = currentHash;
32
+ return true;
33
+ }
34
+ return false;
35
+ }
36
+
37
+ function saveCache() {
38
+ try {
39
+ fs.writeFileSync(paths.CACHE_FILE, yaml.dump(buildCache));
40
+ } catch (e) {
41
+ console.error("⚠️ Failed to save build cache:", e);
42
+ }
43
+ }
44
+
45
+ module.exports = {
46
+ hasChanged,
47
+ saveCache
48
+ };
@@ -0,0 +1,31 @@
1
+ const path = require('path');
2
+
3
+ // CLI Args
4
+ const isSecure = process.argv.includes('--obfuscate');
5
+ const isDev = process.argv.includes('--dev');
6
+ let forceRebuild = process.argv.includes('--force');
7
+
8
+ // Paths
9
+ const ROOT_DIR = process.cwd();
10
+ const SRC_DIR = path.join(ROOT_DIR, 'src');
11
+ const DIST_DIR = path.join(ROOT_DIR, isDev ? 'dist-dev' : 'dist');
12
+ const ASSETS_DIST = path.join(DIST_DIR, 'assets');
13
+ const CACHE_FILE = path.join(ROOT_DIR, '.build-cache.yaml');
14
+
15
+ // Internal paths for the framework itself (when running from node_modules)
16
+ const CORE_DIR = path.resolve(__dirname, '../../');
17
+
18
+ module.exports = {
19
+ isSecure,
20
+ isDev,
21
+ forceRebuild,
22
+ paths: {
23
+ ROOT: ROOT_DIR,
24
+ CORE_ROOT: CORE_DIR,
25
+ SRC: SRC_DIR,
26
+ DIST: DIST_DIR,
27
+ ASSETS_DIST: ASSETS_DIST,
28
+ CACHE_FILE: CACHE_FILE
29
+ },
30
+ setForceRebuild: (val) => { forceRebuild = val; }
31
+ };