diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e47d613 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + pull_request: + branches: + - main + - devel + workflow_dispatch: + +jobs: + check: + name: Portfolio Check + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + + - name: Install dependencies + run: npm clean-install + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f0b2788 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,38 @@ +name: Release + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + release: + name: Release + runs-on: ubuntu-latest + permissions: + contents: write + issues: write + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + + - name: Initialize package.json + run: npm init -y + + - name: Install dependencies + run: npm install -D semantic-release + + - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies + run: npm audit signatures + + - name: Run semantic release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx semantic-release diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..548e644 --- /dev/null +++ b/.releaserc @@ -0,0 +1,10 @@ +{ + "branches": [ + "main" + ], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/github" + ] +} diff --git a/LICENSE b/LICENSE index 8e08b0c..a8f3691 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2024 Axel Sanchez - -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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2025 Axel Omar Sanchez Peralta + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/package-lock.json b/package-lock.json index ca32c9d..71f20a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,12 +15,13 @@ "@radix-ui/react-tooltip": "^1.0.7", "@types/mdx": "^2.0.13", "@vercel/analytics": "^1.3.2", + "@vercel/speed-insights": "^1.2.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "framer-motion": "^11.2.10", "gray-matter": "^4.0.3", "lucide-react": "^0.395.0", - "next": "14.2.4", + "next": "^14.2.32", "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18", @@ -267,9 +268,10 @@ } }, "node_modules/@next/env": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", - "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==" + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.32.tgz", + "integrity": "sha512-n9mQdigI6iZ/DF6pCTwMKeWgF2e8lg7qgt5M7HXMLtyhZYMnf/u905M18sSpPmHL9MKp9JHo56C6jrD2EvWxng==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "14.2.4", @@ -281,12 +283,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", - "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.32.tgz", + "integrity": "sha512-osHXveM70zC+ilfuFa/2W6a1XQxJTvEhzEycnjUaVE8kpUS09lDpiDDX2YLdyFCzoUbvbo5r0X1Kp4MllIOShw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -296,12 +299,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", - "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.32.tgz", + "integrity": "sha512-P9NpCAJuOiaHHpqtrCNncjqtSBi1f6QUdHK/+dNabBIXB2RUFWL19TY1Hkhu74OvyNQEYEzzMJCMQk5agjw1Qg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -311,12 +315,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", - "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.32.tgz", + "integrity": "sha512-v7JaO0oXXt6d+cFjrrKqYnR2ubrD+JYP7nQVRZgeo5uNE5hkCpWnHmXm9vy3g6foMO8SPwL0P3MPw1c+BjbAzA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -326,12 +331,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", - "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.32.tgz", + "integrity": "sha512-tA6sIKShXtSJBTH88i0DRd6I9n3ZTirmwpwAqH5zdJoQF7/wlJXR8DkPmKwYl5mFWhEKr5IIa3LfpMW9RRwKmQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -341,12 +347,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", - "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.32.tgz", + "integrity": "sha512-7S1GY4TdnlGVIdeXXKQdDkfDysoIVFMD0lJuVVMeb3eoVjrknQ0JNN7wFlhCvea0hEk0Sd4D1hedVChDKfV2jw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -356,12 +363,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", - "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.32.tgz", + "integrity": "sha512-OHHC81P4tirVa6Awk6eCQ6RBfWl8HpFsZtfEkMpJ5GjPsJ3nhPe6wKAJUZ/piC8sszUkAgv3fLflgzPStIwfWg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -371,12 +379,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", - "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.32.tgz", + "integrity": "sha512-rORQjXsAFeX6TLYJrCG5yoIDj+NKq31Rqwn8Wpn/bkPNy5rTHvOXkW8mLFonItS7QC6M+1JIIcLe+vOCTOYpvg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -386,12 +395,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", - "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.32.tgz", + "integrity": "sha512-jHUeDPVHrgFltqoAqDB6g6OStNnFxnc7Aks3p0KE0FbwAvRg6qWKYF5mSTdCTxA3axoSAUwxYdILzXJfUwlHhA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -401,12 +411,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", - "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.32.tgz", + "integrity": "sha512-2N0lSoU4GjfLSO50wvKpMQgKd4HdI2UHEhQPPPnlgfBJlOgJxkjpkYBqzk08f1gItBB6xF/n+ykso2hgxuydsA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1168,10 +1179,11 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1233,6 +1245,41 @@ } } }, + "node_modules/@vercel/speed-insights": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-1.2.0.tgz", + "integrity": "sha512-y9GVzrUJ2xmgtQlzFP2KhVRoCglwfRQgjyfY607aU0hh0Un6d0OUyrJkjuAlsV18qR4zfoFPs/BiIj9YDS6Wzw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "peerDependencies": { + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } + } + }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -1553,10 +1600,11 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1806,9 +1854,10 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3025,9 +3074,10 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -4777,15 +4827,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4800,11 +4851,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", - "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==", + "version": "14.2.32", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.32.tgz", + "integrity": "sha512-fg5g0GZ7/nFc09X8wLe6pNSU8cLWbLRG3TZzPJ1BJvi2s9m7eF991se67wliM9kR5yLHRkyGKU49MMx58s3LJg==", + "license": "MIT", "dependencies": { - "@next/env": "14.2.4", + "@next/env": "14.2.32", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -4819,15 +4871,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.4", - "@next/swc-darwin-x64": "14.2.4", - "@next/swc-linux-arm64-gnu": "14.2.4", - "@next/swc-linux-arm64-musl": "14.2.4", - "@next/swc-linux-x64-gnu": "14.2.4", - "@next/swc-linux-x64-musl": "14.2.4", - "@next/swc-win32-arm64-msvc": "14.2.4", - "@next/swc-win32-ia32-msvc": "14.2.4", - "@next/swc-win32-x64-msvc": "14.2.4" + "@next/swc-darwin-arm64": "14.2.32", + "@next/swc-darwin-x64": "14.2.32", + "@next/swc-linux-arm64-gnu": "14.2.32", + "@next/swc-linux-arm64-musl": "14.2.32", + "@next/swc-linux-x64-gnu": "14.2.32", + "@next/swc-linux-x64-musl": "14.2.32", + "@next/swc-win32-arm64-msvc": "14.2.32", + "@next/swc-win32-ia32-msvc": "14.2.32", + "@next/swc-win32-x64-msvc": "14.2.32" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/package.json b/package.json index 57b851c..4e97d46 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,13 @@ "@radix-ui/react-tooltip": "^1.0.7", "@types/mdx": "^2.0.13", "@vercel/analytics": "^1.3.2", + "@vercel/speed-insights": "^1.2.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "framer-motion": "^11.2.10", "gray-matter": "^4.0.3", "lucide-react": "^0.395.0", - "next": "14.2.4", + "next": "^14.2.32", "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18", diff --git a/public/Resume.pdf b/public/Resume.pdf new file mode 100644 index 0000000..418ccd7 Binary files /dev/null and b/public/Resume.pdf differ diff --git a/public/agrivanna-logo.jpeg b/public/agrivanna-logo.jpeg new file mode 100644 index 0000000..b9f3257 Binary files /dev/null and b/public/agrivanna-logo.jpeg differ diff --git a/public/favicon-dark.ico b/public/favicon-dark.ico new file mode 100644 index 0000000..d0babef Binary files /dev/null and b/public/favicon-dark.ico differ diff --git a/public/favicon-light.ico b/public/favicon-light.ico new file mode 100644 index 0000000..4ffb197 Binary files /dev/null and b/public/favicon-light.ico differ diff --git a/public/microsoft-az900-logo.png b/public/microsoft-az900-logo.png new file mode 100644 index 0000000..b875bb2 Binary files /dev/null and b/public/microsoft-az900-logo.png differ diff --git a/public/microsoft-logo.jpeg b/public/microsoft-logo.jpeg new file mode 100644 index 0000000..ddfae30 Binary files /dev/null and b/public/microsoft-logo.jpeg differ diff --git a/public/schulich-uofc-logo.jpeg b/public/schulich-uofc-logo.jpeg new file mode 100644 index 0000000..d55192e Binary files /dev/null and b/public/schulich-uofc-logo.jpeg differ diff --git a/public/ucalgary-logo.jpeg b/public/ucalgary-logo.jpeg new file mode 100644 index 0000000..e5dfb1a Binary files /dev/null and b/public/ucalgary-logo.jpeg differ diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/src/app/favicon.ico and /dev/null differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 714f8fb..533e2b0 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,11 @@ import Navbar from "@/components/navbar"; +import FaviconSwitcher from "@/components/favicon-switcher"; import { Analytics } from "@vercel/analytics/react"; import { ThemeProvider } from "@/components/theme-provider"; import { TooltipProvider } from "@/components/ui/tooltip"; import { DATA } from "@/data/resume"; import { cn } from "@/lib/utils"; +import { SpeedInsights } from "@vercel/speed-insights/next"; import type { Metadata } from "next"; import { Inter as FontSans } from "next/font/google"; import "./globals.css"; @@ -20,6 +22,12 @@ export const metadata: Metadata = { template: `%s | ${DATA.name}`, }, description: DATA.description, + icons: { + icon: [ + { url: "/favicon-light.ico", media: "(prefers-color-scheme: light)" }, + { url: "/favicon-dark.ico", media: "(prefers-color-scheme: dark)" }, + ], + }, openGraph: { title: `${DATA.name}`, description: DATA.description, @@ -64,7 +72,9 @@ export default function RootLayout({ > + {children} + diff --git a/src/app/page.tsx b/src/app/page.tsx index 19f2aa3..1edac89 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -20,9 +20,9 @@ export default function Page() {
- Certificates + Certifications

Always eager to learn and grow diff --git a/src/components/favicon-switcher.tsx b/src/components/favicon-switcher.tsx new file mode 100644 index 0000000..a11e875 --- /dev/null +++ b/src/components/favicon-switcher.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useTheme } from "next-themes"; +import { useEffect } from "react"; + +export default function FaviconSwitcher() { + const { theme, resolvedTheme } = useTheme(); + + useEffect(() => { + const updateFavicon = () => { + const link = document.querySelector( + "link[rel~='icon']" + ) as HTMLLinkElement; + if (!link) return; + + const currentTheme = resolvedTheme || theme; + const faviconPath = + currentTheme === "dark" ? "/favicon-dark.ico" : "/favicon-light.ico"; + + if (link.href !== faviconPath) { + link.href = faviconPath; + } + }; + + updateFavicon(); + }, [theme, resolvedTheme]); + + return null; +} diff --git a/src/components/icons.tsx b/src/components/icons.tsx index c4984e8..6e5134f 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1,10 +1,11 @@ -import { GlobeIcon, MailIcon } from "lucide-react"; +import { GlobeIcon, MailIcon, DownloadIcon } from "lucide-react"; export type IconProps = React.HTMLAttributes; export const Icons = { globe: (props: IconProps) => , email: (props: IconProps) => , + download: (props: IconProps) => , linkedin: (props: IconProps) => ( LinkedIn diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx index a815e22..de9e9a6 100644 --- a/src/components/navbar.tsx +++ b/src/components/navbar.tsx @@ -43,18 +43,31 @@ export default function Navbar() { - - - + {name === "resume" ? ( + + + + ) : ( + + + + )} -

{name}

+

{social.name}

diff --git a/src/data/resume.tsx b/src/data/resume.tsx index 2d140df..c5f4388 100644 --- a/src/data/resume.tsx +++ b/src/data/resume.tsx @@ -2,37 +2,73 @@ import { Icons } from "@/components/icons"; import { HomeIcon, NotebookIcon } from "lucide-react"; export const DATA = { - name: "Axel Sanchez", + name: "Axel Sanchez Portfolio", initials: "AOSP", - url: "https://axelo.me", - location: "Calgary, AB", + url: "https://axelsanchez.me", + location: "Calgary, Alberta", locationLink: "https://www.google.com/maps/place/calgary", description: - "Software Engineer and Entrepreneur. I enjoy football, soccer, playing videogames, lifting weights and muay thai.", + "Software Engineer, Researcher, and Entrepreneur. On my free time I enjoy football, lifting weights and muay thai.", summary: - "I’m a Software Engineering student at the University of Calgary with experience across startups and established tech companies. At Aptum, I enhanced cloud systems by migrating monoliths to microservices and adding GPU support for AI workloads. At Sigma, I improved eCommerce operations by integrating APIs and implementing CI/CD pipelines, reducing testing time by 98.75%. I’ve also led development at Rethread and Bandist, two startups, where I built scalable platforms and integrated services for over 10,000 users. As VP Software Development for Student Energy UCalgary, I increased engagement by 70% and led software team recruitment. Currently, I joined an AI-powered personalized skincare venture focused on B2B2C solutions.", + "I’m Axel Sanchez, a Software Engineer from Mexico. Welcome to my portfolio website, where you’ll find my latest work, research, blogs, and projects. I specialize in building high-performance systems, from GPU computing and cloud microservices to dApps and DeFi solutions on blockchain.", avatarUrl: "/me.png", skills: [ + // Programming Languages + "C", + "C++", + "C#", + "Java", + "JavaScript", + "TypeScript", + "Python", + "Go", + "Rust", + "Dart", + "SQL", + "Solidity", + + // Cloud & Infrastructure + "Azure", "AWS", "GCP", - "Azure", - "Terrform", - "Jenkins", + "Blockchain", + "Kubernetes", + "Docker", + "Helm", + "Terraform", + "Kafka", + "RabbitMQ", + + // Databases + "MySQL", + "PostgreSQL", + + // Frameworks & Platforms + ".NET", "Spring Boot", + "Express", + "Django", + + // Frontend "React", - "Flutter", "Next.js", - "Typescript", - "Express", - "Node.js", - "Vue", - "Dart", - "Python", - "MySQL", - "Docker", - "Kubernetes", - "Java", - "C++/C", + "Vue.js", + "Redux", + "Expo", + "Flutter", + "Vite", + "Tailwind", + + // APIs & Tools + "gRPC", + + // Machine Learning / HPC + "PyTorch", + "CUDA", + + // CI/CD + "Jenkins", + "GitHub Actions", ], navbar: [ { href: "/", icon: HomeIcon, label: "Home" }, @@ -60,85 +96,115 @@ export const DATA = { icon: Icons.email, navbar: false, }, + resume: { + name: "Download Resume", + url: "/Resume.pdf", + icon: Icons.download, + navbar: true, + }, }, }, work: [ + { + company: "Microsoft", + href: "https://www.microsoft.com/en-ca/", + badges: [], + location: "Vancouver, British Columbia", + title: "Software Engineer Intern", + logoUrl: "/microsoft-logo.jpeg", + start: "May 2025", + end: "Aug. 2025", + description: + "Built a custom CUDA all-reduce (TRT plugin) on H200s with NVLink/P2P fallback; optimized GPU comms/GEMM and integrated research into production experiments.", + }, + { + company: "Agrivanna", + href: "https://www.agrivanna.com/", + badges: [], + location: "Calgary, Alberta", + title: "Full Stack Engineer (Part-Time)", + logoUrl: "/agrivanna-logo.jpeg", + start: "Sep. 2024", + end: "Apr. 2025", + description: + "Shipped Go/Java microservices and ML features (scikit-learn + PyTorch) for personalized health; deployed FastAPI on Kubernetes and mentored teammates on Docker/K8s.", + }, { company: "Aptum", href: "https://aptum.com/", badges: [], - location: "Remote", + location: "Calgary, Alberta", title: "Cloud Developer Intern", logoUrl: "/aptum-logo.png", start: "May 2024", - end: "Present", + end: "Apr. 2025", description: - "Developed and implemented GPU support feature for VM instances within the Google Cloud plugin, improving processing speed by 25% for AI company customers. Migrated a legacy monolithic plugin architecture to a microservices-based system using gRPC, enhancing scalability and improving performance by 66%. Directed a platform-wide database migration, updating users, roles, environments, and scopes to ensure system integrity and efficiency.", + "Scaled Kubernetes infra with Terraform/Helm and Jenkins CI, doubling throughput; migrated a monolith to gRPC microservices (Java/Spring/MySQL) with a 66% perf lift.", }, { - company: "ReThread", + company: "Student Energy UCalgary", badges: [], - href: "#", - location: "Calgary, AB", - title: "Tech Lead", - logoUrl: "/rethread-logo.png", - start: "September 2023", - end: "April 2024", + href: "https://studentenergyuofc.org/", + location: "Calgary, Alberta", + title: "Vice-President Software Development", + logoUrl: "/seuc-logo.png", + start: "Sep. 2023", + end: "Apr. 2024", description: - "Led and mentored the backend team, coordinating and managing tickets, conducting code reviews, and promoting peer development, resulting in a reduction in bug reports. Architected a microservice e-commerce platform, enhancing scalability and performance, which resulted in enhanced system throughput and reduced downtime. Designed and prototyped user interfaces with Figma, ensuring a seamless and intuitive user experience, leading to an increase in user satisfaction scores.", + "Launched a Next.js/TypeScript news app (+70% engagement) and automated AWS infra with Terraform + GitHub Actions; led hiring and set engineering standards.", }, { - company: "Student Energy UCalgary", + company: "ReThread", badges: [], - href: "https://studentenergyuofc.org/", - location: "Calgary, AB", - title: "CO-VP Software Development", - logoUrl: "/seuc-logo.png", - start: "September 2023", - end: "April 2024", + href: "#", + location: "Calgary, Alberta", + title: "Backend Engineer (Part-Time)", + logoUrl: "/rethread-logo.png", + start: "Sep. 2023", + end: "Apr. 2024", description: - "Led the development team in creating an interactive and dynamic web application for chapter news, increasing site engagement by 70%. Automated deployment processes, reducing update time and ensuring reliable, timely updates. Coordinated development activities, managed project timelines, and conducted interviews for the software team, improving project completion rates.", + "Designed TypeScript/Express microservices with Redis caching on AWS/Kubernetes; prototyped a PyTorch CNN for fabric classification and set CI/code-review practices.", }, { - company: "Sigma", + company: "Sigma Foodservice", href: "https://www.sigma-alimentos.com/en/", badges: [], location: "Remote", - title: "Software Developer Intern", + title: "Software Engineer Intern", logoUrl: "/sigma-logo.png", start: "May 2023", - end: "August 2023", + end: "Aug. 2023", description: - "Integrated Copomex API at an enterprise-level, ensuring pinpoint accuracy for over 10,000 locations, enhancing data precision by 50%. Conducted presentations at 5 sprint reviews, effectively aligning progress with business and marketing objectives, leading to an improvement in team collaboration. Implemented a CI/CD pipeline for the eCommerce’s UI, enhancing test speed and report generation, reducing QA testing time by 98.75%, and increasing deployment frequency.", + "Integrated Copomex API in .NET/C# for 10k+ locations (↑ address accuracy 80%); added Playwright E2E + Jenkins to slash QA time and speed deployments.", }, { company: "Bandist", href: "#", badges: [], location: "Calgary, AB", - title: "Full-Stack Developer", + title: "Frontend Engineer (Part-Time)", logoUrl: "/bandist-logo.png", - start: "September 2022", - end: "April 2023", + start: "Sep. 2022", + end: "Apr. 2023", description: - "Integrated Django with Ticketmaster & Spotify APIs, achieving a faster registration process and reducing development costs by 20%, while improving user registration experience. Mentored and guided a team of 5 engineers, improving code quality and increasing project delivery. Managed Firebase hosting, ensuring consistent support for over 10,000 active users monthly, and uptime by 99.95%.", + "Connected Django app to Ticketmaster/Spotify, cut costs 20%, and managed PostgreSQL/GCP for 10k+ MAU; shipped a Flutter mobile app with 99.95% uptime on Firebase.", }, ], education: [ { - school: "University of Calgary", - href: "https://www.ucalgary.ca/", - degree: "Bachelor's Degree of Software Engineering (BCS)", - logoUrl: "/uofc-logo.png", - start: "2021", - end: "Present", + school: "Schulich School of Engineering, University of Calgary", + href: "https://schulich.ucalgary.ca/", + degree: "Bachelor of Science in Software Engineering", + logoUrl: "/ucalgary-logo.jpeg", + start: "Sep. 2021", + end: "Apr. 2026", }, ], projects: [ { title: "ChoreShare", href: "#", - dates: "January 2024 - April 2024", + dates: "Jan. 2024 - Apr. 2024", active: true, description: "A cross-platform application for household roommates to coordinate tasks.", @@ -171,7 +237,7 @@ export const DATA = { { title: "MyNotes", href: "#", - dates: "December 2023 - January 2024", + dates: "Dec. 2023 - Jan. 2024", active: true, description: "A simple note-taking mobile app designed for capturing important ideas and reminders.", @@ -189,7 +255,7 @@ export const DATA = { { title: "The Last Show", href: "#", - dates: "January 2023 - April 2023", + dates: "Jan. 2023 - Apr. 2023", active: true, description: "A serverless web app that automatically generates personalized obituaries for people.", @@ -218,7 +284,7 @@ export const DATA = { { title: "Game Heaven", href: "#", - dates: "January 2023 - August 2023", + dates: "Jan. 2023 - Aug. 2023", active: true, description: "Developed an AI Customer Support Chatbot which automatically responds to customer support tickets using the latest GPT models.", @@ -266,5 +332,18 @@ export const DATA = { }, ], }, + { + title: "Microsoft Certified Azure Fundamentals", + dates: "Feb. 2025", + image: "microsoft-az900-logo.png", + mlh: "https://s3.amazonaws.com/logged-assets/trust-badge/2019/mlh-trust-badge-2019-white.svg", + links: [ + { + title: "View Credential", + href: "https://learn.microsoft.com/en-us/users/axelsnchez-2277/credentials/2ee95ece9f3f4cac", + icon: , + }, + ], + }, ], } as const;