diff --git a/README.md b/README.md index 200f4282..ab461dcd 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ # Portfolio + +Netlify-link: + +Figma-link: https://www.figma.com/design/jOlPicmO7AGtZLrZOpgZ44/Portfolio?node-id=1791-1877&t=CGhZrNLZ8wEjnYxZ-0 \ No newline at end of file diff --git a/index.html b/index.html index 6676fb2d..08a62698 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,39 @@ - - - - - Portfolio - - -
- - - + + + + + + + + + Portfolio + + + +
+ + + + \ No newline at end of file diff --git a/package.json b/package.json index 48911600..3f03a53d 100644 --- a/package.json +++ b/package.json @@ -4,20 +4,23 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --host", "build": "vite build", "lint": "eslint .", "preview": "vite preview" }, "dependencies": { "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "styled-components": "^6.1.19", + "swiper": "^12.0.3" }, "devDependencies": { "@eslint/js": "^9.21.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", + "babel-plugin-styled-components": "^2.1.4", "eslint": "^9.21.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", diff --git a/public/images/cake.png b/public/images/cake.png new file mode 100644 index 00000000..072e61b9 Binary files /dev/null and b/public/images/cake.png differ diff --git a/public/images/cupcakes.png b/public/images/cupcakes.png new file mode 100644 index 00000000..0f714ada Binary files /dev/null and b/public/images/cupcakes.png differ diff --git a/public/images/discoball.png b/public/images/discoball.png new file mode 100644 index 00000000..a4c2c09c Binary files /dev/null and b/public/images/discoball.png differ diff --git a/public/images/gold.png b/public/images/gold.png new file mode 100644 index 00000000..ddd297f2 Binary files /dev/null and b/public/images/gold.png differ diff --git a/public/images/profilepicture.png b/public/images/profilepicture.png new file mode 100644 index 00000000..bd8779cd Binary files /dev/null and b/public/images/profilepicture.png differ diff --git a/public/images/quiz.png b/public/images/quiz.png new file mode 100644 index 00000000..1ebcb72c Binary files /dev/null and b/public/images/quiz.png differ diff --git a/public/images/recipelibrary.png b/public/images/recipelibrary.png new file mode 100644 index 00000000..e1b5d239 Binary files /dev/null and b/public/images/recipelibrary.png differ diff --git a/public/images/tailtales.png b/public/images/tailtales.png new file mode 100644 index 00000000..fac51827 Binary files /dev/null and b/public/images/tailtales.png differ diff --git a/public/images/weatherapp.png b/public/images/weatherapp.png new file mode 100644 index 00000000..17f6654c Binary files /dev/null and b/public/images/weatherapp.png differ diff --git a/src/App.jsx b/src/App.jsx index a161d8d3..4b232020 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,8 +1,31 @@ +import { GlobalStyle } from "./components/Styling/GlobalStyle" +import { Header } from "./components/1.Header" +import { Skills } from "./components/2.Skills" +import { Project } from "./components/3.Projects" +import { Tech } from "./components/4.Tech" +import { Articles } from "./components/5.Articles" +import { Contact } from "./components/6.Contact" + + + export const App = () => { return ( <> -

Portfolio

-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem, laborum! Maxime animi nostrum facilis distinctio neque labore consectetur beatae eum ipsum excepturi voluptatum, dicta repellendus incidunt fugiat, consequatur rem aperiam.

+ + + +
+ + + + + + + + + + + ) -} +} \ No newline at end of file diff --git a/src/components/1.Header.jsx b/src/components/1.Header.jsx new file mode 100644 index 00000000..0c374463 --- /dev/null +++ b/src/components/1.Header.jsx @@ -0,0 +1,43 @@ +import styled from "styled-components" +import { Icons } from "./Reusables/icons" +import { H1, H3, P } from "./Styling/Typography" + +export const Header = () => { + return ( + + +

I am Julia Lindstrand

+

Junior Frontend Developer

+

I am a developer with a passion for everything technology. For my whole life technology played a big part and I've always found much joy in learning about everything tech. What I bring to a new team is the same relentless curiosity that helped me debug code late into the night for school-projects, the discipline to learn independently, and the proven ability to thrive under pressure. I’m eager to apply these strengths to build robust, user‑focused products at  my next job.

+
+ +
+ ) +} + + +// Styling +const HeaderSection = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + flex-wrap: wrap; + + @media(max-width: 1440px) { + flex-direction: column; + align-items: center; +}` + +const TextSection = styled.div` + display: flex; + flex-direction: column; + margin: 128px 128px 0 128px; + max-width: 580px; +` + +const Picture = styled.img` + width: 526px; + height: auto; + object-fit: contain; +` \ No newline at end of file diff --git a/src/components/2.Skills.jsx b/src/components/2.Skills.jsx new file mode 100644 index 00000000..fa77b2a3 --- /dev/null +++ b/src/components/2.Skills.jsx @@ -0,0 +1,59 @@ +import skills from "../data/skills.json" +import styled from "styled-components" +import { H2, H4, P, UL } from "./Styling/Typography" +import { + theme +} from "./Styling/Theme" + +export const Skills = () => { + return ( + +

Skills

+ + {skills.skills.map((skill) => ( + +
    +

    + {skill.group}



    + {skill.items.map(skilling =>
      {skilling}
    )} +
))} +
+
+ ) +} + +// Styling +const SkillSection = styled.div` + text-align: center; + margin-top: 80px; + ` + +const SkillSectionSkills = styled.div` + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + gap: 24px; + margin-top: 15px; + +@media(max-width: 1440px) { + flex-direction: column; + align-items: center; +}` + +const SkillColumn = styled.div` + text-align: center; + width: 180px; + padding-right: 30px; + &:not(:last-child) { + border-right: 2px solid ${(props) => props.$color}; + } + + @media (max-width: 1440px) { + &:not(:last-child) { + border-right: none; + border-bottom: 2px solid ${(props) => props.$color}; + padding-bottom: 20px; + margin-bottom: 20px; + }}` \ No newline at end of file diff --git a/src/components/3.Projects.jsx b/src/components/3.Projects.jsx new file mode 100644 index 00000000..9c13c99f --- /dev/null +++ b/src/components/3.Projects.jsx @@ -0,0 +1,42 @@ +import projectsData from "../data/projects.json" +import { ProjectCard } from "./Reusables/card" +import styled from "styled-components" +import { H2 } from "./Styling/Typography" +import { Carousel } from "./Styling/Carousel" + +export const Project = () => { + return ( + +

Featured Projects

+ ( + + )} + /> +
+ ) +} + + +// Styling +const ProjectSection = styled.div` + margin-top: 80px; +` + +const Projects = styled.div` +display: flex; +flex-direction: row; +justify-content: center; +align-items: flex-start; +padding: 0px; +gap: 64px; +width: 1440px; +height: 625px;` \ No newline at end of file diff --git a/src/components/4.Tech.jsx b/src/components/4.Tech.jsx new file mode 100644 index 00000000..b65d62fb --- /dev/null +++ b/src/components/4.Tech.jsx @@ -0,0 +1,26 @@ +import styled from "styled-components" +import { H2, H3 } from "./Styling/Typography" + + +export const Tech = () => { + return ( + +

Tech

+ +

HTML, CSS, Flexbox, JavaScript, ES6, JSX, React, React Hooks, Node.js, Mongo DB, Web Accessibility, APIs, Mob-programming, Pair-programming, GitHub

+
+
+ ) +} + + +// Styling +const TechSection = styled.div` + margin-top: 120px; +` + +const TechContainer = styled.div` + justify-self: center; + text-align: center; + max-width: 782px; +` \ No newline at end of file diff --git a/src/components/5.Articles.jsx b/src/components/5.Articles.jsx new file mode 100644 index 00000000..88b05599 --- /dev/null +++ b/src/components/5.Articles.jsx @@ -0,0 +1,40 @@ +import articlesData from "../data/articles.json" +import { ArticleCard } from "./Reusables/card" +import styled from "styled-components" +import { H2 } from "./Styling/Typography" +import { Carousel } from "./Styling/Carousel" + +export const Articles = () => { + return ( + +

My Journey

+ ( + + )} + /> +
+ ) +} + + +// Styling +const ArticlesSection = styled.div` + margin-top: 100px; +` + +const ArticlesContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex - start; + padding: 0px; + gap: 64px; + width: 1440px; + height: 625px;` \ No newline at end of file diff --git a/src/components/6.Contact.jsx b/src/components/6.Contact.jsx new file mode 100644 index 00000000..e09deb54 --- /dev/null +++ b/src/components/6.Contact.jsx @@ -0,0 +1,36 @@ +import { Icons } from "./Reusables/icons" +import styled from "styled-components" +import { H2, H3 } from "./Styling/Typography" + +export const Contact = () => { + return ( + + + +

Let's talk

+

Julia Lindstrand

+

+46 (0) 768 28 97 94

+

julia.lindstrand@pm.me

+
+
+ ) +} + +// Styling +const ContactSection = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + @media (max-width: 667px) { + flex-direction: column; + } +` +const Picture = styled.img` + width: 476px; +` +const ContactInfo = styled.div` + display: flex; + flex-direction: column; +` \ No newline at end of file diff --git a/src/components/Reusables/buttons.jsx b/src/components/Reusables/buttons.jsx new file mode 100644 index 00000000..b6418ac2 --- /dev/null +++ b/src/components/Reusables/buttons.jsx @@ -0,0 +1,29 @@ +import styled from "styled-components" +import { + theme +} from "../Styling/Theme" + +export const Button = ({ href, title, className }) => { + + return ( + <> + + {title} + + + ) +} + +const StyledButton = styled.button` + width: 192px; + height: 48px; + background: ${(props) => theme.variant[props.$className]?.background}; + border-radius: 12px; + border: 2px solid ${(props) => props.$color}; + gap: 5xp; + ` + +const StyledLink = styled.a` + text-decoration: none; + color: ${(props) => theme.variant[props.$className]?.color}; + ` \ No newline at end of file diff --git a/src/components/Reusables/card.jsx b/src/components/Reusables/card.jsx new file mode 100644 index 00000000..46d09c36 --- /dev/null +++ b/src/components/Reusables/card.jsx @@ -0,0 +1,56 @@ +import { H3, P } from "../Styling/Typography" +import { Button } from "./buttons" +import styled from "styled-components" + +export const ArticleCard = ({ title, image, description, readmore }) => { + return ( + <> + + +

{title}

+

{description}

+ +
+ ) +} + +export const ProjectCard = ({ name, image, description, netlify, github }) => { + return ( + <> + + +

{name}

+

{description}

+ + + + +
+ + ) +} + +const Card = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 0px; + gap: 24px; + width: 400px; + height: 700px; +` + +const Buttons = styled.div` + display: flex; + gap: 15px; +` +const Picture = styled.img` + width: 400px; + height: 300px; +` \ No newline at end of file diff --git a/src/components/Reusables/icons.jsx b/src/components/Reusables/icons.jsx new file mode 100644 index 00000000..605f8a85 --- /dev/null +++ b/src/components/Reusables/icons.jsx @@ -0,0 +1,22 @@ +import githubicon from "../../images/icons/github.png" +import linkedinicon from "../../images/icons/linkedin.png" +import stackoverflowicon from "../../images/icons/stackoverflow.png" +import styled from "styled-components" + +export const Icons = () => { + return ( + + + + + + ) +} + +const IconRow = styled.div` + display: flex; + flex-direction: row;` + +const Picture = styled.img` + padding-right: 15px; +` \ No newline at end of file diff --git a/src/components/Styling/Carousel.jsx b/src/components/Styling/Carousel.jsx new file mode 100644 index 00000000..2cd53da6 --- /dev/null +++ b/src/components/Styling/Carousel.jsx @@ -0,0 +1,104 @@ +import styled from "styled-components"; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/scrollbar"; +import { Scrollbar, Mousewheel, FreeMode } from "swiper/modules"; +import { + theme +} from "../Styling/Theme" + +export const Carousel = ({ data, renderItem }) => { + return ( + + = 1200px + 1200: { + slidesPerView: 3, + spaceBetween: 150, + }, + // when window width is >= 992px + 992: { + slidesPerView: 3, + spaceBetween: 150, + }, + // when window width is >= 768px + 768: { + slidesPerView: 2, + spaceBetween: 150, + }, + // when window width is < 768px + 0: { + slidesPerView: 1, + spaceBetween: 150, + }, + }} + > + {data.map((item, index) => ( + + {renderItem(item, index)} + + ))} + + + ); +}; + +const CarouselWrapper = styled.div` + margin-top: 62px; + padding: 0 20px; + max-width: 1400px; + width: 100%; + overflow: visible; + + .swiper { + padding-bottom: 70px; + } + + .swiper-wrapper { + align-items: stretch; + } + + .swiper-slide { + width: 100% !important; + height: auto; + display: flex; + } + + .swiper-scrollbar { + height: 20px; + background: #d8d8d8; + border-radius: 20px; + margin: 32px auto 0; + width: 80%; + cursor: pointer; + position: relative; + } + + .swiper-scrollbar-drag { + background: ${(props) => props.$color}; + border-radius: 20px; + height: 100%; + cursor: grab; + } + + .swiper-scrollbar-drag:active { + cursor: grabbing; + } + + @media (max-width: 768px) { + padding: 0 20px; + } + + .swiper-slide { + width: 300px !important;} +`; \ No newline at end of file diff --git a/src/components/Styling/GlobalStyle.js b/src/components/Styling/GlobalStyle.js new file mode 100644 index 00000000..0082485c --- /dev/null +++ b/src/components/Styling/GlobalStyle.js @@ -0,0 +1,20 @@ +import { createGlobalStyle } from "styled-components" + +export const basecolor = "#FD6F00" +export const GlobalStyle = createGlobalStyle` + * { + margin: 0; + padding: 0; + color: #202020; + font-style: normal; + } + +body { + display: flex; + flex-direction: column; + align-items: center; +} + +H2 { + text-align: center; +}` \ No newline at end of file diff --git a/src/components/Styling/Theme.js b/src/components/Styling/Theme.js new file mode 100644 index 00000000..9dc69421 --- /dev/null +++ b/src/components/Styling/Theme.js @@ -0,0 +1,17 @@ +import { basecolor } from "./GlobalStyle" + +export const theme = { + color: basecolor, + variant: { + "live-demo": { + background: basecolor, + color: "white" + }, + "view-code": { + color: basecolor + }, + "read-article": { + color: basecolor + } + } +} \ No newline at end of file diff --git a/src/components/Styling/Typography.jsx b/src/components/Styling/Typography.jsx new file mode 100644 index 00000000..e3213337 --- /dev/null +++ b/src/components/Styling/Typography.jsx @@ -0,0 +1,41 @@ +import styled from "styled-components" + +export const H1 = styled.h1` + font-family: 'Urbanist'; + font-weight: 700; + font-size: 100px; + line-height: 100px; + margin-bottom: 30px;` + +export const H2 = styled.h2` + font-family: 'Urbanist'; + font-weight: 700; + font-size: 80px; + line-height: 100px; + ` + +export const H3 = styled.h3` + font-family: 'Poppins'; + font-weight: 500; + font-size: 24px; + line-height: 36px;` + +export const H4 = styled.h4` + font-family: 'Poppins'; + font-size: 30px; +` + +export const P = styled.p` + font-family: 'Poppins'; + font-weight: 400; + font-size: 18px; + line-height: 32px; + padding-bottom: 20px;` + + +export const UL = styled.ul` + font-family: 'Poppins'; + font-weight: 400; + font-size: 18px; + line-height: 32px; + padding-bottom: 5px;` \ No newline at end of file diff --git a/src/data/articles.json b/src/data/articles.json new file mode 100644 index 00000000..3547d06b --- /dev/null +++ b/src/data/articles.json @@ -0,0 +1,27 @@ +{ + "articles": [ + { + "title": "Learning to love code", + "image": "/images/discoball.png", + "description": "Writing code is less about “just working”. Instead, it’s much more about creativity. It’s similar to creative writing in that the author architecting a story must use an assortment of tools and components (i.e., content) in a way to satisfy a particular objective.", + "readmore": "link" + }, + { + "title": "My First Codereview", + "image": "/images/gold.png", + "description": "Writing code is less about “just working”. Instead, it’s much more about creativity. It’s similar to creative writing in that the author architecting a story must use an assortment of tools and components (i.e., content) in a way to satisfy a particular objective.", + "readmore": "link" + }, + { + "title": "Javascript 101", + "image": "/images/cupcakes.png", + "description": "Writing code is less about “just working”. Instead, it’s much more about creativity. It’s similar to creative writing in that the author architecting a story must use an assortment of tools and components (i.e., content) in a way to satisfy a particular objective.", + "readmore": "link" + }, + { + "title": "Javascript 102", + "image": "/images/cake.png", + "description": "Writing code is less about “just working”. Instead, it’s much more about creativity. It’s similar to creative writing in that the author architecting a story must use an assortment of tools and components (i.e., content) in a way to satisfy a particular objective.", + "readmore": "link" + } + ] } \ No newline at end of file diff --git a/src/data/projects.json b/src/data/projects.json index 7c426028..d8c8e2a1 100644 --- a/src/data/projects.json +++ b/src/data/projects.json @@ -2,18 +2,20 @@ "projects": [ { "name": "Business site", - "image": "https://images.unsplash.com/photo-1557008075-7f2c5efa4cfd?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2497&q=80", + "image": "/images/tailtales.png", + "description": "This is a website for adopting cats and seeing how the adoption process works. Every cat has their own card with information and picture. Then there’s a form to fill out if you want to adopt", "tags": [ "HTML5", "CSS3", "JavaScript" ], - "netlify": "link", - "github": "link" + "netlify": "https://technigo-tailtales.app/", + "github": "https://github.com/julialindstrand/js-project-business-site" }, { "name": "Weather app", - "image": "https://images.unsplash.com/photo-1520792532857-293bd046307a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2370&q=80", + "image": "/images/weatherapp.png", + "description": "A weather application with the ability to toggle between four different cities. It shows a picture of the cities in the background. You can also see the next 5 days forecast.", "tags": [ "HTML5", "CSS3", @@ -21,8 +23,33 @@ "TypeScript", "APIs" ], - "netlify": "link", - "github": "link" + "netlify": "https://poodles3-weather-app.netlify.app", + "github": "https://github.com/julialindstrand/js-project-weather-app" + }, + { + "name": "Recipe Library", + "image": "/images/recipelibrary.png", + "description": "A simple site with recipes fetched by an API. I followed a design as closely as possible and just integrated the API. It was focus on beeing able to sort and filter the different recipes.", + "tags": [ + "HTML5", + "CSS3", + "JavaScript", + "APIs" + ], + "netlify": "https://recipeslibrary.netlify.app/", + "github": "https://github.com/julialindstrand/js-project-recipe-library" + }, + { + "name": "Quiz", + "image": "/images/quiz.png", + "description": "A groupproject where we chose to make a little quiz about ourselfs. First you have to enter your information to get to the quiz and you get all the answers in the about page.", + "tags": [ + "HTML5", + "CSS3", + "JavaScript" + ], + "netlify": "https://github.com/julialindstrand/js-project-accessibility", + "github": "https://github.com/julialindstrand/js-project-accessibility" } ] } \ No newline at end of file diff --git a/src/data/skills.json b/src/data/skills.json new file mode 100644 index 00000000..1fe5b1a6 --- /dev/null +++ b/src/data/skills.json @@ -0,0 +1,37 @@ +{ + "skills": [ + { "group": "Code", + "items": [ + "HTML5", + "CSS3", + "JavaScript", + "TypeScript", + "React", + "JSON" + ] + }, { + "group": "Toolbox", + "items": [ + "VS Code", + "Figma", + "Netlify", + "Github", + "Slack", + "Mattermost" + ] + }, { + "group": "Upcoming", + "items": [ + "Node.js", + "MongoDB" + ] + }, { + "group": "More", + "items": [ + "Agile methodology", + "Web accessibility", + "Wordpress" + ] + } + ] +} \ No newline at end of file diff --git a/src/images/icons/github.png b/src/images/icons/github.png new file mode 100644 index 00000000..e2e63d21 Binary files /dev/null and b/src/images/icons/github.png differ diff --git a/src/images/icons/linkedin.png b/src/images/icons/linkedin.png new file mode 100644 index 00000000..a8926ee1 Binary files /dev/null and b/src/images/icons/linkedin.png differ diff --git a/src/images/icons/stackoverflow.png b/src/images/icons/stackoverflow.png new file mode 100644 index 00000000..dfb53b26 Binary files /dev/null and b/src/images/icons/stackoverflow.png differ diff --git a/src/index.css b/src/index.css index 61010be6..f72b9e52 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,4 @@ -body { - background: pink; - color: hotpink; -} \ No newline at end of file +/* body { + background: rgb(86, 146, 113); + color: rgb(0, 0, 0); +} */ \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 8b0f57b9..3995d7a4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,14 @@ +// https://vite.dev/config/ +// vite.config.js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -// https://vite.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [ + react({ + babel: { + plugins: [['babel-plugin-styled-components', { displayName: true }]] + } + }) + ] +}) \ No newline at end of file