Updates
This commit is contained in:
+149
-149
@@ -1,149 +1,149 @@
|
||||
import { gsap } from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
import TextPlugin from "gsap/TextPlugin";
|
||||
|
||||
/**
|
||||
* Register plugins
|
||||
*/
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
/**
|
||||
* Animates the hero section
|
||||
*/
|
||||
export function hero() {
|
||||
/**
|
||||
* Animate hero section
|
||||
*/
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 1.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 2.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 1,
|
||||
},
|
||||
y: 150,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 100,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function about() {
|
||||
gsap.fromTo(
|
||||
"#about-section",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 4,
|
||||
},
|
||||
y: 0,
|
||||
scale: 1.1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.to("#about-me-label", {
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 300,
|
||||
scale: 0.8,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function genericScroll() {
|
||||
gsap.fromTo(
|
||||
".generic-scroll",
|
||||
{
|
||||
y: 0,
|
||||
scale: 0.9,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 3,
|
||||
},
|
||||
y: 100,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function appear() {
|
||||
gsap.fromTo(
|
||||
".appear",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
y: 0,
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 2,
|
||||
delay: (i, target) => {
|
||||
const datasetDelay = target?.dataset?.delay;
|
||||
|
||||
if (datasetDelay) {
|
||||
return datasetDelay;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
import { gsap } from "gsap";
|
||||
import ScrollTrigger from "gsap/ScrollTrigger";
|
||||
import TextPlugin from "gsap/TextPlugin";
|
||||
|
||||
/**
|
||||
* Register plugins
|
||||
*/
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
/**
|
||||
* Animates the hero section
|
||||
*/
|
||||
export function hero() {
|
||||
/**
|
||||
* Animate hero section
|
||||
*/
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 1.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
z: -100,
|
||||
scale: 1.2,
|
||||
},
|
||||
{
|
||||
z: 0,
|
||||
duration: 2.5,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#main-image",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 1,
|
||||
},
|
||||
y: 150,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.fromTo(
|
||||
"#hero-text-section",
|
||||
{
|
||||
y: 0,
|
||||
// scale: 1,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 100,
|
||||
// scale: 0.8,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function about() {
|
||||
gsap.fromTo(
|
||||
"#about-section",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 4,
|
||||
},
|
||||
y: 0,
|
||||
scale: 1.1,
|
||||
}
|
||||
);
|
||||
|
||||
gsap.to("#about-me-label", {
|
||||
scrollTrigger: {
|
||||
scrub: 2,
|
||||
},
|
||||
y: 300,
|
||||
scale: 0.8,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function genericScroll() {
|
||||
gsap.fromTo(
|
||||
".generic-scroll",
|
||||
{
|
||||
y: 0,
|
||||
scale: 0.9,
|
||||
},
|
||||
{
|
||||
scrollTrigger: {
|
||||
scrub: 3,
|
||||
},
|
||||
y: 100,
|
||||
scale: 1,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the about section
|
||||
*/
|
||||
export function appear() {
|
||||
gsap.fromTo(
|
||||
".appear",
|
||||
{
|
||||
y: 40,
|
||||
scale: 0.8,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
y: 0,
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 2,
|
||||
delay: (i, target) => {
|
||||
const datasetDelay = target?.dataset?.delay;
|
||||
|
||||
if (datasetDelay) {
|
||||
return datasetDelay;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+208
-208
@@ -1,208 +1,208 @@
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger, Observer } from "gsap/all";
|
||||
gsap.registerPlugin(ScrollTrigger, Observer);
|
||||
|
||||
export default function homepageTimeline({ componentRef }: { componentRef: { current: HTMLDivElement | null } }) {
|
||||
const mm = gsap.matchMedia();
|
||||
|
||||
const compHeight = componentRef.current?.clientHeight;
|
||||
|
||||
const isMobile = window.innerWidth <= 1200;
|
||||
|
||||
// mm.add("(min-width: 1200px)", () => {
|
||||
ScrollTrigger.create({
|
||||
trigger: "#homepage-content-wrapper",
|
||||
start: "200px 200px",
|
||||
end: "bottom 90%",
|
||||
pin: isMobile ? null : "#main-image",
|
||||
scrub: 1,
|
||||
onUpdate: (self) => {
|
||||
const scrollTop = compHeight ? self.progress * compHeight : 0;
|
||||
|
||||
/**
|
||||
* Origin
|
||||
*/
|
||||
if (!isMobile) {
|
||||
if (scrollTop < 300) {
|
||||
gsap.to("nav", {
|
||||
opacity: 1,
|
||||
pointerEvents: "visible",
|
||||
});
|
||||
gsap.to("header", {
|
||||
zIndex: 2000,
|
||||
});
|
||||
} else {
|
||||
gsap.to("nav", {
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
});
|
||||
gsap.to("header", {
|
||||
zIndex: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Mobile
|
||||
*/
|
||||
if (isMobile && scrollTop > 100) {
|
||||
gsap.to("#main-image", {
|
||||
opacity: 0.1,
|
||||
duration: 1,
|
||||
});
|
||||
} else {
|
||||
gsap.to("#main-image", {
|
||||
opacity: 1,
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
},
|
||||
onEnter: (self) => {},
|
||||
});
|
||||
|
||||
/**
|
||||
* Position color map
|
||||
*/
|
||||
const positionColorMap: {
|
||||
x: number;
|
||||
imgBg: string;
|
||||
bodyBg: string;
|
||||
duration: number;
|
||||
imgSrc?: string;
|
||||
}[] = [
|
||||
{
|
||||
x: 0,
|
||||
imgBg: "#3e3f9c",
|
||||
bodyBg: "#181515",
|
||||
duration: 1,
|
||||
imgSrc: "/images/my-photo-stroked.png",
|
||||
},
|
||||
{
|
||||
x: -50,
|
||||
imgBg: "#FE6847",
|
||||
bodyBg: "#292a6b",
|
||||
duration: 1,
|
||||
imgSrc: "/images/my-photo-3.png",
|
||||
},
|
||||
{
|
||||
x: 600,
|
||||
imgBg: "#688e26",
|
||||
bodyBg: "#181515",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/programming-laptop.png",
|
||||
},
|
||||
{
|
||||
x: -50,
|
||||
imgBg: "#1B2CC1",
|
||||
bodyBg: "#091540",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/projects-section-image.png",
|
||||
},
|
||||
{
|
||||
x: 600,
|
||||
imgBg: "#ffd87d",
|
||||
bodyBg: "#3e3f9c",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/why-so-serious.png",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Activate section based on scroll position
|
||||
*/
|
||||
const sections = document.querySelectorAll(".page-section");
|
||||
|
||||
function activateSection(index: number) {
|
||||
const targetPositionMap = positionColorMap[index];
|
||||
|
||||
if (!targetPositionMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
gsap.to("#main-image", {
|
||||
backgroundColor: targetPositionMap.imgBg,
|
||||
x: isMobile ? 0 : targetPositionMap.x,
|
||||
duration: targetPositionMap.duration,
|
||||
});
|
||||
gsap.to("body", {
|
||||
backgroundColor: targetPositionMap.bodyBg,
|
||||
});
|
||||
|
||||
if (targetPositionMap?.imgSrc) {
|
||||
changeMainImage(targetPositionMap.imgSrc);
|
||||
}
|
||||
|
||||
if (index >= 2) {
|
||||
gsap.to("#main-image img", {
|
||||
filter: "none",
|
||||
duration: 1,
|
||||
});
|
||||
} else {
|
||||
gsap.to("#main-image img", {
|
||||
filter: "grayscale(100%) contrast(140%)",
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
ScrollTrigger.create({
|
||||
trigger: section,
|
||||
start: "top 50%",
|
||||
end: "bottom 50%",
|
||||
onEnter: (self) => {
|
||||
activateSection(index);
|
||||
},
|
||||
onEnterBack: (self) => {
|
||||
activateSection(index);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Entry animation timeline
|
||||
*/
|
||||
const entryTimeline = gsap.timeline();
|
||||
|
||||
entryTimeline
|
||||
.from("#main-image", {
|
||||
clipPath: "circle(0)",
|
||||
})
|
||||
.to("#main-image", {
|
||||
clipPath: "circle(100%)",
|
||||
scale: 1,
|
||||
duration: 1,
|
||||
});
|
||||
|
||||
gsap.to("#main-image", {
|
||||
y: 20,
|
||||
repeat: -1,
|
||||
duration: 2,
|
||||
yoyo: true,
|
||||
ease: "sine.inOut",
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
async function changeMainImage(src: string) {
|
||||
const mainImage: HTMLImageElement | null = document.querySelector("#main-image img");
|
||||
|
||||
if (mainImage) {
|
||||
await gsap.to(mainImage, {
|
||||
opacity: 0,
|
||||
duration: 0.5,
|
||||
});
|
||||
|
||||
if (mainImage) {
|
||||
mainImage.setAttribute("src", src);
|
||||
|
||||
mainImage.onload = () => {
|
||||
gsap.to(mainImage, {
|
||||
opacity: 1,
|
||||
duration: 0.5,
|
||||
delay: 0.5,
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger, Observer } from "gsap/all";
|
||||
gsap.registerPlugin(ScrollTrigger, Observer);
|
||||
|
||||
export default function homepageTimeline({ componentRef }: { componentRef: { current: HTMLDivElement | null } }) {
|
||||
const mm = gsap.matchMedia();
|
||||
|
||||
const compHeight = componentRef.current?.clientHeight;
|
||||
|
||||
const isMobile = window.innerWidth <= 1200;
|
||||
|
||||
// mm.add("(min-width: 1200px)", () => {
|
||||
ScrollTrigger.create({
|
||||
trigger: "#homepage-content-wrapper",
|
||||
start: "200px 200px",
|
||||
end: "bottom 90%",
|
||||
pin: isMobile ? null : "#main-image",
|
||||
scrub: 1,
|
||||
onUpdate: (self) => {
|
||||
const scrollTop = compHeight ? self.progress * compHeight : 0;
|
||||
|
||||
/**
|
||||
* Origin
|
||||
*/
|
||||
if (!isMobile) {
|
||||
if (scrollTop < 300) {
|
||||
gsap.to("nav", {
|
||||
opacity: 1,
|
||||
pointerEvents: "visible",
|
||||
});
|
||||
gsap.to("header", {
|
||||
zIndex: 2000,
|
||||
});
|
||||
} else {
|
||||
gsap.to("nav", {
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
});
|
||||
gsap.to("header", {
|
||||
zIndex: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Mobile
|
||||
*/
|
||||
if (isMobile && scrollTop > 100) {
|
||||
gsap.to("#main-image", {
|
||||
opacity: 0.1,
|
||||
duration: 1,
|
||||
});
|
||||
} else {
|
||||
gsap.to("#main-image", {
|
||||
opacity: 1,
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
},
|
||||
onEnter: (self) => {},
|
||||
});
|
||||
|
||||
/**
|
||||
* Position color map
|
||||
*/
|
||||
const positionColorMap: {
|
||||
x: number;
|
||||
imgBg: string;
|
||||
bodyBg: string;
|
||||
duration: number;
|
||||
imgSrc?: string;
|
||||
}[] = [
|
||||
{
|
||||
x: 0,
|
||||
imgBg: "#3e3f9c",
|
||||
bodyBg: "#181515",
|
||||
duration: 1,
|
||||
imgSrc: "/images/my-photo-stroked.png",
|
||||
},
|
||||
{
|
||||
x: -50,
|
||||
imgBg: "#FE6847",
|
||||
bodyBg: "#292a6b",
|
||||
duration: 1,
|
||||
imgSrc: "/images/my-photo-3.png",
|
||||
},
|
||||
{
|
||||
x: 600,
|
||||
imgBg: "#688e26",
|
||||
bodyBg: "#181515",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/programming-laptop.png",
|
||||
},
|
||||
{
|
||||
x: -50,
|
||||
imgBg: "#1B2CC1",
|
||||
bodyBg: "#091540",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/projects-section-image.png",
|
||||
},
|
||||
{
|
||||
x: 600,
|
||||
imgBg: "#ffd87d",
|
||||
bodyBg: "#3e3f9c",
|
||||
duration: 1.2,
|
||||
imgSrc: "/images/why-so-serious.png",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Activate section based on scroll position
|
||||
*/
|
||||
const sections = document.querySelectorAll(".page-section");
|
||||
|
||||
function activateSection(index: number) {
|
||||
const targetPositionMap = positionColorMap[index];
|
||||
|
||||
if (!targetPositionMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
gsap.to("#main-image", {
|
||||
backgroundColor: targetPositionMap.imgBg,
|
||||
x: isMobile ? 0 : targetPositionMap.x,
|
||||
duration: targetPositionMap.duration,
|
||||
});
|
||||
gsap.to("body", {
|
||||
backgroundColor: targetPositionMap.bodyBg,
|
||||
});
|
||||
|
||||
if (targetPositionMap?.imgSrc) {
|
||||
changeMainImage(targetPositionMap.imgSrc);
|
||||
}
|
||||
|
||||
if (index >= 2) {
|
||||
gsap.to("#main-image img", {
|
||||
filter: "none",
|
||||
duration: 1,
|
||||
});
|
||||
} else {
|
||||
gsap.to("#main-image img", {
|
||||
filter: "grayscale(100%) contrast(140%)",
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
ScrollTrigger.create({
|
||||
trigger: section,
|
||||
start: "top 50%",
|
||||
end: "bottom 50%",
|
||||
onEnter: (self) => {
|
||||
activateSection(index);
|
||||
},
|
||||
onEnterBack: (self) => {
|
||||
activateSection(index);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Entry animation timeline
|
||||
*/
|
||||
const entryTimeline = gsap.timeline();
|
||||
|
||||
entryTimeline
|
||||
.from("#main-image", {
|
||||
clipPath: "circle(0)",
|
||||
})
|
||||
.to("#main-image", {
|
||||
clipPath: "circle(100%)",
|
||||
scale: 1,
|
||||
duration: 1,
|
||||
});
|
||||
|
||||
gsap.to("#main-image", {
|
||||
y: 20,
|
||||
repeat: -1,
|
||||
duration: 2,
|
||||
yoyo: true,
|
||||
ease: "sine.inOut",
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
async function changeMainImage(src: string) {
|
||||
const mainImage: HTMLImageElement | null = document.querySelector("#main-image img");
|
||||
|
||||
if (mainImage) {
|
||||
await gsap.to(mainImage, {
|
||||
opacity: 0,
|
||||
duration: 0.5,
|
||||
});
|
||||
|
||||
if (mainImage) {
|
||||
mainImage.setAttribute("src", src);
|
||||
|
||||
mainImage.onload = () => {
|
||||
gsap.to(mainImage, {
|
||||
opacity: 1,
|
||||
duration: 0.5,
|
||||
delay: 0.5,
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
[
|
||||
{
|
||||
"title": "Adobe Photoshop",
|
||||
"description": "Web design, image manipulation, image compositing, and more."
|
||||
},
|
||||
{
|
||||
"title": "Adobe Illustrator",
|
||||
"description": "Vector graphic of all types"
|
||||
},
|
||||
{
|
||||
"title": "Figma",
|
||||
"description": "Web, UI, UX design."
|
||||
},
|
||||
{
|
||||
"title": "Affinity Designer",
|
||||
"description": "Vector graphics."
|
||||
},
|
||||
{
|
||||
"title": "After Effects",
|
||||
"description": "Motion graphics and animation"
|
||||
},
|
||||
{
|
||||
"title": "Adobe XD",
|
||||
"description": "UI/UX design"
|
||||
},
|
||||
{
|
||||
"title": "Webflow",
|
||||
"description": "Visual Web coding"
|
||||
}
|
||||
]
|
||||
[
|
||||
{
|
||||
"title": "Adobe Photoshop",
|
||||
"description": "Web design, image manipulation, image compositing, and more."
|
||||
},
|
||||
{
|
||||
"title": "Adobe Illustrator",
|
||||
"description": "Vector graphic of all types"
|
||||
},
|
||||
{
|
||||
"title": "Figma",
|
||||
"description": "Web, UI, UX design."
|
||||
},
|
||||
{
|
||||
"title": "Affinity Designer",
|
||||
"description": "Vector graphics."
|
||||
},
|
||||
{
|
||||
"title": "After Effects",
|
||||
"description": "Motion graphics and animation"
|
||||
},
|
||||
{
|
||||
"title": "Adobe XD",
|
||||
"description": "UI/UX design"
|
||||
},
|
||||
{
|
||||
"title": "Webflow",
|
||||
"description": "Visual Web coding"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
[
|
||||
{
|
||||
"title": "HTML, CSS, Javascript",
|
||||
"description": "The basics, the bedrock of all websites."
|
||||
},
|
||||
{
|
||||
"title": "React JS",
|
||||
"description": "JavaScript library for high-performance web applications"
|
||||
},
|
||||
{
|
||||
"title": "Next JS",
|
||||
"description": "High performance React and Node js web framework for building blazing flast and performant web applications"
|
||||
},
|
||||
{
|
||||
"title": "Tailwind CSS",
|
||||
"description": "Lighting fast mobile first styling"
|
||||
},
|
||||
{
|
||||
"title": "Node JS",
|
||||
"description": "JavaScript runtime for the server. For creating backend architectures and APIs"
|
||||
},
|
||||
{
|
||||
"title": "Ubuntu Linux",
|
||||
"description": "Secure server management with ubuntu and Linux"
|
||||
},
|
||||
{
|
||||
"title": "Nginx",
|
||||
"description": "Super secure web server, reverse proxy and load balancer"
|
||||
},
|
||||
{
|
||||
"title": "MySQL",
|
||||
"description": "Tried and tested data storage, querying, and management."
|
||||
},
|
||||
{
|
||||
"title": "Git and Github",
|
||||
"description": "Version control"
|
||||
}
|
||||
]
|
||||
[
|
||||
{
|
||||
"title": "HTML, CSS, Javascript",
|
||||
"description": "The basics, the bedrock of all websites."
|
||||
},
|
||||
{
|
||||
"title": "React JS",
|
||||
"description": "JavaScript library for high-performance web applications"
|
||||
},
|
||||
{
|
||||
"title": "Next JS",
|
||||
"description": "High performance React and Node js web framework for building blazing flast and performant web applications"
|
||||
},
|
||||
{
|
||||
"title": "Tailwind CSS",
|
||||
"description": "Lighting fast mobile first styling"
|
||||
},
|
||||
{
|
||||
"title": "Node JS",
|
||||
"description": "JavaScript runtime for the server. For creating backend architectures and APIs"
|
||||
},
|
||||
{
|
||||
"title": "Ubuntu Linux",
|
||||
"description": "Secure server management with ubuntu and Linux"
|
||||
},
|
||||
{
|
||||
"title": "Nginx",
|
||||
"description": "Super secure web server, reverse proxy and load balancer"
|
||||
},
|
||||
{
|
||||
"title": "MySQL",
|
||||
"description": "Tried and tested data storage, querying, and management."
|
||||
},
|
||||
{
|
||||
"title": "Git and Github",
|
||||
"description": "Version control"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user