feat: initial commit
This commit is contained in:
4
.babelrc
Normal file
4
.babelrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"sourceType": "unambiguous",
|
||||||
|
"presets": [["@babel/preset-env", { "modules": false }]]
|
||||||
|
}
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
7990
package-lock.json
generated
Normal file
7990
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "portfolio-website",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "webpack serve --mode development",
|
||||||
|
"build": "webpack --mode production"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.28.5",
|
||||||
|
"@babel/preset-env": "^7.28.5",
|
||||||
|
"autoprefixer": "^10.4.22",
|
||||||
|
"babel-loader": "^10.0.0",
|
||||||
|
"css-loader": "^7.1.2",
|
||||||
|
"html-loader": "^5.1.0",
|
||||||
|
"html-webpack-plugin": "^5.6.5",
|
||||||
|
"mini-css-extract-plugin": "^2.9.4",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"postcss-loader": "^8.2.0",
|
||||||
|
"tailwindcss": "^3.4.18",
|
||||||
|
"webpack": "^5.103.0",
|
||||||
|
"webpack-cli": "^6.0.1",
|
||||||
|
"webpack-dev-server": "^5.2.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.1.17"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
BIN
src/images/profile.jpg
Normal file
BIN
src/images/profile.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
1244
src/index.html
Normal file
1244
src/index.html
Normal file
File diff suppressed because it is too large
Load Diff
154
src/index.js
Normal file
154
src/index.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import "./styles.css";
|
||||||
|
|
||||||
|
// Set year in footer
|
||||||
|
const yearEl = document.getElementById("year");
|
||||||
|
if (yearEl) {
|
||||||
|
yearEl.textContent = new Date().getFullYear().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hero entrance animation
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const heroEls = document.querySelectorAll("[data-hero]");
|
||||||
|
heroEls.forEach((el, idx) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
el.classList.add("animate-fade-in-up");
|
||||||
|
el.classList.remove("opacity-0", "translate-y-6");
|
||||||
|
}, 150 * idx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scroll animations for sections
|
||||||
|
const animatedSections = document.querySelectorAll("[data-animate]");
|
||||||
|
animatedSections.forEach((section) => {
|
||||||
|
section.classList.add(
|
||||||
|
"opacity-0",
|
||||||
|
"translate-y-8",
|
||||||
|
"transition-all",
|
||||||
|
"duration-700"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.add("animate-fade-in-up");
|
||||||
|
entry.target.classList.remove("opacity-0", "translate-y-8");
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ threshold: 0.12 }
|
||||||
|
);
|
||||||
|
|
||||||
|
animatedSections.forEach((section) => observer.observe(section));
|
||||||
|
|
||||||
|
// tailwind.config = {
|
||||||
|
// theme: {
|
||||||
|
// extend: {
|
||||||
|
// fontFamily: {
|
||||||
|
// sans: [
|
||||||
|
// "Inter",
|
||||||
|
// "ui-sans-serif",
|
||||||
|
// "system-ui",
|
||||||
|
// "-apple-system",
|
||||||
|
// "BlinkMacSystemFont",
|
||||||
|
// '"Segoe UI"',
|
||||||
|
// "sans-serif",
|
||||||
|
// ],
|
||||||
|
// heading: [
|
||||||
|
// "Montserrat",
|
||||||
|
// "ui-sans-serif",
|
||||||
|
// "system-ui",
|
||||||
|
// "-apple-system",
|
||||||
|
// "BlinkMacSystemFont",
|
||||||
|
// '"Segoe UI"',
|
||||||
|
// "sans-serif",
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// colors: {
|
||||||
|
// primary: "#1e90ff", // dodgerblue
|
||||||
|
// "bg-primary": "#1e90ff",
|
||||||
|
// "bg-dark": "#020617", // slate-950-ish
|
||||||
|
// "card-dark": "#020617",
|
||||||
|
// "card-elevated": "#020617",
|
||||||
|
// },
|
||||||
|
// boxShadow: {
|
||||||
|
// glow: "0 0 40px rgba(30,144,255,0.45)",
|
||||||
|
// },
|
||||||
|
// keyframes: {
|
||||||
|
// "fade-in-up": {
|
||||||
|
// "0%": { opacity: "0", transform: "translateY(20px)" },
|
||||||
|
// "100%": { opacity: "1", transform: "translateY(0)" },
|
||||||
|
// },
|
||||||
|
// "fade-in": {
|
||||||
|
// "0%": { opacity: "0" },
|
||||||
|
// "100%": { opacity: "1" },
|
||||||
|
// },
|
||||||
|
// "scale-in": {
|
||||||
|
// "0%": { opacity: "0", transform: "scale(0.96)" },
|
||||||
|
// "100%": { opacity: "1", transform: "scale(1)" },
|
||||||
|
// },
|
||||||
|
// "glow-pulse": {
|
||||||
|
// "0%,100%": { boxShadow: "0 0 0 rgba(30,144,255,0.0)" },
|
||||||
|
// "50%": { boxShadow: "0 0 40px rgba(30,144,255,0.5)" },
|
||||||
|
// },
|
||||||
|
// "border-spin": {
|
||||||
|
// "0%": { transform: "rotate(0deg)" },
|
||||||
|
// "100%": { transform: "rotate(360deg)" },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// animation: {
|
||||||
|
// "fade-in-up": "fade-in-up 0.8s ease-out forwards",
|
||||||
|
// "fade-in": "fade-in 1s ease-out forwards",
|
||||||
|
// "scale-in": "scale-in 0.7s ease-out forwards",
|
||||||
|
// "glow-pulse": "glow-pulse 2s ease-in-out infinite",
|
||||||
|
// "border-spin": "border-spin 8s linear infinite",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// --- SCRIPTING
|
||||||
|
|
||||||
|
// Set year
|
||||||
|
// document.getElementById("year").textContent = new Date()
|
||||||
|
// .getFullYear()
|
||||||
|
// .toString();
|
||||||
|
|
||||||
|
// // Hero entrance animation
|
||||||
|
// window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// const heroEls = document.querySelectorAll("[data-hero]");
|
||||||
|
// heroEls.forEach((el, idx) => {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// el.classList.add("animate-fade-in-up");
|
||||||
|
// el.classList.remove("opacity-0", "translate-y-6");
|
||||||
|
// }, 150 * idx);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Scroll animations for sections
|
||||||
|
// const animatedSections = document.querySelectorAll("[data-animate]");
|
||||||
|
// animatedSections.forEach((section) => {
|
||||||
|
// section.classList.add(
|
||||||
|
// "opacity-0",
|
||||||
|
// "translate-y-8",
|
||||||
|
// "transition-all",
|
||||||
|
// "duration-700"
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const observer = new IntersectionObserver(
|
||||||
|
// (entries) => {
|
||||||
|
// entries.forEach((entry) => {
|
||||||
|
// if (entry.isIntersecting) {
|
||||||
|
// entry.target.classList.add("animate-fade-in-up");
|
||||||
|
// entry.target.classList.remove("opacity-0", "translate-y-8");
|
||||||
|
// observer.unobserve(entry.target);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// { threshold: 0.12 }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// animatedSections.forEach((section) => observer.observe(section));
|
||||||
16
src/styles.css
Normal file
16
src/styles.css
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
@apply bg-bg-dark text-slate-100 antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide scrollbars on cards but keep scroll behavior */
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
67
tailwind.config.js
Normal file
67
tailwind.config.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./src/**/*.{html,js,ts,jsx,tsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: [
|
||||||
|
"Inter",
|
||||||
|
"ui-sans-serif",
|
||||||
|
"system-ui",
|
||||||
|
"-apple-system",
|
||||||
|
"BlinkMacSystemFont",
|
||||||
|
'"Segoe UI"',
|
||||||
|
"sans-serif",
|
||||||
|
],
|
||||||
|
heading: [
|
||||||
|
"Montserrat",
|
||||||
|
"ui-sans-serif",
|
||||||
|
"system-ui",
|
||||||
|
"-apple-system",
|
||||||
|
"BlinkMacSystemFont",
|
||||||
|
'"Segoe UI"',
|
||||||
|
"sans-serif",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
primary: "#1e90ff", // dodgerblue
|
||||||
|
"bg-dark": "#020617",
|
||||||
|
"card-dark": "#020617",
|
||||||
|
"card-elevated": "#020617",
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
glow: "0 0 40px rgba(30,144,255,0.45)",
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
"fade-in-up": {
|
||||||
|
"0%": { opacity: "0", transform: "translateY(20px)" },
|
||||||
|
"100%": { opacity: "1", transform: "translateY(0)" },
|
||||||
|
},
|
||||||
|
"fade-in": {
|
||||||
|
"0%": { opacity: "0" },
|
||||||
|
"100%": { opacity: "1" },
|
||||||
|
},
|
||||||
|
"scale-in": {
|
||||||
|
"0%": { opacity: "0", transform: "scale(0.96)" },
|
||||||
|
"100%": { opacity: "1", transform: "scale(1)" },
|
||||||
|
},
|
||||||
|
"glow-pulse": {
|
||||||
|
"0%,100%": { boxShadow: "0 0 0 rgba(30,144,255,0.0)" },
|
||||||
|
"50%": { boxShadow: "0 0 40px rgba(30,144,255,0.5)" },
|
||||||
|
},
|
||||||
|
"border-spin": {
|
||||||
|
"0%": { transform: "rotate(0deg)" },
|
||||||
|
"100%": { transform: "rotate(360deg)" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
"fade-in-up": "fade-in-up 0.8s ease-out forwards",
|
||||||
|
"fade-in": "fade-in 1s ease-out forwards",
|
||||||
|
"scale-in": "scale-in 0.7s ease-out forwards",
|
||||||
|
"glow-pulse": "glow-pulse 2s ease-in-out infinite",
|
||||||
|
"border-spin": "border-spin 8s linear infinite",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
58
webpack.config.js
Normal file
58
webpack.config.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
|
||||||
|
module.exports = (env, argv) => {
|
||||||
|
const isProd = argv.mode === "production";
|
||||||
|
|
||||||
|
return {
|
||||||
|
entry: "./src/index.js",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
filename: isProd ? "js/[name].[contenthash].js" : "js/[name].js",
|
||||||
|
clean: true,
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.html$/i,
|
||||||
|
loader: "html-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.m?js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: "babel-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)$/i,
|
||||||
|
type: "asset/resource",
|
||||||
|
generator: {
|
||||||
|
filename: "images/[name][hash][ext][query]",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/index.html",
|
||||||
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: isProd ? "css/[name].[contenthash].css" : "css/[name].css",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
devServer: {
|
||||||
|
static: "./dist",
|
||||||
|
hot: true,
|
||||||
|
open: true,
|
||||||
|
port: 5173,
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".js"],
|
||||||
|
},
|
||||||
|
devtool: isProd ? "source-map" : "eval-source-map",
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user