Skip to content

Commit aa7c9e0

Browse files
authored
Figma Updates (#117)
* Updated packages * Updated package.json * Refactored package.json * Ignore zips in the root * Adding in a figmaignore file * Ignore vite.config.ts * Adding ignore library * Adding ignore library * Extract figma with ignore files * Updated ignore script * Updates * Updates * Updates * Updated App * Blog Page on a separate file * Figma Updates * Removed unsupported node versions from tests
1 parent 0faaf30 commit aa7c9e0

30 files changed

+6668
-6357
lines changed

.figmaignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
README.md
2+
vite.config.ts
3+
index.html

.github/workflows/pr-checks.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
node-version: [ 18.x, 19.x, 20.x, 21.x, 22.x, 23.x, 24.x ]
14+
node-version: [ 20.x, 22.x, 23.x, 24.x ]
1515
permissions:
1616
contents: write
1717

@@ -31,4 +31,4 @@ jobs:
3131
- name: Build Project 🏗️
3232
run: npm run build
3333
env:
34-
PUBLIC_URL: 'craigiswayne.com'
34+
PUBLIC_URL: 'craigiswayne.com'

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
build/
22
.idea/
3-
node_modules/
3+
node_modules/
4+
/*.zip

_posts/ai-terms.md

Lines changed: 202 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| Feature | Angular | React | Vue |
2+
|----------------------------------------|---------|-------------|-----|
3+
| Scoped Styles | Yes | CSS Modules | Yes |
4+
| Scoped Styles from External stylesheet | Yes | CSS Modules | Yes |
5+
| Routing Built-in | Yes | CSS Modules | No |
6+
| MVC | Yes | ? | - |

_posts/type-vs-interface.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
| Feature | interface | type |
2+
|----------------------|------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
3+
| Defines | Object shapes and class contracts. | Any TypeScript type, including object shapes, unions, intersections, tuples, and primitives |
4+
| | | |
5+
| Declaration Merging | Yes | No |
6+
| | Multiple interface blocks with the same name are merged into one | A type alias is final once declared and cannot be added to |
7+
| | | |
8+
| Extending | Uses the extends keyword. Can extend multiple interfaces. | Uses the & (intersection) keyword to combine shapes. |
9+
| | | |
10+
| Implemented by Class | Yes | Yes |
11+
| | Use class MyClass implements MyInterface { ... } | A class can implement a type if the type represents an object shape. |
12+
| | | |
13+
| Unions & Tuples | No | Yes |

extract-figma-files.js

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Import the 'extract-zip' library
2+
const extract = require('extract-zip');
3+
4+
// Import 'path' for resolving paths
5+
const path = require('path');
6+
7+
// Import 'fs/promises' for asynchronous file system operations
8+
const fs = require('node:fs/promises');
9+
10+
// --- NEW DEPENDENCY ---
11+
// Import the 'ignore' library to handle .figmaignore rules
12+
// Run: npm install ignore
13+
const { Ignore } = require('ignore');
14+
const ignore = require("ignore");
15+
// --- END NEW DEPENDENCY ---
16+
17+
// --- Configuration ---
18+
const INTERMEDIATE_FOLDER = path.resolve(__dirname, 'figma_extracted_files');
19+
// --- End of Configuration ---
20+
21+
/**
22+
* Extracts a zip file.
23+
* (This function is unchanged)
24+
*/
25+
async function extract_zip_archive(source_file, target_dir) {
26+
console.log(`Starting extraction of: ${source_file}`);
27+
await extract(source_file, { dir: target_dir });
28+
console.log(`✅ Extraction complete. Files are in: ${target_dir}`);
29+
}
30+
31+
/**
32+
* Recursively copies files from a source directory to a destination.
33+
* (This function is unchanged, used as a fast-path if no .figmaignore exists)
34+
*/
35+
async function copy_files_recursively(source_dir, destination_dir) {
36+
console.log(`Starting recursive copy from: ${source_dir}`);
37+
await fs.cp(source_dir, destination_dir, { recursive: true });
38+
console.log(`✅ Successfully copied files to: ${destination_dir}`);
39+
}
40+
41+
// --- NEW FUNCTION ---
42+
/**
43+
* Recursively copies files, respecting .figmaignore rules.
44+
*
45+
* @param {string} root_source - The absolute path to the root source folder (e.g., INTERMEDIATE_FOLDER).
46+
* @param {string} root_destination - The absolute path to the root destination folder.
47+
* @param {Ignore} ig - An 'ignore' instance pre-loaded with rules.
48+
*/
49+
async function copy_with_ignore(root_source, root_destination, ig) {
50+
console.log('Starting recursive copy with ignore rules...');
51+
52+
// We define an internal 'walk' function to handle the recursion
53+
async function walk(current_source) {
54+
// Read all entries (files/dirs) in the current directory
55+
const entries = await fs.readdir(current_source, { withFileTypes: true });
56+
57+
for (const entry of entries) {
58+
const source_path = path.join(current_source, entry.name);
59+
60+
// Get the path *relative* to the root, which is what 'ignore' needs
61+
// e.g., 'src/components/button.js'
62+
const relative_path = path.relative(root_source, source_path);
63+
64+
// Add a trailing slash for directories to match .gitignore behavior
65+
// e.g., 'node_modules/'
66+
const check_path = entry.isDirectory() ? `${relative_path}/` : relative_path;
67+
68+
// Check if the 'ignore' instance filters this path
69+
if (ig.ignores(check_path)) {
70+
console.log(`- Ignoring: ${check_path}`);
71+
continue; // Skip this file or directory
72+
}
73+
74+
// If not ignored, determine its destination path
75+
const destination_path = path.join(root_destination, relative_path);
76+
77+
if (entry.isDirectory()) {
78+
// If it's a directory, create it in the destination
79+
await fs.mkdir(destination_path, { recursive: true });
80+
// Recurse into this directory
81+
await walk(source_path);
82+
} else {
83+
// If it's a file, ensure its parent directory exists
84+
await fs.mkdir(path.dirname(destination_path), { recursive: true });
85+
// Copy the file
86+
await fs.copyFile(source_path, destination_path);
87+
}
88+
}
89+
}
90+
91+
// Start the recursive walk from the root source directory
92+
await walk(root_source);
93+
console.log(`✅ Successfully copied files (with ignores) to: ${root_destination}`);
94+
}
95+
// --- END NEW FUNCTION ---
96+
97+
/**
98+
* Main orchestration function to run the script.
99+
* (This function is MODIFIED)
100+
*/
101+
async function main() {
102+
// --- Guard Clauses (Input Validation) ---
103+
const source_file_arg = process.argv[2];
104+
const final_destination_arg = './' // process.argv[3]; // You had this hardcoded, I left it but you might want process.argv[3]
105+
106+
if (!source_file_arg || !final_destination_arg) {
107+
console.error('Error: Missing required arguments.');
108+
console.log('Usage: node index.js <path_to_zip_file> <final_destination_folder>');
109+
process.exit(1);
110+
}
111+
112+
// --- Path Resolution ---
113+
const absolute_source = path.resolve(source_file_arg);
114+
const absolute_intermediate = INTERMEDIATE_FOLDER;
115+
const absolute_destination = path.resolve(final_destination_arg);
116+
117+
// --- Main Execution ---
118+
try {
119+
// Step 1: Extract the zip file to the intermediate folder
120+
await extract_zip_archive(absolute_source, absolute_intermediate);
121+
122+
// --- MODIFIED SECTION ---
123+
// Step 2: Check for .figmaignore and decide which copy function to use
124+
const figma_ignore_path = path.join(__dirname, '.figmaignore');
125+
let ignore_content = null;
126+
127+
try {
128+
// Try to read the .figmaignore file
129+
ignore_content = await fs.readFile(figma_ignore_path, 'utf8');
130+
} catch (error) {
131+
// If the error is *not* "file not found", re-throw it.
132+
if (error.code !== 'ENOENT') {
133+
console.error('Error reading .figmaignore file:', error);
134+
throw error; // Propagate error to the main catch block
135+
}
136+
// If file is not found (ENOENT), ignore_content remains null. This is fine.
137+
}
138+
139+
if (ignore_content) {
140+
// --- Path A: .figmaignore EXISTS ---
141+
console.log('Found .figmaignore. Applying ignore rules...');
142+
// Create an 'ignore' instance and add the file content
143+
const ig = ignore().add(ignore_content);
144+
145+
// Use our new copy function that respects these rules
146+
await copy_with_ignore(absolute_intermediate, absolute_destination, ig);
147+
} else {
148+
// --- Path B: .figmaignore does NOT exist ---
149+
console.log('No .figmaignore file found. Copying all files...');
150+
151+
// Use the original fast-path copy function
152+
await copy_files_recursively(absolute_intermediate, absolute_destination);
153+
}
154+
// --- END MODIFIED SECTION ---
155+
156+
console.log('✨ All operations completed successfully.');
157+
158+
} catch (error) {
159+
// This catch block handles errors from extraction, file I/O, or copying
160+
console.error('An error occurred during the process:', error);
161+
process.exit(1); // Exit with a failure code
162+
}
163+
164+
// Step 3: Clean up the intermediate folder (this is unchanged)
165+
// We do this outside the try/catch, or in a 'finally' block,
166+
// but here is fine so it only runs on success.
167+
// Let's move it to *after* the catch block to *always* run.
168+
// --- Correction: Your original code had this *after* the catch,
169+
// which is good, but it should be inside the main() function scope.
170+
// I'm moving it to be *just before* the end of the main() function.
171+
172+
try {
173+
await fs.rm(INTERMEDIATE_FOLDER, { recursive: true, force: true });
174+
console.log('🧹 Cleaned up intermediate folder.');
175+
} catch (rm_error) {
176+
// Don't fail the whole script if cleanup fails, just log it.
177+
console.warn(`Warning: Failed to clean up intermediate folder: ${rm_error.message}`);
178+
}
179+
}
180+
181+
// Run the main function
182+
main();

index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,20 @@
1515
<meta property="og:image:alt" content="Craig Wayne Portfolio" />
1616
<meta property="og:url" content="https://craigiswayne.com/" />
1717
<meta property="og:locale" content="en_GB" />
18+
1819
<meta name="twitter:title" content="Craig Wayne Portfolio" />
1920
<meta name="twitter:description" content="Web Portfolio for Craig Wayne; a full stack javascript engineer with more than 10 years of experience in design, development and architecture, specializing in typescript, angular, webgl" />
20-
<meta property="twitter:domain" content="craigiswayne.com">
21-
<meta property="twitter:url" content="https://craigiswayne.com/">
21+
<meta name="twitter:domain" content="craigiswayne.com">
22+
<meta name="twitter:url" content="https://craigiswayne.com/">
2223
<meta name="twitter:image" content="/social/banner.png" />
2324
<meta name="twitter:image:width" content="1200" />
2425
<meta name="twitter:image:height" content="630" />
2526
<meta name="twitter:card" content="summary_large_image" />
2627
<meta name="twitter:site" content="craigiswayne" />
28+
<meta name="twitter:creator" content="@craigiswayne" />
29+
2730
<meta name="theme-color" content="#ffffff">
31+
<meta name="referrer" content="origin-when-cross-origin" />
2832

2933
<link rel="icon" type="image/png" sizes="16x16" href="/social/favicon_16x16.png">
3034
<link rel="icon" type="image/png" sizes="32x32" href="/social/favicon_32x32.png">
@@ -42,5 +46,6 @@
4246
<body>
4347
<div id="root"></div>
4448
<script type="module" src="/src/main.tsx"></script>
49+
<script data-name="BMC-Widget" data-cfasync="false" src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" data-id="craigiswayne" data-description="Support me on Buy me a coffee!" data-message="" data-color="#FF5F5F" data-position="Right" data-x_margin="18" data-y_margin="18"></script>
4550
</body>
4651
</html>

0 commit comments

Comments
 (0)