Update Print Portfolio
This commit is contained in:
parent
e41d8ec3cb
commit
faefc32c49
89 changed files with 887 additions and 788 deletions
1
dist/assets/index-BOGP2GsU.css
vendored
1
dist/assets/index-BOGP2GsU.css
vendored
File diff suppressed because one or more lines are too long
133
dist/assets/index-C5_7qcB8.js
vendored
133
dist/assets/index-C5_7qcB8.js
vendored
File diff suppressed because one or more lines are too long
135
dist/assets/index-CDV1Fqci.js
vendored
Normal file
135
dist/assets/index-CDV1Fqci.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/index-DS6IUas1.css
vendored
Normal file
1
dist/assets/index-DS6IUas1.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -5,8 +5,8 @@
|
||||||
<link rel="icon" type="image/svg+xml" href="/vndk-icon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vndk-icon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Khoa Vo - AI Creative Lead</title>
|
<title>Khoa Vo - AI Creative Lead</title>
|
||||||
<script type="module" crossorigin src="/assets/index-C5_7qcB8.js"></script>
|
<script type="module" crossorigin src="/assets/index-CDV1Fqci.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-BOGP2GsU.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DS6IUas1.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
|
||||||
0
node_modules/.bin/autoprefixer
generated
vendored
Normal file → Executable file
0
node_modules/.bin/autoprefixer
generated
vendored
Normal file → Executable file
0
node_modules/.bin/autoprefixer.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/autoprefixer.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/autoprefixer.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/autoprefixer.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/baseline-browser-mapping.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/browserslist.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/cssesc.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/esbuild.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jiti.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/jsesc.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/json5.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/loose-envify.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/nanoid.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/parser.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/resolve.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/rollup.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/semver.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase-node.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/sucrase.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwind.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/tailwindcss.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/update-browserslist-db.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite.cmd
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite.ps1
generated
vendored
Normal file → Executable file
0
node_modules/.bin/vite.ps1
generated
vendored
Normal file → Executable file
59
node_modules/.package-lock.json
generated
vendored
59
node_modules/.package-lock.json
generated
vendored
|
|
@ -48,7 +48,6 @@
|
||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
|
|
@ -300,18 +299,18 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.25.12",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"darwin"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
|
@ -412,32 +411,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.60.1",
|
"version": "4.60.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
|
||||||
"integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
|
"integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"darwin"
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
|
||||||
"version": "4.60.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
|
|
||||||
"integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
|
|
@ -505,7 +490,6 @@
|
||||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
|
|
@ -666,7 +650,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.10.12",
|
"baseline-browser-mapping": "^2.10.12",
|
||||||
"caniuse-lite": "^1.0.30001782",
|
"caniuse-lite": "^1.0.30001782",
|
||||||
|
|
@ -972,6 +955,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
|
@ -1086,7 +1084,6 @@
|
||||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
|
|
@ -1355,7 +1352,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
|
|
@ -1525,7 +1521,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -1538,7 +1533,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"scheduler": "^0.23.2"
|
"scheduler": "^0.23.2"
|
||||||
|
|
@ -1848,7 +1842,6 @@
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|
@ -1926,7 +1919,6 @@
|
||||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
|
|
@ -2020,7 +2012,6 @@
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
42
node_modules/.vite/deps/_metadata.json
generated
vendored
42
node_modules/.vite/deps/_metadata.json
generated
vendored
|
|
@ -1,50 +1,50 @@
|
||||||
{
|
{
|
||||||
"hash": "90ee4654",
|
"hash": "990005cb",
|
||||||
"configHash": "fbb0cfde",
|
"configHash": "dd418e0b",
|
||||||
"lockfileHash": "a6533fbd",
|
"lockfileHash": "9e20975c",
|
||||||
"browserHash": "8360e944",
|
"browserHash": "123a9614",
|
||||||
"optimized": {
|
"optimized": {
|
||||||
"react": {
|
"react": {
|
||||||
"src": "../../react/index.js",
|
"src": "../../react/index.js",
|
||||||
"file": "react.js",
|
"file": "react.js",
|
||||||
"fileHash": "ecc3583d",
|
"fileHash": "2e48ac20",
|
||||||
"needsInterop": true
|
"needsInterop": true
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"src": "../../react-dom/index.js",
|
"src": "../../react-dom/index.js",
|
||||||
"file": "react-dom.js",
|
"file": "react-dom.js",
|
||||||
"fileHash": "5d314a57",
|
"fileHash": "455f0ae0",
|
||||||
"needsInterop": true
|
"needsInterop": true
|
||||||
},
|
},
|
||||||
"react/jsx-dev-runtime": {
|
"react/jsx-dev-runtime": {
|
||||||
"src": "../../react/jsx-dev-runtime.js",
|
"src": "../../react/jsx-dev-runtime.js",
|
||||||
"file": "react_jsx-dev-runtime.js",
|
"file": "react_jsx-dev-runtime.js",
|
||||||
"fileHash": "0de83b10",
|
"fileHash": "82ad24c4",
|
||||||
"needsInterop": true
|
"needsInterop": true
|
||||||
},
|
},
|
||||||
"react/jsx-runtime": {
|
"react/jsx-runtime": {
|
||||||
"src": "../../react/jsx-runtime.js",
|
"src": "../../react/jsx-runtime.js",
|
||||||
"file": "react_jsx-runtime.js",
|
"file": "react_jsx-runtime.js",
|
||||||
"fileHash": "5ce06852",
|
"fileHash": "67186fcc",
|
||||||
"needsInterop": true
|
|
||||||
},
|
|
||||||
"lucide-react": {
|
|
||||||
"src": "../../lucide-react/dist/esm/lucide-react.js",
|
|
||||||
"file": "lucide-react.js",
|
|
||||||
"fileHash": "5c75eae5",
|
|
||||||
"needsInterop": false
|
|
||||||
},
|
|
||||||
"react-dom/client": {
|
|
||||||
"src": "../../react-dom/client.js",
|
|
||||||
"file": "react-dom_client.js",
|
|
||||||
"fileHash": "c3cad18b",
|
|
||||||
"needsInterop": true
|
"needsInterop": true
|
||||||
},
|
},
|
||||||
"framer-motion": {
|
"framer-motion": {
|
||||||
"src": "../../framer-motion/dist/es/index.mjs",
|
"src": "../../framer-motion/dist/es/index.mjs",
|
||||||
"file": "framer-motion.js",
|
"file": "framer-motion.js",
|
||||||
"fileHash": "53e35944",
|
"fileHash": "f64f8e8e",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
|
},
|
||||||
|
"lucide-react": {
|
||||||
|
"src": "../../lucide-react/dist/esm/lucide-react.js",
|
||||||
|
"file": "lucide-react.js",
|
||||||
|
"fileHash": "36896c9b",
|
||||||
|
"needsInterop": false
|
||||||
|
},
|
||||||
|
"react-dom/client": {
|
||||||
|
"src": "../../react-dom/client.js",
|
||||||
|
"file": "react-dom_client.js",
|
||||||
|
"fileHash": "95365ffd",
|
||||||
|
"needsInterop": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chunks": {
|
"chunks": {
|
||||||
|
|
|
||||||
3
node_modules/@esbuild/darwin-arm64/README.md
generated
vendored
Normal file
3
node_modules/@esbuild/darwin-arm64/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# esbuild
|
||||||
|
|
||||||
|
This is the macOS ARM 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
|
||||||
BIN
node_modules/@esbuild/win32-x64/esbuild.exe → node_modules/@esbuild/darwin-arm64/bin/esbuild
generated
vendored
Normal file → Executable file
BIN
node_modules/@esbuild/win32-x64/esbuild.exe → node_modules/@esbuild/darwin-arm64/bin/esbuild
generated
vendored
Normal file → Executable file
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@esbuild/win32-x64",
|
"name": "@esbuild/darwin-arm64",
|
||||||
"version": "0.25.12",
|
"version": "0.25.12",
|
||||||
"description": "The Windows 64-bit binary for esbuild, a JavaScript bundler.",
|
"description": "The macOS ARM 64-bit binary for esbuild, a JavaScript bundler.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/evanw/esbuild.git"
|
"url": "git+https://github.com/evanw/esbuild.git"
|
||||||
|
|
@ -12,9 +12,9 @@
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"darwin"
|
||||||
],
|
],
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"arm64"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
3
node_modules/@esbuild/win32-x64/README.md
generated
vendored
3
node_modules/@esbuild/win32-x64/README.md
generated
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
# esbuild
|
|
||||||
|
|
||||||
This is the Windows 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
|
|
||||||
3
node_modules/@rollup/rollup-darwin-arm64/README.md
generated
vendored
Normal file
3
node_modules/@rollup/rollup-darwin-arm64/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# `@rollup/rollup-darwin-arm64`
|
||||||
|
|
||||||
|
This is the **aarch64-apple-darwin** binary for `rollup`
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
{
|
{
|
||||||
"name": "@rollup/rollup-win32-x64-gnu",
|
"name": "@rollup/rollup-darwin-arm64",
|
||||||
"version": "4.60.1",
|
"version": "4.60.1",
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"darwin"
|
||||||
],
|
],
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"rollup.win32-x64-gnu.node"
|
"rollup.darwin-arm64.node"
|
||||||
],
|
],
|
||||||
"description": "Native bindings for Rollup",
|
"description": "Native bindings for Rollup",
|
||||||
"author": "Lukas Taegert-Atkinson",
|
"author": "Lukas Taegert-Atkinson",
|
||||||
|
|
@ -18,5 +18,5 @@
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/rollup/rollup.git"
|
"url": "git+https://github.com/rollup/rollup.git"
|
||||||
},
|
},
|
||||||
"main": "./rollup.win32-x64-gnu.node"
|
"main": "./rollup.darwin-arm64.node"
|
||||||
}
|
}
|
||||||
BIN
node_modules/@rollup/rollup-darwin-arm64/rollup.darwin-arm64.node
generated
vendored
Normal file
BIN
node_modules/@rollup/rollup-darwin-arm64/rollup.darwin-arm64.node
generated
vendored
Normal file
Binary file not shown.
3
node_modules/@rollup/rollup-win32-x64-gnu/README.md
generated
vendored
3
node_modules/@rollup/rollup-win32-x64-gnu/README.md
generated
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
# `@rollup/rollup-win32-x64-gnu`
|
|
||||||
|
|
||||||
This is the **x86_64-pc-windows-gnu** binary for `rollup`
|
|
||||||
BIN
node_modules/@rollup/rollup-win32-x64-gnu/rollup.win32-x64-gnu.node
generated
vendored
BIN
node_modules/@rollup/rollup-win32-x64-gnu/rollup.win32-x64-gnu.node
generated
vendored
Binary file not shown.
3
node_modules/@rollup/rollup-win32-x64-msvc/README.md
generated
vendored
3
node_modules/@rollup/rollup-win32-x64-msvc/README.md
generated
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
# `@rollup/rollup-win32-x64-msvc`
|
|
||||||
|
|
||||||
This is the **x86_64-pc-windows-msvc** binary for `rollup`
|
|
||||||
22
node_modules/@rollup/rollup-win32-x64-msvc/package.json
generated
vendored
22
node_modules/@rollup/rollup-win32-x64-msvc/package.json
generated
vendored
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@rollup/rollup-win32-x64-msvc",
|
|
||||||
"version": "4.60.1",
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"files": [
|
|
||||||
"rollup.win32-x64-msvc.node"
|
|
||||||
],
|
|
||||||
"description": "Native bindings for Rollup",
|
|
||||||
"author": "Lukas Taegert-Atkinson",
|
|
||||||
"homepage": "https://rollupjs.org/",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/rollup/rollup.git"
|
|
||||||
},
|
|
||||||
"main": "./rollup.win32-x64-msvc.node"
|
|
||||||
}
|
|
||||||
BIN
node_modules/@rollup/rollup-win32-x64-msvc/rollup.win32-x64-msvc.node
generated
vendored
BIN
node_modules/@rollup/rollup-win32-x64-msvc/rollup.win32-x64-msvc.node
generated
vendored
Binary file not shown.
22
node_modules/fsevents/LICENSE
generated
vendored
Normal file
22
node_modules/fsevents/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
MIT License
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Copyright (C) 2010-2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
89
node_modules/fsevents/README.md
generated
vendored
Normal file
89
node_modules/fsevents/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
# fsevents
|
||||||
|
|
||||||
|
Native access to MacOS FSEvents in [Node.js](https://nodejs.org/)
|
||||||
|
|
||||||
|
The FSEvents API in MacOS allows applications to register for notifications of
|
||||||
|
changes to a given directory tree. It is a very fast and lightweight alternative
|
||||||
|
to kqueue.
|
||||||
|
|
||||||
|
This is a low-level library. For a cross-platform file watching module that
|
||||||
|
uses fsevents, check out [Chokidar](https://github.com/paulmillr/chokidar).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install fsevents
|
||||||
|
```
|
||||||
|
|
||||||
|
Supports only **Node.js v8.16 and higher**.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const fsevents = require('fsevents');
|
||||||
|
|
||||||
|
// To start observation
|
||||||
|
const stop = fsevents.watch(__dirname, (path, flags, id) => {
|
||||||
|
const info = fsevents.getInfo(path, flags);
|
||||||
|
});
|
||||||
|
|
||||||
|
// To end observation
|
||||||
|
stop();
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Important note:** The API behaviour is slightly different from typical JS APIs. The `stop` function **must** be
|
||||||
|
> retrieved and stored somewhere, even if you don't plan to stop the watcher. If you forget it, the garbage collector
|
||||||
|
> will eventually kick in, the watcher will be unregistered, and your callbacks won't be called anymore.
|
||||||
|
|
||||||
|
The callback passed as the second parameter to `.watch` get's called whenever the operating system detects a
|
||||||
|
a change in the file system. It takes three arguments:
|
||||||
|
|
||||||
|
###### `fsevents.watch(dirname: string, (path: string, flags: number, id: string) => void): () => Promise<undefined>`
|
||||||
|
|
||||||
|
* `path: string` - the item in the filesystem that have been changed
|
||||||
|
* `flags: number` - a numeric value describing what the change was
|
||||||
|
* `id: string` - an unique-id identifying this specific event
|
||||||
|
|
||||||
|
Returns closer callback which when called returns a Promise resolving when the watcher process has been shut down.
|
||||||
|
|
||||||
|
###### `fsevents.getInfo(path: string, flags: number, id: string): FsEventInfo`
|
||||||
|
|
||||||
|
The `getInfo` function takes the `path`, `flags` and `id` arguments and converts those parameters into a structure
|
||||||
|
that is easier to digest to determine what the change was.
|
||||||
|
|
||||||
|
The `FsEventsInfo` has the following shape:
|
||||||
|
|
||||||
|
```js
|
||||||
|
/**
|
||||||
|
* @typedef {'created'|'modified'|'deleted'|'moved'|'root-changed'|'cloned'|'unknown'} FsEventsEvent
|
||||||
|
* @typedef {'file'|'directory'|'symlink'} FsEventsType
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"event": "created", // {FsEventsEvent}
|
||||||
|
"path": "file.txt",
|
||||||
|
"type": "file", // {FsEventsType}
|
||||||
|
"changes": {
|
||||||
|
"inode": true, // Had iNode Meta-Information changed
|
||||||
|
"finder": false, // Had Finder Meta-Data changed
|
||||||
|
"access": false, // Had access permissions changed
|
||||||
|
"xattrs": false // Had xAttributes changed
|
||||||
|
},
|
||||||
|
"flags": 0x100000000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- v2.3 supports Apple Silicon ARM CPUs
|
||||||
|
- v2 supports node 8.16+ and reduces package size massively
|
||||||
|
- v1.2.8 supports node 6+
|
||||||
|
- v1.2.7 supports node 4+
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- I'm getting `EBADPLATFORM` `Unsupported platform for fsevents` error.
|
||||||
|
- It's fine, nothing is broken. fsevents is macos-only. Other platforms are skipped. If you want to hide this warning, report a bug to NPM bugtracker asking them to hide ebadplatform warnings by default.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License Copyright (C) 2010-2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller — see LICENSE file.
|
||||||
|
|
||||||
|
Visit our [GitHub page](https://github.com/fsevents/fsevents) and [NPM Page](https://npmjs.org/package/fsevents)
|
||||||
46
node_modules/fsevents/fsevents.d.ts
generated
vendored
Normal file
46
node_modules/fsevents/fsevents.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
declare type Event = "created" | "cloned" | "modified" | "deleted" | "moved" | "root-changed" | "unknown";
|
||||||
|
declare type Type = "file" | "directory" | "symlink";
|
||||||
|
declare type FileChanges = {
|
||||||
|
inode: boolean;
|
||||||
|
finder: boolean;
|
||||||
|
access: boolean;
|
||||||
|
xattrs: boolean;
|
||||||
|
};
|
||||||
|
declare type Info = {
|
||||||
|
event: Event;
|
||||||
|
path: string;
|
||||||
|
type: Type;
|
||||||
|
changes: FileChanges;
|
||||||
|
flags: number;
|
||||||
|
};
|
||||||
|
declare type WatchHandler = (path: string, flags: number, id: string) => void;
|
||||||
|
export declare function watch(path: string, handler: WatchHandler): () => Promise<void>;
|
||||||
|
export declare function watch(path: string, since: number, handler: WatchHandler): () => Promise<void>;
|
||||||
|
export declare function getInfo(path: string, flags: number): Info;
|
||||||
|
export declare const constants: {
|
||||||
|
None: 0x00000000;
|
||||||
|
MustScanSubDirs: 0x00000001;
|
||||||
|
UserDropped: 0x00000002;
|
||||||
|
KernelDropped: 0x00000004;
|
||||||
|
EventIdsWrapped: 0x00000008;
|
||||||
|
HistoryDone: 0x00000010;
|
||||||
|
RootChanged: 0x00000020;
|
||||||
|
Mount: 0x00000040;
|
||||||
|
Unmount: 0x00000080;
|
||||||
|
ItemCreated: 0x00000100;
|
||||||
|
ItemRemoved: 0x00000200;
|
||||||
|
ItemInodeMetaMod: 0x00000400;
|
||||||
|
ItemRenamed: 0x00000800;
|
||||||
|
ItemModified: 0x00001000;
|
||||||
|
ItemFinderInfoMod: 0x00002000;
|
||||||
|
ItemChangeOwner: 0x00004000;
|
||||||
|
ItemXattrMod: 0x00008000;
|
||||||
|
ItemIsFile: 0x00010000;
|
||||||
|
ItemIsDir: 0x00020000;
|
||||||
|
ItemIsSymlink: 0x00040000;
|
||||||
|
ItemIsHardlink: 0x00100000;
|
||||||
|
ItemIsLastHardlink: 0x00200000;
|
||||||
|
OwnEvent: 0x00080000;
|
||||||
|
ItemCloned: 0x00400000;
|
||||||
|
};
|
||||||
|
export {};
|
||||||
83
node_modules/fsevents/fsevents.js
generated
vendored
Normal file
83
node_modules/fsevents/fsevents.js
generated
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
** © 2020 by Philipp Dunkel, Ben Noordhuis, Elan Shankar, Paul Miller
|
||||||
|
** Licensed under MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint node:true */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (process.platform !== "darwin") {
|
||||||
|
throw new Error(`Module 'fsevents' is not compatible with platform '${process.platform}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Native = require("./fsevents.node");
|
||||||
|
const events = Native.constants;
|
||||||
|
|
||||||
|
function watch(path, since, handler) {
|
||||||
|
if (typeof path !== "string") {
|
||||||
|
throw new TypeError(`fsevents argument 1 must be a string and not a ${typeof path}`);
|
||||||
|
}
|
||||||
|
if ("function" === typeof since && "undefined" === typeof handler) {
|
||||||
|
handler = since;
|
||||||
|
since = Native.flags.SinceNow;
|
||||||
|
}
|
||||||
|
if (typeof since !== "number") {
|
||||||
|
throw new TypeError(`fsevents argument 2 must be a number and not a ${typeof since}`);
|
||||||
|
}
|
||||||
|
if (typeof handler !== "function") {
|
||||||
|
throw new TypeError(`fsevents argument 3 must be a function and not a ${typeof handler}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let instance = Native.start(Native.global, path, since, handler);
|
||||||
|
if (!instance) throw new Error(`could not watch: ${path}`);
|
||||||
|
return () => {
|
||||||
|
const result = instance ? Promise.resolve(instance).then(Native.stop) : Promise.resolve(undefined);
|
||||||
|
instance = undefined;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInfo(path, flags) {
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
flags,
|
||||||
|
event: getEventType(flags),
|
||||||
|
type: getFileType(flags),
|
||||||
|
changes: getFileChanges(flags),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileType(flags) {
|
||||||
|
if (events.ItemIsFile & flags) return "file";
|
||||||
|
if (events.ItemIsDir & flags) return "directory";
|
||||||
|
if (events.MustScanSubDirs & flags) return "directory";
|
||||||
|
if (events.ItemIsSymlink & flags) return "symlink";
|
||||||
|
}
|
||||||
|
function anyIsTrue(obj) {
|
||||||
|
for (let key in obj) {
|
||||||
|
if (obj[key]) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function getEventType(flags) {
|
||||||
|
if (events.ItemRemoved & flags) return "deleted";
|
||||||
|
if (events.ItemRenamed & flags) return "moved";
|
||||||
|
if (events.ItemCreated & flags) return "created";
|
||||||
|
if (events.ItemModified & flags) return "modified";
|
||||||
|
if (events.RootChanged & flags) return "root-changed";
|
||||||
|
if (events.ItemCloned & flags) return "cloned";
|
||||||
|
if (anyIsTrue(flags)) return "modified";
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
function getFileChanges(flags) {
|
||||||
|
return {
|
||||||
|
inode: !!(events.ItemInodeMetaMod & flags),
|
||||||
|
finder: !!(events.ItemFinderInfoMod & flags),
|
||||||
|
access: !!(events.ItemChangeOwner & flags),
|
||||||
|
xattrs: !!(events.ItemXattrMod & flags),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.watch = watch;
|
||||||
|
exports.getInfo = getInfo;
|
||||||
|
exports.constants = events;
|
||||||
BIN
node_modules/fsevents/fsevents.node
generated
vendored
Executable file
BIN
node_modules/fsevents/fsevents.node
generated
vendored
Executable file
Binary file not shown.
62
node_modules/fsevents/package.json
generated
vendored
Normal file
62
node_modules/fsevents/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"name": "fsevents",
|
||||||
|
"version": "2.3.3",
|
||||||
|
"description": "Native Access to MacOS FSEvents",
|
||||||
|
"main": "fsevents.js",
|
||||||
|
"types": "fsevents.d.ts",
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"fsevents.d.ts",
|
||||||
|
"fsevents.js",
|
||||||
|
"fsevents.node"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "node-gyp clean && rm -f fsevents.node",
|
||||||
|
"build": "node-gyp clean && rm -f fsevents.node && node-gyp rebuild && node-gyp clean",
|
||||||
|
"test": "/bin/bash ./test.sh 2>/dev/null",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/fsevents/fsevents.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"fsevents",
|
||||||
|
"mac"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Philipp Dunkel",
|
||||||
|
"email": "pip@pipobscure.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ben Noordhuis",
|
||||||
|
"email": "info@bnoordhuis.nl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Elan Shankar",
|
||||||
|
"email": "elan.shanker@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Miroslav Bajtoš",
|
||||||
|
"email": "mbajtoss@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Paul Miller",
|
||||||
|
"url": "https://paulmillr.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/fsevents/fsevents/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/fsevents/fsevents",
|
||||||
|
"devDependencies": {
|
||||||
|
"node-gyp": "^9.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
package-lock.json
generated
10
package-lock.json
generated
|
|
@ -67,7 +67,6 @@
|
||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
|
|
@ -1271,7 +1270,6 @@
|
||||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
|
|
@ -1432,7 +1430,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.10.12",
|
"baseline-browser-mapping": "^2.10.12",
|
||||||
"caniuse-lite": "^1.0.30001782",
|
"caniuse-lite": "^1.0.30001782",
|
||||||
|
|
@ -1867,7 +1864,6 @@
|
||||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
|
|
@ -2136,7 +2132,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
|
|
@ -2306,7 +2301,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -2319,7 +2313,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"scheduler": "^0.23.2"
|
"scheduler": "^0.23.2"
|
||||||
|
|
@ -2629,7 +2622,6 @@
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|
@ -2707,7 +2699,6 @@
|
||||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
|
|
@ -2801,7 +2792,6 @@
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
12
src/App.jsx
12
src/App.jsx
|
|
@ -22,7 +22,7 @@ const PERSONAL_INFO = {
|
||||||
|
|
||||||
// --- CREATIVE PERSONA DATA ---
|
// --- CREATIVE PERSONA DATA ---
|
||||||
const CREATIVE_DATA = {
|
const CREATIVE_DATA = {
|
||||||
title: "AI Creative Lead & Motion Designer",
|
title: "Creative Manager & AI Innovation Lead",
|
||||||
summary: "Visionary Creative Leader with 9+ years of expertise bridging brand strategy, digital design, motion graphics, and cutting-edge generative AI. Currently pioneering AI-augmented creative workflows at Phibious, merging traditional art direction with ComfyUI, Stable Diffusion, and FLUX to redefine what's possible in visual storytelling. Previously led eCommerce design at P&G, shaping digital experiences for millions of consumers across Southeast Asia.",
|
summary: "Visionary Creative Leader with 9+ years of expertise bridging brand strategy, digital design, motion graphics, and cutting-edge generative AI. Currently pioneering AI-augmented creative workflows at Phibious, merging traditional art direction with ComfyUI, Stable Diffusion, and FLUX to redefine what's possible in visual storytelling. Previously led eCommerce design at P&G, shaping digital experiences for millions of consumers across Southeast Asia.",
|
||||||
tagline: "Where Design Meets Intelligence",
|
tagline: "Where Design Meets Intelligence",
|
||||||
skills: [
|
skills: [
|
||||||
|
|
@ -94,10 +94,10 @@ const CREATIVE_DATA = {
|
||||||
period: "2025 - Present",
|
period: "2025 - Present",
|
||||||
location: "Ho Chi Minh City",
|
location: "Ho Chi Minh City",
|
||||||
highlights: [
|
highlights: [
|
||||||
"Spearhead the integration of generative AI (ComfyUI, Stable Diffusion, FLUX) into creative workflows, reducing production time by 50%",
|
"Spearheaded the transformation of video production workflows via AI and automation, achieving a 60% measurable gain in output volume",
|
||||||
"Lead cross-functional teams of designers, copywriters, and data analysts to deliver technology-driven creative campaigns",
|
"Acted as a creative multiplier, leading regional stakeholders and cross-functional teams to automate end-to-end content lifecycles",
|
||||||
"Developed proprietary AI tools for mood boarding, concept visualization, and rapid prototyping",
|
"Designed and deployed Agentic AI systems and custom frameworks for rapid concept-to-video prototyping, serving global Fortune 500 brands",
|
||||||
"Created AI-augmented design concepts for digital and physical platforms serving Fortune 500 clients"
|
"Drove Regional Enablement by establishing SOPs and mentoring 20+ producers on prompt engineering, AI ethics, and workflow standardization"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -284,7 +284,7 @@ const LandingPage = ({ onSelect }) => {
|
||||||
transition={{ duration: 0.8, delay: 1 }}
|
transition={{ duration: 0.8, delay: 1 }}
|
||||||
className="text-[10px] font-bold tracking-[0.4em] text-[#1A1A1A]/30 uppercase mb-10 md:mb-12"
|
className="text-[10px] font-bold tracking-[0.4em] text-[#1A1A1A]/30 uppercase mb-10 md:mb-12"
|
||||||
>
|
>
|
||||||
AI Creative Lead & Motion Designer
|
Creative Manager & AI Innovation Lead
|
||||||
</motion.p>
|
</motion.p>
|
||||||
|
|
||||||
{/* Enter Button (Desktop only) */}
|
{/* Enter Button (Desktop only) */}
|
||||||
|
|
|
||||||
|
|
@ -1,310 +1,418 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const PERSONAL_INFO = {
|
const PRINT_PERSONAL_INFO = {
|
||||||
name: "VO NGUYEN DANG KHOA",
|
name: "Khoa.vo",
|
||||||
title: "AI CREATIVE LEAD & SOFTWARE DEVELOPER",
|
title: "CREATIVE MANAGER & AI INNOVATION LEAD",
|
||||||
dob: "19/01/1993",
|
location: "Ho Chi Minh City, Vietnam",
|
||||||
nationality: "Vietnam",
|
|
||||||
marital: "Married",
|
|
||||||
gender: "Male",
|
|
||||||
phone: "0398300340",
|
phone: "0398300340",
|
||||||
email: "vonguyendangkhoa@gmail.com",
|
email: "vonguyendangkhoa@gmail.com",
|
||||||
location: "Ho Chi Minh City, Vietnam",
|
|
||||||
linkedin: "linkedin.com/in/khoavo",
|
linkedin: "linkedin.com/in/khoavo",
|
||||||
portfolio: "khoavo.myds.me",
|
portfolio: "khoavo.myds.me",
|
||||||
github: "git.khoavo.myds.me/vndangkhoa",
|
summaryHeadline: "Visionary Creative Leader merging Brand Strategy with Generative AI.",
|
||||||
summary: "Highly accomplished Creative Leader bridging the gap between artistic direction and high-performance software engineering. With over 9+ years managing brand strategies and digital design, I evaluate and execute technology-driven projects from concept to production. Specialized in merging traditional creative direction with cutting-edge generative AI workflows (ComfyUI, FLUX) and full-stack development (Go, React)."
|
summaryBody: "With 9+ years of expertise at global firms like P&G and Phibious, I bridge the gap between artistic direction and high-performance automation. I specialize in designing scalable AI video production workflows and agentic systems that serve Fortune 500 brands while driving measurable growth and operational excellence.\n\nBeyond traditional creative direction, my recent evolution into an AI-Powered Developer enables me to architect custom web applications and full-stack deployment pipelines (React, Go, Docker). By unifying deep brand-building experience with hands-on coding and machine learning integration, I transform creative conceptualization into quantifiable, automated, and highly scalable digital realities."
|
||||||
};
|
};
|
||||||
|
|
||||||
const EDUCATION = [
|
const PRINT_EDUCATION = [
|
||||||
{
|
{
|
||||||
period: "12/2012 - 06/2016",
|
period: "2012 - 2016",
|
||||||
school: "RMIT Vietnam",
|
school: "RMIT University",
|
||||||
degree: "Bachelor of Multimedia System Design (Graduated with Excellence)"
|
degree: "Bachelor of Multimedia Design",
|
||||||
|
details: "Graduated with Excellence."
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const SKILLS = [
|
const PRINT_SKILLS = [
|
||||||
{ category: "Creative & AI Tools", items: "Adobe Creative Suite (Ps, Ai, Id, Pr), ComfyUI, Stable Diffusion, FLUX, Ollama, 3D Animation, Motion Graphics" },
|
"Creative Direction", "Brand Strategy", "Team Mentorship",
|
||||||
{ category: "Development Stack", items: "React, Next.js, Go (Gin), Rust (Axum), Python (FastAPI), TypeScript, Tailwind CSS" },
|
"GenAI Workflows", "ComfyUI & FLUX", "AI Video Systems",
|
||||||
{ category: "Infrastructure", items: "Docker, SQLite, Synology NAS Deployment, HLS Video Streaming" },
|
"Adobe Creative Suite", "Motion Graphics", "3D Visualization",
|
||||||
{ category: "Leadership", items: "Cross-Functional Management, Creative Strategy, Technical Mentorship, Process Optimization" }
|
"Full-Stack Dev", "Agentic AI", "Automation SOPs"
|
||||||
];
|
];
|
||||||
|
|
||||||
const EXPERIENCES = [
|
const PRINT_EXPERIENCES = [
|
||||||
{
|
{
|
||||||
role: "AI Creative Lead", company: "Phibious Viet Nam", period: "06/2024 - Present",
|
role: "AI Creative Lead",
|
||||||
|
company: "Phibious Vietnam",
|
||||||
|
period: "Jun 2025 - Present",
|
||||||
highlights: [
|
highlights: [
|
||||||
"Manage highly complex, technology-driven creative projects, merging traditional design with advanced generative AI models and data analytics.",
|
"Spearheaded the transformation of video production workflows via AI and automation, achieving a 60% measurable gain in output volume.",
|
||||||
"Deploy and utilize ComfyUI, Stable Diffusion, FLUX, and local LLMs (Ollama, LM Studio) to augment design workflows and drive overarching agency strategies.",
|
"Acted as a creative multiplier, leading regional stakeholders and cross-functional teams to automate end-to-end content lifecycles.",
|
||||||
"Lead cross-functional collaboration between traditional designers, copywriters, and data analysts to ensure measurable campaign performance.",
|
"Standardized end-to-end AI video production SOPs—ranging from AI-led scripting to automated localization—ensuring brand compliance across Southeast Asian markets.",
|
||||||
"Optimize internal design processes by integrating advanced image generation pipelines into daily operations.",
|
"Drove Regional Enablement by mentoring 20+ producers on prompt engineering, AI ethics, and workflow standardization."
|
||||||
"Train and mentor the broader agency (including interns) on core AI design competencies and prompt engineering."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "eCOM Design Lead", company: "Procter & Gamble (P&G) Vietnam", period: "09/2023 - 06/2025",
|
role: "eCOM Design Lead",
|
||||||
|
company: "Procter & Gamble",
|
||||||
|
period: "Sep 2023 - Jun 2025",
|
||||||
highlights: [
|
highlights: [
|
||||||
"Spearheaded strategic design concepts and visual strategies for e-commerce, directly impacting consumer engagement and online sales for Hair Care brands.",
|
"Directed visual strategies for P&G's Hair Care portfolio across SEA, impacting millions of consumers effectively.",
|
||||||
"Managed end-to-end medium-to-large design projects, actively improving internal design processes and ensuring strict corporate standard compliance.",
|
"Managed end-to-end design lifecycles, ensuring strict brand compliance and high-volume output across regional markets.",
|
||||||
"Collaborated globally across functional geographic boundaries and cross-functional teams to deliver cohesive brand stories."
|
"Collaborated with global brand teams to localize and scale omnichannel retail experiences."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "ECOM Graphic Designer (ABM)", company: "P&G Viet Nam", period: "11/2020 - 09/2023",
|
role: "Associate Brand Manager (Design)",
|
||||||
|
company: "P&G Vietnam",
|
||||||
|
period: "Nov 2020 - Sep 2023",
|
||||||
highlights: [
|
highlights: [
|
||||||
"Built concepts and executed visual strategy across vast consumer touchpoints including packaging, eCommerce, and social media under the Hair Care Packaging Design Studio.",
|
"Developed core visual concepts for major product launches, including packaging and digital touchpoints for regional SEA markets.",
|
||||||
"Leveraged hands-on design mastery to craft illustrations and brand expressions that consistently met high commercial demands.",
|
"Optimized internal design processes, reducing asset turnaround time for regional marketing teams by 30%.",
|
||||||
"Ensured brand guidelines and directives were embraced consistently and creatively across all regional platforms."
|
"Mastered corporate identity systems, ensuring consistent brand expression across all platforms and physical retail environments."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "Production Creative Lead", company: "Inn Saigon", period: "12/2019 - 11/2020",
|
role: "Production Creative Lead",
|
||||||
|
company: "Inn Saigon",
|
||||||
|
period: "Dec 2019 - Nov 2020",
|
||||||
highlights: [
|
highlights: [
|
||||||
"Led the photography and production team, setting the standard for internal branding deliverables (Food, Product, Events).",
|
"Directed a multi-disciplinary team of photographers and retouchers for high-profile hospitality clients.",
|
||||||
"Managed project budgets, retouching workflows, and cross-team communications to deliver high-volume outcomes.",
|
"Managed production budgets and resource allocation for 30+ simultaneous client accounts.",
|
||||||
"Conducted frequent feedback sessions to boost performance and facilitate the development of team members."
|
"Implemented quality control frameworks that reduced post-production errors by 40%."
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "Regional Head of Design", company: "ASIAMARINE", period: "12/2018 - 12/2019",
|
|
||||||
highlights: [
|
|
||||||
"Supervised all creation of concepts and layouts across digital/offline marketing for luxury marine sectors.",
|
|
||||||
"Managed independent contractors and junior designers, leveraging creative marketing to develop targeted campaigns."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "Senior Graphic Designer", company: "EMG", period: "12/2017 - 12/2018",
|
|
||||||
highlights: [
|
|
||||||
"Created outstanding digital and print designs, managing corporate identity, merchandise, and digital displays.",
|
|
||||||
"Assisted with concept proposals to clients including mockup preparations and asset sourcing."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "Graphic Artist", company: "Le Meridien Saigon", period: "12/2016 - 12/2017",
|
|
||||||
highlights: [
|
|
||||||
"Designed and executed all promotional collateral according to strict Le Meridien brand identity guidelines.",
|
|
||||||
"Liaised with external suppliers to ensure creative print quality and deadlines were consistently met."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "Animation Designer", company: "Adidas Group", period: "06/2016 - 12/2016",
|
|
||||||
highlights: [
|
|
||||||
"Developed graphics and animations for production environment simulations (Line Balancing, One Pair Flow).",
|
|
||||||
"Compiled and edited video infographics for visual training purposes."
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const IT_PROJECTS = [
|
const PRINT_STRATEGIC_TECH = [
|
||||||
{ name: "KV-Tube", tech: "Go (Gin), Next.js, SQLite, Docker, HLS.js", desc: "YouTube-like video streaming platform with HLS support, subscriptions, and Synology NAS deployment." },
|
{ name: "KV-Tube", tech: "Go, Next.js, Docker", desc: "Enterprise-grade HLS video streaming platform with custom NAS deployment architecture." },
|
||||||
{ name: "Spotify Clone", tech: "React, Rust (Axum), YouTube API", desc: "Full-featured music player with real-time lyrics and custom playlists." },
|
{ name: "APIx GenAI", tech: "TypeScript, LLM APIs", desc: "A custom AI image generation portal integrating multiple LLM and Diffusion providers." }
|
||||||
{ name: "APIx (kv-pix)", tech: "Next.js 14, TypeScript, Prisma", desc: "AI Image Generator powered by multiple providers (Grok, Meta, Whisk)." }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const REFERENCES = [
|
// --- BRANDING COMPONENT (B&W Friendly) ---
|
||||||
{ name: "Dung Bui", title: "Senior Manager", company: "Adidas Group", contact: "dung.bui@adidas-group.com" },
|
const PRINT_VNDKLogo = ({ size = 100, vnColor = "#000000", dkColor = "#333333" }) => (
|
||||||
{ name: "Wouter Pasman", title: "Graphic Designer", company: "FreshStudio.vn", contact: "0908074383" },
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width={size} height={size} fill="none" strokeWidth="6" strokeLinecap="round" strokeLinejoin="round">
|
||||||
{ name: "Tran Nhuan Vu", title: "Marketing Mgr", company: "Element Mgmt", contact: "Vu.tran@element.vn" }
|
<path stroke={vnColor} d="M 15 25 L 30 45 L 45 25" />
|
||||||
];
|
<path stroke={vnColor} d="M 55 45 L 55 25 L 85 45 L 85 25" />
|
||||||
|
<path stroke={dkColor} d="M 15 55 L 30 55 A 10 10 0 0 1 30 75 L 15 75 Z" />
|
||||||
|
<path stroke={dkColor} d="M 55 55 L 55 75 M 85 55 L 55 65 L 85 75" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
const s = {
|
const PRINT_COLORS = {
|
||||||
pageContainer: {
|
accent: '#222222', // Replaced mint with dark grey for B&W printing
|
||||||
width: '210mm',
|
black: '#000000',
|
||||||
padding: '14mm 16mm',
|
white: '#FFFFFF',
|
||||||
background: '#ffffff',
|
grey: '#444444',
|
||||||
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
muted: '#666666',
|
||||||
color: '#000000',
|
border: '#DDDDDD'
|
||||||
fontSize: '9pt',
|
};
|
||||||
lineHeight: '1.5',
|
|
||||||
|
const PRINT_STYLES = {
|
||||||
|
container: {
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '210mm',
|
||||||
|
background: PRINT_COLORS.white,
|
||||||
|
fontFamily: "'Inter', sans-serif",
|
||||||
|
color: PRINT_COLORS.black,
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 1,
|
||||||
},
|
},
|
||||||
header: {
|
documentContainer: {
|
||||||
borderBottom: '2px solid #000',
|
padding: '0',
|
||||||
paddingBottom: '4mm',
|
backgroundColor: PRINT_COLORS.white,
|
||||||
marginBottom: '4mm',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
headerWrapper: {
|
||||||
|
backgroundColor: PRINT_COLORS.white,
|
||||||
|
padding: '16mm 18mm 12mm 18mm',
|
||||||
|
width: '100%',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
borderTop: `6mm solid ${PRINT_COLORS.black}`,
|
||||||
|
borderBottom: `1px solid ${PRINT_COLORS.border}`,
|
||||||
|
marginBottom: '10mm'
|
||||||
|
},
|
||||||
|
topHeader: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: '10mm',
|
||||||
|
},
|
||||||
|
logoSlot: {
|
||||||
|
border: `2px solid ${PRINT_COLORS.black}`,
|
||||||
|
padding: '2mm',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: PRINT_COLORS.white,
|
||||||
|
},
|
||||||
|
nameTitle: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flex: 1,
|
||||||
|
marginLeft: '12mm',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
fontSize: '25pt',
|
fontSize: '28pt',
|
||||||
fontWeight: 900,
|
fontWeight: 800,
|
||||||
letterSpacing: '-0.02em',
|
letterSpacing: '-0.02em',
|
||||||
margin: '0 0 4px 0',
|
color: PRINT_COLORS.black,
|
||||||
lineHeight: '1',
|
marginBottom: '1mm',
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: '11pt',
|
fontSize: '12pt',
|
||||||
fontWeight: 600,
|
fontWeight: 700,
|
||||||
color: '#333',
|
color: PRINT_COLORS.muted,
|
||||||
margin: '0 0 4mm 0',
|
letterSpacing: '0.08em',
|
||||||
letterSpacing: '0.05em',
|
|
||||||
},
|
|
||||||
infoGrid: {
|
|
||||||
display: 'flex',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
gap: '3mm 8mm',
|
|
||||||
fontSize: '8pt',
|
|
||||||
color: '#444',
|
|
||||||
},
|
|
||||||
sectionTitle: {
|
|
||||||
fontSize: '11pt',
|
|
||||||
fontWeight: 800,
|
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: '0.05em',
|
|
||||||
borderBottom: '1px solid #ccc',
|
|
||||||
paddingBottom: '1.5mm',
|
|
||||||
margin: '5mm 0 3mm 0',
|
|
||||||
color: '#000',
|
|
||||||
},
|
},
|
||||||
summary: {
|
contactInfo: {
|
||||||
|
textAlign: 'right',
|
||||||
fontSize: '9pt',
|
fontSize: '9pt',
|
||||||
lineHeight: '1.5',
|
fontWeight: 600,
|
||||||
margin: '0 0 4mm 0',
|
color: PRINT_COLORS.black,
|
||||||
|
lineHeight: '1.8',
|
||||||
|
},
|
||||||
|
headerLine: {
|
||||||
|
width: '100%',
|
||||||
|
height: '1.5px',
|
||||||
|
backgroundColor: PRINT_COLORS.black,
|
||||||
|
margin: '8mm 0 4mm 0',
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
headerLineAccent: {
|
||||||
|
position: 'absolute',
|
||||||
|
right: '0',
|
||||||
|
top: '0',
|
||||||
|
width: '30%',
|
||||||
|
height: '1.5px',
|
||||||
|
backgroundColor: PRINT_COLORS.accent,
|
||||||
|
},
|
||||||
|
summaryHeadline: {
|
||||||
|
fontSize: '22pt',
|
||||||
|
fontWeight: 800,
|
||||||
|
lineHeight: '1.2',
|
||||||
|
marginBottom: '8mm',
|
||||||
|
color: PRINT_COLORS.black,
|
||||||
|
maxWidth: '90%',
|
||||||
|
},
|
||||||
|
summaryParagraph: {
|
||||||
|
fontSize: '11pt',
|
||||||
|
color: PRINT_COLORS.grey,
|
||||||
|
marginBottom: '12mm',
|
||||||
textAlign: 'justify',
|
textAlign: 'justify',
|
||||||
|
lineHeight: '1.7',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
},
|
},
|
||||||
skillGrid: {
|
skillsGrid: {
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
gridTemplateColumns: '1fr 1fr',
|
gridTemplateColumns: 'repeat(3, 1fr)',
|
||||||
gap: '2mm 5mm',
|
gap: '3mm 10mm',
|
||||||
marginBottom: '3mm',
|
|
||||||
},
|
},
|
||||||
experienceItem: {
|
skillItem: {
|
||||||
marginBottom: '4mm',
|
fontSize: '10pt',
|
||||||
},
|
|
||||||
expHeader: {
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
alignItems: 'center',
|
||||||
alignItems: 'baseline',
|
gap: '4mm',
|
||||||
marginBottom: '1.5mm',
|
fontWeight: 600,
|
||||||
|
},
|
||||||
|
skillIcon: {
|
||||||
|
width: '6mm',
|
||||||
|
height: '1.5px',
|
||||||
|
backgroundColor: PRINT_COLORS.accent,
|
||||||
|
},
|
||||||
|
mainBody: {
|
||||||
|
padding: '0 18mm',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
sectionHeading: {
|
||||||
|
fontSize: '11pt',
|
||||||
|
fontWeight: 900,
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: '0.2em',
|
||||||
|
marginBottom: '10mm',
|
||||||
|
color: PRINT_COLORS.black,
|
||||||
|
borderLeft: `5mm solid ${PRINT_COLORS.accent}`,
|
||||||
|
paddingLeft: '5mm',
|
||||||
|
pageBreakAfter: 'avoid',
|
||||||
|
breakAfter: 'avoid'
|
||||||
|
},
|
||||||
|
experienceRow: {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1.3fr 2fr',
|
||||||
|
gap: '12mm',
|
||||||
|
marginBottom: '12mm',
|
||||||
|
},
|
||||||
|
experienceMeta: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
},
|
},
|
||||||
expRole: {
|
expRole: {
|
||||||
fontSize: '10pt',
|
fontSize: '13pt',
|
||||||
fontWeight: 700,
|
fontWeight: 800,
|
||||||
margin: 0,
|
marginBottom: '2mm',
|
||||||
},
|
},
|
||||||
expCompany: {
|
expCompany: {
|
||||||
|
fontSize: '10.5pt',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: '#333',
|
color: PRINT_COLORS.muted,
|
||||||
},
|
},
|
||||||
expPeriod: {
|
expPeriod: {
|
||||||
fontSize: '8pt',
|
|
||||||
color: '#555',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
expList: {
|
|
||||||
margin: '0',
|
|
||||||
paddingLeft: '5mm',
|
|
||||||
},
|
|
||||||
expBullet: {
|
|
||||||
marginBottom: '1mm',
|
|
||||||
textAlign: 'justify',
|
|
||||||
},
|
|
||||||
projectItem: {
|
|
||||||
marginBottom: '2.5mm',
|
|
||||||
},
|
|
||||||
projectHeader: {
|
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: '9.5pt',
|
fontSize: '9.5pt',
|
||||||
},
|
color: PRINT_COLORS.muted,
|
||||||
projectTech: {
|
marginTop: '3mm',
|
||||||
fontSize: '7.5pt',
|
|
||||||
color: '#555',
|
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
marginLeft: '2mm',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
refGrid: {
|
expHighlights: {
|
||||||
|
margin: 0,
|
||||||
|
paddingLeft: '6mm',
|
||||||
|
listStyleType: 'none',
|
||||||
|
},
|
||||||
|
highlightItem: {
|
||||||
|
marginBottom: '4mm',
|
||||||
|
textAlign: 'justify',
|
||||||
|
fontSize: '10.5pt',
|
||||||
|
position: 'relative',
|
||||||
|
lineHeight: '1.6',
|
||||||
|
pageBreakInside: 'avoid',
|
||||||
|
breakInside: 'avoid'
|
||||||
|
},
|
||||||
|
highlightBullet: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: '-6mm',
|
||||||
|
top: '2.5mm',
|
||||||
|
width: '3.5mm',
|
||||||
|
height: '1px',
|
||||||
|
backgroundColor: PRINT_COLORS.accent,
|
||||||
|
},
|
||||||
|
techMeta: {
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: '10pt',
|
||||||
|
color: PRINT_COLORS.black,
|
||||||
|
backgroundColor: PRINT_COLORS.white,
|
||||||
|
padding: '1.5mm 3mm',
|
||||||
|
borderLeft: `2px solid ${PRINT_COLORS.accent}`,
|
||||||
|
border: `1px solid ${PRINT_COLORS.border}`,
|
||||||
|
marginTop: '3mm',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
marginTop: '10mm',
|
||||||
|
padding: '10mm 18mm',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '9pt',
|
||||||
|
color: PRINT_COLORS.muted,
|
||||||
|
borderTop: `1px solid ${PRINT_COLORS.border}`,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
fontSize: '8pt',
|
alignItems: 'center',
|
||||||
marginTop: '2mm',
|
pageBreakInside: 'avoid',
|
||||||
|
breakInside: 'avoid'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PrintPortfolio() {
|
export default function PrintPortfolio() {
|
||||||
|
if (!PRINT_PERSONAL_INFO) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={s.pageContainer}>
|
<div style={PRINT_STYLES.container} className="print-portfolio-content">
|
||||||
|
<div style={PRINT_STYLES.documentContainer}>
|
||||||
{/* HEADER SECTION */}
|
{/* --- HEADER --- */}
|
||||||
<div style={s.header}>
|
<div style={PRINT_STYLES.headerWrapper}>
|
||||||
<h1 style={s.name}>{PERSONAL_INFO.name}</h1>
|
<div style={PRINT_STYLES.topHeader}>
|
||||||
<div style={s.title}>{PERSONAL_INFO.title}</div>
|
<div style={PRINT_STYLES.logoSlot}>
|
||||||
<div style={s.infoGrid}>
|
<PRINT_VNDKLogo size={64} />
|
||||||
<span><strong>Email:</strong> {PERSONAL_INFO.email}</span>
|
</div>
|
||||||
<span><strong>Phone:</strong> {PERSONAL_INFO.phone}</span>
|
<div style={PRINT_STYLES.nameTitle}>
|
||||||
<span><strong>Location:</strong> {PERSONAL_INFO.location}</span>
|
<h1 style={PRINT_STYLES.name}>{PRINT_PERSONAL_INFO.name}</h1>
|
||||||
<span><strong>Portfolio:</strong> {PERSONAL_INFO.portfolio}</span>
|
<div style={PRINT_STYLES.title}>{PRINT_PERSONAL_INFO.title}</div>
|
||||||
<span><strong>GitHub:</strong> {PERSONAL_INFO.github}</span>
|
</div>
|
||||||
<span><strong>DOB:</strong> {PERSONAL_INFO.dob}</span>
|
<div style={PRINT_STYLES.contactInfo}>
|
||||||
|
<div>{PRINT_PERSONAL_INFO.email}</div>
|
||||||
|
<div>{PRINT_PERSONAL_INFO.phone}</div>
|
||||||
|
<div style={{color: PRINT_COLORS.muted, textDecoration: 'underline'}}>{PRINT_PERSONAL_INFO.portfolio}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={PRINT_STYLES.headerLine}>
|
||||||
|
<div style={PRINT_STYLES.headerLineAccent}></div>
|
||||||
|
</div>
|
||||||
|
<div style={{...PRINT_STYLES.expPeriod, marginBottom: '10mm', textAlign: 'right'}}>{PRINT_PERSONAL_INFO.location}</div>
|
||||||
|
|
||||||
|
<h2 style={PRINT_STYLES.summaryHeadline}>{PRINT_PERSONAL_INFO.summaryHeadline}</h2>
|
||||||
|
<p style={PRINT_STYLES.summaryParagraph}>{PRINT_PERSONAL_INFO.summaryBody}</p>
|
||||||
|
|
||||||
|
<div style={{marginBottom: '8mm', fontSize: '10.5pt', fontWeight: 900, textTransform: 'uppercase', color: PRINT_COLORS.black, letterSpacing: '0.15em'}}>Branded Expertise</div>
|
||||||
|
<div style={PRINT_STYLES.skillsGrid}>
|
||||||
|
{PRINT_SKILLS.map((skill, i) => (
|
||||||
|
<div key={i} style={PRINT_STYLES.skillItem}>
|
||||||
|
<div style={PRINT_STYLES.skillIcon}></div>
|
||||||
|
{skill}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* --- MAIN CONTENT CONTINUOUS --- */}
|
||||||
|
<div style={PRINT_STYLES.mainBody}>
|
||||||
|
<div style={PRINT_STYLES.sectionHeading}>Experience Journey</div>
|
||||||
|
|
||||||
|
{PRINT_EXPERIENCES.map((exp, i) => (
|
||||||
|
<div key={i} style={PRINT_STYLES.experienceRow}>
|
||||||
|
<div style={PRINT_STYLES.experienceMeta}>
|
||||||
|
<div style={PRINT_STYLES.expRole}>{exp.role}</div>
|
||||||
|
<div style={PRINT_STYLES.expCompany}>{exp.company}</div>
|
||||||
|
<div style={PRINT_STYLES.expPeriod}>{exp.period}</div>
|
||||||
|
</div>
|
||||||
|
<ul style={PRINT_STYLES.expHighlights}>
|
||||||
|
{exp.highlights && exp.highlights.map((h, j) => (
|
||||||
|
<li key={j} style={PRINT_STYLES.highlightItem}>
|
||||||
|
<div style={PRINT_STYLES.highlightBullet}></div>
|
||||||
|
{h}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div style={{...PRINT_STYLES.sectionHeading, marginTop: '8mm'}}>Branded Systems & Tech</div>
|
||||||
|
{PRINT_STRATEGIC_TECH.map((proj, i) => (
|
||||||
|
<div key={i} style={PRINT_STYLES.experienceRow}>
|
||||||
|
<div style={PRINT_STYLES.experienceMeta}>
|
||||||
|
<div style={{...PRINT_STYLES.expRole, fontSize: '12pt'}}>{proj.name}</div>
|
||||||
|
<div style={PRINT_STYLES.techMeta}>{proj.tech}</div>
|
||||||
|
</div>
|
||||||
|
<div style={{fontSize: '11pt', color: PRINT_COLORS.grey, lineHeight: '1.7'}}>
|
||||||
|
{proj.desc}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div style={{...PRINT_STYLES.sectionHeading, marginTop: '8mm'}}>Foundation & Recognition</div>
|
||||||
|
<div style={PRINT_STYLES.experienceRow}>
|
||||||
|
<div style={PRINT_STYLES.experienceMeta}>
|
||||||
|
<div style={PRINT_STYLES.expRole}>{PRINT_EDUCATION[0].school}</div>
|
||||||
|
<div style={PRINT_STYLES.expPeriod}>{PRINT_EDUCATION[0].period}</div>
|
||||||
|
</div>
|
||||||
|
<div style={{fontSize: '11pt', color: PRINT_COLORS.grey}}>
|
||||||
|
<strong style={{color: PRINT_COLORS.black}}>{PRINT_EDUCATION[0].degree}</strong> ({PRINT_EDUCATION[0].details})<br/>
|
||||||
|
<div style={{marginTop: '6mm', borderTop: `1px solid ${PRINT_COLORS.border}`, paddingTop: '4mm'}}>
|
||||||
|
<div style={{display: 'grid', gridTemplateColumns: '1fr', gap: '3mm'}}>
|
||||||
|
<div style={{display: 'flex', alignItems: 'center', gap: '3mm'}}>
|
||||||
|
<div style={{...PRINT_STYLES.skillIcon, width: '4mm'}}></div>
|
||||||
|
<span>P&G SEA Digital Awards (Best Digital Campaign, 2024)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* --- FOOTER --- */}
|
||||||
|
<div style={PRINT_STYLES.footer}>
|
||||||
|
<div style={{display: 'flex', gap: '6mm'}}>
|
||||||
|
<span>{PRINT_PERSONAL_INFO.linkedin}</span>
|
||||||
|
<span>{PRINT_PERSONAL_INFO.portfolio}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{display: 'flex', alignItems: 'center', gap: '4mm'}}>
|
||||||
|
<PRINT_VNDKLogo size={24} />
|
||||||
|
<span style={{fontWeight: 900, color: PRINT_COLORS.black}}>VNDK // CV</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* SUMMARY */}
|
|
||||||
<p style={s.summary}>{PERSONAL_INFO.summary}</p>
|
|
||||||
|
|
||||||
{/* SKILLS */}
|
|
||||||
<h2 style={s.sectionTitle}>Core Competencies</h2>
|
|
||||||
<div style={s.skillGrid}>
|
|
||||||
{SKILLS.map((skill, idx) => (
|
|
||||||
<div key={idx}>
|
|
||||||
<strong style={{display: 'block', fontSize: '9pt', marginBottom: '1mm'}}>{skill.category}</strong>
|
|
||||||
<span style={{fontSize: '8.5pt', color: '#333'}}>{skill.items}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* EXPERIENCE */}
|
|
||||||
<h2 style={s.sectionTitle}>Work Experience</h2>
|
|
||||||
<div>
|
|
||||||
{EXPERIENCES.map((exp, idx) => (
|
|
||||||
<div key={idx} style={s.experienceItem}>
|
|
||||||
<div style={s.expHeader}>
|
|
||||||
<h3 style={s.expRole}>{exp.role} <span style={{fontWeight: 400}}>at</span> <span style={s.expCompany}>{exp.company}</span></h3>
|
|
||||||
<span style={s.expPeriod}>{exp.period}</span>
|
|
||||||
</div>
|
|
||||||
<ul style={s.expList}>
|
|
||||||
{exp.highlights.map((bullet, bIdx) => (
|
|
||||||
<li key={bIdx} style={s.expBullet}>{bullet}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* SOFTWARE PROJECTS */}
|
|
||||||
<h2 style={s.sectionTitle}>Software Engineering Projects</h2>
|
|
||||||
<div>
|
|
||||||
{IT_PROJECTS.map((proj, idx) => (
|
|
||||||
<div key={idx} style={s.projectItem}>
|
|
||||||
<span style={s.projectHeader}>{proj.name}</span>
|
|
||||||
<span style={s.projectTech}>[{proj.tech}]</span>
|
|
||||||
<span style={{display: 'block', fontSize: '8.5pt', color: '#333', marginTop: '1mm'}}>{proj.desc}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* EDUCATION */}
|
|
||||||
<h2 style={s.sectionTitle}>Education</h2>
|
|
||||||
<div style={{marginBottom: '6mm'}}>
|
|
||||||
{EDUCATION.map((edu, idx) => (
|
|
||||||
<div key={idx} style={{display: 'flex', justifyContent: 'space-between'}}>
|
|
||||||
<strong>{edu.school}</strong>
|
|
||||||
<span>{edu.degree}</span>
|
|
||||||
<span style={s.expPeriod}>{edu.period}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* REFERENCES */}
|
|
||||||
<h2 style={s.sectionTitle}>References</h2>
|
|
||||||
<div style={s.refGrid}>
|
|
||||||
{REFERENCES.map((ref, idx) => (
|
|
||||||
<div key={idx}>
|
|
||||||
<strong>{ref.name}</strong><br/>
|
|
||||||
<span style={{color: '#555'}}>{ref.title}, {ref.company}</span><br/>
|
|
||||||
<span>{ref.contact}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
337
src/print.css
337
src/print.css
|
|
@ -1,40 +1,51 @@
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
html {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: #020617;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
PRINT STYLES - A4 Portfolio PDF
|
PRINT STYLES - A4 Portfolio PDF
|
||||||
============================================ */
|
============================================ */
|
||||||
|
|
||||||
|
/* Hide by default on screen so it doesn't break web app layout */
|
||||||
|
.print-portfolio {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-portfolio.show-preview {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #0f172a;
|
||||||
|
padding: 40px 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-portfolio.show-preview .cv-page {
|
||||||
|
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5);
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@page {
|
@page {
|
||||||
size: A4;
|
size: A4;
|
||||||
margin: 0;
|
margin: 15mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
width: 100% !important;
|
||||||
-webkit-print-color-adjust: exact;
|
background: #ffffff !important;
|
||||||
print-color-adjust: exact;
|
-webkit-print-color-adjust: exact !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide the main UI components, only show print portfolio */
|
/* Hide everything except the print-portfolio container */
|
||||||
body > * {
|
body > *:not(#root) {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#root > *:not(.print-portfolio) {
|
#root > *:not(.print-portfolio) {
|
||||||
|
|
@ -43,290 +54,10 @@ body {
|
||||||
|
|
||||||
.print-portfolio {
|
.print-portfolio {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
width: 210mm;
|
width: 100% !important;
|
||||||
margin: 0 auto;
|
margin: 0 auto !important;
|
||||||
}
|
padding: 0 !important;
|
||||||
|
background: #ffffff;
|
||||||
/* Clear out legacy rigid page formats */
|
position: static !important;
|
||||||
.page, .page-content, .cover-page, .contact-page, .portfolio-grid {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-content {
|
|
||||||
text-align: center;
|
|
||||||
color: #ffffff;
|
|
||||||
padding: 40mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-name {
|
|
||||||
font-size: 38pt;
|
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: -0.02em;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-title {
|
|
||||||
font-size: 16pt;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #666666;
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
letter-spacing: 0.15em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-contact {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 8px 20px;
|
|
||||||
font-size: 9pt;
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-contact span {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SECTIONS */
|
|
||||||
.section {
|
|
||||||
margin-bottom: 8mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 16pt;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #000000;
|
|
||||||
margin: 0 0 6mm 0;
|
|
||||||
padding-bottom: 3mm;
|
|
||||||
border-bottom: 2px solid #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SUMMARY */
|
|
||||||
.summary-section {
|
|
||||||
background: #f8fafc;
|
|
||||||
padding: 6mm;
|
|
||||||
border-radius: 4mm;
|
|
||||||
border-left: 4px solid #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-text {
|
|
||||||
font-size: 10pt;
|
|
||||||
line-height: 1.7;
|
|
||||||
color: #333333;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EXPERIENCE */
|
|
||||||
.experience-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-item {
|
|
||||||
padding-bottom: 5mm;
|
|
||||||
border-bottom: 1px solid #e2e8f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin-bottom: 2mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-role {
|
|
||||||
font-size: 12pt;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #0f172a;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-company {
|
|
||||||
font-size: 9pt;
|
|
||||||
color: #333333;
|
|
||||||
margin: 2px 0 0 0;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-period {
|
|
||||||
font-size: 8pt;
|
|
||||||
color: #64748b;
|
|
||||||
white-space: nowrap;
|
|
||||||
background: #f1f5f9;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid #e2e8f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-highlights {
|
|
||||||
margin: 3mm 0 0 0;
|
|
||||||
padding-left: 5mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experience-highlights li {
|
|
||||||
font-size: 9pt;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: #475569;
|
|
||||||
margin-bottom: 2mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SKILLS */
|
|
||||||
.skills-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 4mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skill-category {
|
|
||||||
background: #f8fafc;
|
|
||||||
padding: 4mm;
|
|
||||||
border-radius: 3mm;
|
|
||||||
border-left: 3px solid #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skill-category h3 {
|
|
||||||
font-size: 10pt;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #0f172a;
|
|
||||||
margin: 0 0 2mm 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skill-category p {
|
|
||||||
font-size: 8.5pt;
|
|
||||||
color: #475569;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PORTFOLIO */
|
|
||||||
.portfolio-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-item {
|
|
||||||
display: flex;
|
|
||||||
gap: 4mm;
|
|
||||||
background: #f8fafc;
|
|
||||||
border-radius: 3mm;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #e2e8f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-image {
|
|
||||||
width: 45mm;
|
|
||||||
height: 35mm;
|
|
||||||
object-fit: cover;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-info {
|
|
||||||
padding: 3mm 4mm 3mm 0;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-category {
|
|
||||||
font-size: 7pt;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333333;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-title {
|
|
||||||
font-size: 11pt;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #000000;
|
|
||||||
margin: 1mm 0 2mm 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portfolio-description {
|
|
||||||
font-size: 8pt;
|
|
||||||
color: #475569;
|
|
||||||
line-height: 1.5;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CONTACT PAGE */
|
|
||||||
.contact-page {
|
|
||||||
background: transparent;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-content {
|
|
||||||
text-align: center;
|
|
||||||
color: #000000;
|
|
||||||
padding: 40mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-title {
|
|
||||||
font-size: 32pt;
|
|
||||||
font-weight: 800;
|
|
||||||
margin: 0 0 6mm 0;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-subtitle {
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #666666;
|
|
||||||
margin: 0 0 12mm 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-details {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 5mm;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-item {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
padding: 4mm;
|
|
||||||
border-radius: 3mm;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-item strong {
|
|
||||||
display: block;
|
|
||||||
font-size: 7pt;
|
|
||||||
color: #22d3ee;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
margin-bottom: 2mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-item span {
|
|
||||||
font-size: 9pt;
|
|
||||||
color: #cbd5e1;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Screen preview styles */
|
|
||||||
.print-portfolio {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.print-portfolio.show-preview {
|
|
||||||
display: block;
|
|
||||||
background: #1e293b;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.print-portfolio.show-preview .page {
|
|
||||||
width: 210mm;
|
|
||||||
min-height: 297mm;
|
|
||||||
margin: 0 auto 20px;
|
|
||||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
|
||||||
page-break-after: auto;
|
|
||||||
break-after: auto;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue