Compare commits
	
		
			19 Commits
		
	
	
		
			8ddbfe6598
			...
			tailwind
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7bd1f7778a | |||
| bcac680d87 | |||
| 377f0dd743 | |||
| f4dc87d841 | |||
| 1d9d84484d | |||
| 3e5c2a1c1d | |||
| 7476cfce33 | |||
| 53928e5250 | |||
| 61b8ad6380 | |||
| a4fe5e4efc | |||
| 5712c890af | |||
| 504fa251b7 | |||
| d0e35a6d40 | |||
| 5de10940d9 | |||
| 8e9d3f138c | |||
| 412bc5fca1 | |||
| 11c72a9389 | |||
| cc9a4af7d0 | |||
| 90cdb2bf30 | 
| @@ -6,4 +6,4 @@ | ||||
|     :root { | ||||
|         --color-kamilcraft-green: 162 207 0; | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -20,8 +20,7 @@ $btn-colors: ( | ||||
|   min-width: 270px; | ||||
|   padding: 8px 10px; | ||||
|  | ||||
|   border-radius: 3px; | ||||
|   border-width: 3px; | ||||
|   @apply border-4 rounded-md; | ||||
|   border-style: solid; | ||||
|   border-color: $default-color; | ||||
|  | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| <template> | ||||
|   <SiteHeader /> | ||||
|   <main | ||||
|     rel="main" | ||||
|   > | ||||
|     <SiteHeader /> | ||||
|     <RouterView /> | ||||
|     <FooterComponent /> | ||||
|   </main> | ||||
|   <FooterComponent /> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import SiteHeader from './components/SiteHeader' | ||||
| import FooterComponent from './components/FooterComponent' | ||||
| import SiteHeader from '@/components/SiteHeader' | ||||
| import FooterComponent from '@/components/FooterComponent' | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
|               :icon="['fab', link.icon]" | ||||
|             /> | ||||
|             <span class="hidden md:inline-block">{{ link.title }}</span> | ||||
|             <span class="md:hidden">{{ link.shortcut }}</span> | ||||
|             <span class="hidden sm:inline-block md:hidden">{{ link.shortcut }}</span> | ||||
|           </a> | ||||
|         </li> | ||||
|       </ul> | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| <template> | ||||
|   <div class="hello"> | ||||
|     <h1>{{ route.meta.title }}</h1> | ||||
|     <p>Witam na mojej stronie głównej. Wszystkich zainteresowanych oczywiście 😁</p> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { useRoute } from 'vue-router' | ||||
|  | ||||
| const route = useRoute() | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   h1 { | ||||
|     margin: 30px 0 20px; | ||||
|   } | ||||
|   ul { | ||||
|     list-style-type: none; | ||||
|     padding: 0; | ||||
|   } | ||||
|   li { | ||||
|     display: inline-block; | ||||
|     margin: 0 10px; | ||||
|   } | ||||
|   a { | ||||
|     color: #42b983; | ||||
|   } | ||||
| </style> | ||||
| @@ -1,42 +1,50 @@ | ||||
| <template> | ||||
|   <div class="projects"> | ||||
|   <section | ||||
|     id="projects" | ||||
|     class="max-w-screen-xl mx-auto px-6 xl:px-2 py-10" | ||||
|   > | ||||
|     <slot /> | ||||
|     <div class="container"> | ||||
|     <div class="grid items-start grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-5"> | ||||
|       <div | ||||
|         v-for="project in projects" | ||||
|         :key="project.title.slug" | ||||
|         class="project" | ||||
|         class="flex flex-col lg:grid grid-project relative bg-neutral-100 border border-gray-200 rounded-md" | ||||
|       > | ||||
|         <img | ||||
|           v-if="project.images.small" | ||||
|           class="project_image" | ||||
|           class="project-image w-full h-[16rem] lg:w-[12.5rem] lg:h-[12.5rem] object-cover object-top rounded-t-md lg:rounded-bl-md lg:rounded-tr-none" | ||||
|           :src="project.images.small" | ||||
|           :alt="project.title" | ||||
|         > | ||||
|         <img | ||||
|           v-else-if="project.images.large" | ||||
|           class="project_image" | ||||
|           class="project-image w-[12.5rem] h-[12.5rem] object-cover" | ||||
|           :src="project.images.large" | ||||
|           :alt="project.title" | ||||
|         > | ||||
|         <div class="project_content"> | ||||
|           <h3 class="project_title"> | ||||
|             {{ project.title }} | ||||
|           </h3> | ||||
|           <div class="project_release"> | ||||
|             {{ project.version }} | ||||
|           </div> | ||||
|           <div | ||||
|             class="project_description" | ||||
|         <div class="project-content relative p-3 h-[12.5rem] overflow-y-hidden after:absolute after:left-0 after:top-0 after:w-full after:h-full"> | ||||
|           <header class="pb-2"> | ||||
|             <h3 class="text-lg font-bold"> | ||||
|               {{ project.title }} | ||||
|             </h3> | ||||
|             <p class="text-sm"> | ||||
|               {{ project.project_version }} | ||||
|             </p> | ||||
|           </header> | ||||
|           <p | ||||
|             class="text-sm" | ||||
|             v-html="markdownToText(project)" | ||||
|           /> | ||||
|         </div> | ||||
|         <div class="more-button"> | ||||
|         <div | ||||
|           class="project-button lg:flex lg:absolute lg:justify-center lg:items-center lg:left-0 lg:top-0 lg:w-full lg:h-full" | ||||
|         > | ||||
|           <BaseButton | ||||
|             has-icon | ||||
|             icon="eye" | ||||
|             is-reverse | ||||
|             class="btn" | ||||
|             class="w-full lg:w-80 rounded-t-none lg:rounded-t-md" | ||||
|             title="Pokaż więcej" | ||||
|             @click="router.push({ name: 'Project', params: { id: project.id } })" | ||||
|           > | ||||
|             O projekcie | ||||
| @@ -44,14 +52,14 @@ | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { defineProps, onMounted } from 'vue' | ||||
| import { useRoute, useRouter } from 'vue-router' | ||||
| import { useStore } from 'vuex' | ||||
| import BaseButton from './buttons/BaseButton' | ||||
| import BaseButton from '@/components/buttons/BaseButton' | ||||
| import { marked } from 'marked' | ||||
|  | ||||
| defineProps({ | ||||
| @@ -83,133 +91,47 @@ function markdownToText (project) { | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "scss/media"; | ||||
| <style lang="scss" scoped> | ||||
| @import 'scss/media'; | ||||
|  | ||||
| .projects { | ||||
|   padding-top: 45px; | ||||
|   padding-bottom: 45px; | ||||
| .grid-project { | ||||
|   animation: load-project 2s forwards; | ||||
|  | ||||
|   .container { | ||||
|     display: grid; | ||||
|     align-items: flex-start; | ||||
|     grid-template-columns: 1fr 1fr; | ||||
|     grid-auto-rows: minmax(80px, auto); | ||||
|     column-gap: 25px; | ||||
|     row-gap: 20px; | ||||
|   .project-image, .project-content { | ||||
|     object-position: top center; | ||||
|   } | ||||
|  | ||||
|     .project { | ||||
|       display: grid; | ||||
|       position: relative; | ||||
|       grid-template-areas: 'image content'; | ||||
|       grid-template-columns: 200px 1fr; | ||||
|       background-color: #fafafa; | ||||
|       border: 1px solid rgba(0, 0, 0, .025); | ||||
|       border-radius: 5px; | ||||
|       animation: load-project 2s forwards; | ||||
|   .project-image { | ||||
|     grid-area: image; | ||||
|   } | ||||
|  | ||||
|       .project_image { | ||||
|         grid-area: image; | ||||
|         width: 200px; | ||||
|         height: 200px; | ||||
|         object-fit: cover; | ||||
|         object-position: top center; | ||||
|       } | ||||
|   .project-content { | ||||
|     grid-area: content; | ||||
|  | ||||
|       .project_content { | ||||
|         grid-area: content; | ||||
|         padding: 10px 15px; | ||||
|         height: 200px; | ||||
|         overflow-y: hidden; | ||||
|         position: relative; | ||||
|  | ||||
|         .project_title { | ||||
|           font-size: 1.3em; | ||||
|           font-weight: normal; | ||||
|           line-height: 1.5em; | ||||
|         } | ||||
|  | ||||
|         .project_release { | ||||
|           font-size: .9em; | ||||
|           font-weight: bold; | ||||
|           padding: 5px 0; | ||||
|         } | ||||
|  | ||||
|         &::after { | ||||
|           content: ""; | ||||
|           position: absolute; | ||||
|           left: 0; | ||||
|           top: 0; | ||||
|           width: 100%; | ||||
|           height: 100%; | ||||
|           background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 60%, #fafafa 100%); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       p { | ||||
|         font-size: .9em; | ||||
|       } | ||||
|     &::after { | ||||
|       background: linear-gradient(180deg, hsla(0, 0%, 100%, 0) 60%, #fafafa); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|     @include media-tablet(true) { | ||||
|       .project { | ||||
|         .more-button { | ||||
| @screen lg { | ||||
|   .grid-project { | ||||
|     grid-template-areas: 'image content'; | ||||
|     grid-template-columns: 200px 1fr; | ||||
|  | ||||
|     .project-button { | ||||
|       .btn { | ||||
|         display: none; | ||||
|       } | ||||
|       &:hover { | ||||
|         background: rgba(0, 0, 0, .3); | ||||
|         border-radius: 5px; | ||||
|  | ||||
|         .btn { | ||||
|           display: flex; | ||||
|           justify-content: center; | ||||
|           align-items: center; | ||||
|           position: absolute; | ||||
|           left: 0; | ||||
|           top: 0; | ||||
|           width: 100%; | ||||
|           height: 100%; | ||||
|  | ||||
|           .btn { | ||||
|             display: none; | ||||
|           } | ||||
|  | ||||
|           &:hover { | ||||
|             background: rgba(0, 0, 0, .3); | ||||
|             border-radius: 5px; | ||||
|  | ||||
|             .btn { | ||||
|               display: flex; | ||||
|               color: white; | ||||
|               border-style: none; | ||||
|               &:hover { | ||||
|                 background-color: #385c8a; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     @include media-small { | ||||
|       .project { | ||||
|         display: block; | ||||
|  | ||||
|         .project_image { | ||||
|           width: 100%; | ||||
|           height: 250px; | ||||
|         } | ||||
|  | ||||
|         .project_content { | ||||
|           height: 125px; | ||||
|         } | ||||
|  | ||||
|         .more-button { | ||||
|           display: block; | ||||
|           position: unset; | ||||
|           margin-top: 8px; | ||||
|           height: auto; | ||||
|           left: unset; | ||||
|           top: unset; | ||||
|  | ||||
|           .btn { | ||||
|             display: flex; | ||||
|             width: 100%; | ||||
|             border-radius: 0; | ||||
|             border-style: solid; | ||||
|             background-color: rgba(255, 255, 255, .9); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| @@ -227,13 +149,4 @@ function markdownToText (project) { | ||||
|     opacity: 1; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @include media-tablet { | ||||
|   .projects .container { | ||||
|     grid-template-columns: 1fr; | ||||
|     padding: 25px; | ||||
|     column-gap: 0; | ||||
|     row-gap: 20px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -27,7 +27,7 @@ | ||||
| import { computed } from 'vue' | ||||
| import { useStore } from 'vuex' | ||||
| import { useRoute } from 'vue-router' | ||||
| import Navigation from './NavigationHeader' | ||||
| import Navigation from '@/components/NavigationHeader' | ||||
|  | ||||
| const store = useStore() | ||||
| const route = useRoute() | ||||
|   | ||||
| @@ -32,8 +32,8 @@ defineProps({ | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "../../../scss/btn"; | ||||
| <style lang="scss"> | ||||
| @import 'scss/btn'; | ||||
|  | ||||
| .btn { | ||||
|   @include button($has-icon: true); | ||||
|   | ||||
| @@ -25,7 +25,7 @@ defineProps({ | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "../../../scss/btn"; | ||||
| @import 'scss/btn'; | ||||
|  | ||||
| .btn { | ||||
|   @include ghost-button(); | ||||
|   | ||||
| @@ -1,24 +1,27 @@ | ||||
| <template> | ||||
|   <div class="about"> | ||||
|     <div class="container"> | ||||
|       <div id="grid"> | ||||
|         <div id="grid-text"> | ||||
|           <h2 class="name"> | ||||
|   <div class="bg-neutral-50"> | ||||
|     <div class="max-w-screen-xl mx-auto px-6 xl:px-2 py-11"> | ||||
|       <div | ||||
|         id="grid-columns" | ||||
|         class="flex flex-col md:grid items-center" | ||||
|       > | ||||
|         <div id="grid-content"> | ||||
|           <h2 class="text-[2rem]"> | ||||
|             Kamil Niemczycki | ||||
|           </h2> | ||||
|           <div class="tagline"> | ||||
|           <div class="mb-2 text-[1.5rem]"> | ||||
|             Web Developer | ||||
|           </div> | ||||
|           <p> | ||||
|             Jestem młodym i ambitnym inżynierem oprogramowania. Specjalizuję się w tworzeniu frontendów i backendów. | ||||
|             W projektach wykorzystuję techologie oparte o PHP i JavaScript, tworząc skomplikowane i skalowalne aplikacje internetowe. | ||||
|           </p> | ||||
|           <div class="buttons"> | ||||
|           <div class="flex flex-col sm:flex-row justify-center md:justify-start py-6 gap-5"> | ||||
|             <BaseButton | ||||
|               has-icon | ||||
|               icon="portrait" | ||||
|               is-reverse | ||||
|               @click="scrollTo('.selected-projects')" | ||||
|               @click="scrollTo('#projects')" | ||||
|             > | ||||
|               Wybrane projekty | ||||
|             </BaseButton> | ||||
| @@ -32,9 +35,10 @@ | ||||
|           </div> | ||||
|         </div> | ||||
|         <div id="grid-photo"> | ||||
|           <figure id="about-photo"> | ||||
|           <figure> | ||||
|             <img | ||||
|               :src="`${publicPath}assets/me.jpg`" | ||||
|               class="mx-auto rounded-full object-cover w-[12.5rem] h-[12.5rem]" | ||||
|               alt="Moje zdjęcie" | ||||
|             > | ||||
|           </figure> | ||||
| @@ -45,7 +49,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import BaseButton from '../buttons/BaseButton' | ||||
| import BaseButton from '@/components/buttons/BaseButton' | ||||
| import { useRouter } from 'vue-router' | ||||
|  | ||||
| const router = useRouter() | ||||
| @@ -59,97 +63,17 @@ function scrollTo(id) { | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "scss/media"; | ||||
| #grid-columns { | ||||
|   grid-template-columns: 1fr 1fr .8fr; | ||||
|   grid-template-areas: | ||||
|     'text text photo'; | ||||
| } | ||||
|  | ||||
| .about { | ||||
|   background-color: var(--gray-color) !important; | ||||
| #grid-content { | ||||
|   grid-area: text; | ||||
| } | ||||
|  | ||||
|   .container { | ||||
|     padding-top: 45px; | ||||
|     padding-bottom: 45px; | ||||
|   } | ||||
|   h2.name { | ||||
|     font-size: 2.1em; | ||||
|     margin-bottom: 5px; | ||||
|   } | ||||
|   div.tagline { | ||||
|     font-size: 1.6em; | ||||
|     margin-bottom: .7em; | ||||
|   } | ||||
|   #grid { | ||||
|      display: grid; | ||||
|      grid-template-columns: 1fr 1fr .8fr; | ||||
|      grid-template-areas: | ||||
|        'text text photo'; | ||||
|      align-items: center; | ||||
|  | ||||
|      #grid-text { | ||||
|        grid-area: text; | ||||
|        text-align: left; | ||||
|  | ||||
|        .buttons { | ||||
|          display: flex; | ||||
|          justify-content: flex-start; | ||||
|          padding: 25px 0; | ||||
|  | ||||
|          .btn { | ||||
|            margin-right: 20px; | ||||
|  | ||||
|            &:last-child { | ||||
|              margin-right: 0; | ||||
|            } | ||||
|  | ||||
|            @include media-tablet { | ||||
|              margin: 0 auto 15px; | ||||
|  | ||||
|              &:last-child { | ||||
|                margin: 0 auto; | ||||
|              } | ||||
|            } | ||||
|          } | ||||
|  | ||||
|          @include media-small { | ||||
|            justify-content: center; | ||||
|            margin-bottom: 25px; | ||||
|          } | ||||
|  | ||||
|          @include media-tablet { | ||||
|            display: block; | ||||
|            margin-bottom: 25px; | ||||
|          } | ||||
|        } | ||||
|  | ||||
|        @include media-mobile() { | ||||
|          .buttons .btn, | ||||
|          .buttons a { | ||||
|            min-width: unset; | ||||
|            width: 100%; | ||||
|          } | ||||
|        } | ||||
|      } | ||||
|      #grid-photo { | ||||
|        grid-area: photo; | ||||
|  | ||||
|        #about-photo img { | ||||
|          border-radius: 50%; | ||||
|        } | ||||
|      } | ||||
|      figure { | ||||
|        text-align: center; | ||||
|        img { | ||||
|          object-fit: cover; | ||||
|          width: 200px; | ||||
|          height: 200px; | ||||
|        } | ||||
|      } | ||||
|   } | ||||
|   @include media-small { | ||||
|     #grid { | ||||
|       grid-template-columns: 1fr 1fr; | ||||
|       grid-template-areas: | ||||
|     'text text' | ||||
|     'photo photo'; | ||||
|     } | ||||
|   } | ||||
| #grid-photo { | ||||
|   grid-area: photo; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| <template> | ||||
|   <div class="experiences"> | ||||
|     <div class="container"> | ||||
|       <h2>Wykorzystywane technologie</h2> | ||||
|       <p> | ||||
|   <div> | ||||
|     <div class="max-w-screen-xl mx-auto px-6 xl:px-2 py-11"> | ||||
|       <h2 class="text-[2rem] mb-2"> | ||||
|         Wykorzystywane technologie | ||||
|       </h2> | ||||
|       <p class="mb-5"> | ||||
|         Programowaniem stron internetowych zajmuję się najmłodszych lat, czyli od 2011 roku. Pierwsze projekty były | ||||
|         proste i najczęściej na użytek własny. Jednakże, doświadczenie zebrane przez lata pomogło mi wyselekcjonować | ||||
|         technologie, które wspomagają pisanie i rozwijanie oprogramowania. | ||||
|       </p> | ||||
|       <div class="skills"> | ||||
|       <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-5"> | ||||
|         <div | ||||
|           v-for="(skill, skillKey) in list" | ||||
|           :key="skillKey" | ||||
|           class="skill-group" | ||||
|           class="p-4 bg-neutral-50 rounded-lg" | ||||
|         > | ||||
|           <header class="skill-header"> | ||||
|             <div class="tech-icons"> | ||||
|           <header> | ||||
|             <div class="flex gap-2 text-3xl mb-2"> | ||||
|               <font-awesome-icon | ||||
|                 v-for="(icon, iconKey) in skill.icons" | ||||
|                 :key="iconKey" | ||||
| @@ -24,13 +26,25 @@ | ||||
|                 :title="icon.title" | ||||
|               /> | ||||
|             </div> | ||||
|             <h3>{{ skill.header }}</h3> | ||||
|             <h3 class="text-lg font-bold"> | ||||
|               {{ skill.header }} | ||||
|             </h3> | ||||
|           </header> | ||||
|           <p v-if="skill.showMore.value || skill.description.length < 200"> | ||||
|           <p | ||||
|             v-if="skill.showMore.value || skill.description.length < 200" | ||||
|             class="text-sm" | ||||
|           > | ||||
|             {{ skill.description }} | ||||
|           </p> | ||||
|           <p v-else> | ||||
|             {{ parseText(skill.description) }}... <a @click="changeMoreStatus(skill)">Więcej</a> | ||||
|           <p | ||||
|             v-else | ||||
|             class="text-sm" | ||||
|           > | ||||
|             {{ parseText(skill.description) }}... | ||||
|             <a | ||||
|               class="text-neutral-500 hover:text-neutral-700 hover:underline cursor-pointer" | ||||
|               @click="changeMoreStatus(skill)" | ||||
|             >Więcej</a> | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
| @@ -160,74 +174,7 @@ function changeMoreStatus(skill) { | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "scss/media"; | ||||
|  | ||||
| .experiences { | ||||
|   .container { | ||||
|     padding-top: 45px; | ||||
|     padding-bottom: 45px; | ||||
|  | ||||
|     .skills { | ||||
|       display: grid; | ||||
|       grid-template-columns: repeat(4, 1fr); | ||||
|       column-gap: 20px; | ||||
|       row-gap: 20px; | ||||
|       margin-top: 15px; | ||||
|  | ||||
|       .skill-group { | ||||
|         background-color: #fafafa; | ||||
|         padding: 15px; | ||||
|         border-radius: 5px; | ||||
|  | ||||
|         .tech-icons { | ||||
|           font-size: 1.8em; | ||||
|           margin-bottom: 3px; | ||||
|  | ||||
|           & > svg[class*='icon'] { | ||||
|             margin-right: 10px; | ||||
|  | ||||
|             &:last-child { | ||||
|               margin-right: 0; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         h3 { | ||||
|           font-size: 1.2em; | ||||
|           line-height: 1.6em; | ||||
|           font-weight: bold; | ||||
|         } | ||||
|         .skill-list { | ||||
|           margin-block: auto; | ||||
|           padding-inline: inherit; | ||||
|           margin-left: 5px; | ||||
|           list-style-type: initial; | ||||
|         } | ||||
|         p { | ||||
|           font-size: .9em; | ||||
|  | ||||
|           a { | ||||
|             color: #8D8D8D; | ||||
|             cursor: pointer; | ||||
|           } | ||||
|         } | ||||
|         &:hover { | ||||
|           background-color: rgba(0, 0, 0, .03); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       @include media-small { | ||||
|         grid-template-columns: repeat(3, 1fr); | ||||
|       } | ||||
|       @include media-tablet { | ||||
|         grid-template-columns: repeat(2, 1fr); | ||||
|       } | ||||
|       @include media-mobile { | ||||
|         grid-template-columns: repeat(1, 1fr); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| <style scoped> | ||||
| .icon-js { | ||||
|   color: #F1DE4F; | ||||
| } | ||||
|   | ||||
| @@ -1,13 +1,20 @@ | ||||
| <template> | ||||
|   <section class="selected-projects"> | ||||
|   <section class="bg-neutral-50"> | ||||
|     <projects :projects="select_projects"> | ||||
|       <div class="header-container"> | ||||
|         <h2>Wybrane projekty</h2> | ||||
|         <p>Poniżej przedstawiam Państwu, wybraną przeze mnie, listę projektów.</p> | ||||
|       </div> | ||||
|       <header> | ||||
|         <h2 class="text-[2rem] mb-2"> | ||||
|           Wybrane projekty | ||||
|         </h2> | ||||
|         <p class="mb-5"> | ||||
|           Poniżej przedstawiam Państwu, wybraną przeze mnie, listę projektów. | ||||
|         </p> | ||||
|       </header> | ||||
|     </projects> | ||||
|     <div class="more-button"> | ||||
|       <GhostButton @click="router.push('projects')"> | ||||
|     <div class="w-full -translate-y-5 pb-5 more-button"> | ||||
|       <GhostButton | ||||
|         class="mx-auto" | ||||
|         @click="router.push('projects')" | ||||
|       > | ||||
|         ZOBACZ WIĘCEJ | ||||
|       </GhostButton> | ||||
|     </div> | ||||
| @@ -17,8 +24,8 @@ | ||||
| <script setup> | ||||
| import { ref, onMounted } from 'vue' | ||||
| import { useRouter } from 'vue-router' | ||||
| import Projects from '../SelectedProjects' | ||||
| import GhostButton from '../buttons/GhostButton' | ||||
| import Projects from '@/components/SelectedProjects' | ||||
| import GhostButton from '@/components/buttons/GhostButton' | ||||
|  | ||||
| const router = useRouter() | ||||
|  | ||||
|   | ||||
| @@ -1,91 +1,99 @@ | ||||
| <template> | ||||
|   <div class="contact_container"> | ||||
|     <div | ||||
|       v-if="hasMessageError" | ||||
|       class="message message_error" | ||||
|     > | ||||
|       {{ messageError }} | ||||
|     </div> | ||||
|     <div | ||||
|       v-if="hasMessageOkStatus" | ||||
|       class="message message_ok" | ||||
|     > | ||||
|       {{ messageOk }} | ||||
|     </div> | ||||
|     <header class="container_head"> | ||||
|       Formularz kontaktowy: | ||||
|   <div | ||||
|     id="contact-form" | ||||
|     class="contact_container w-full bg-neutral-100 rounded-md border border-gray-200 md:max-w-[500px] p-2 shadow" | ||||
|   > | ||||
|     <header class="mb-1.5"> | ||||
|       <h3 class="text-xl"> | ||||
|         Formularz kontaktowy | ||||
|       </h3> | ||||
|     </header> | ||||
|     <form | ||||
|       id="form-point" | ||||
|       class="flex flex-col gap-3 justify-start items-start" | ||||
|       @submit="formSubmit" | ||||
|     > | ||||
|       <label | ||||
|         class="label-info" | ||||
|         :class="{ 'label-error': isEmailError }" | ||||
|         for="email" | ||||
|       <div | ||||
|         v-if="hasMessageError" | ||||
|         class="w-full p-2 bg-red-200 text-red-500 text-sm border border-red-300 rounded-md" | ||||
|       > | ||||
|         E-mail: | ||||
|       </label> | ||||
|       <input | ||||
|         id="email" | ||||
|         v-model="emailValue" | ||||
|         class="contact_input" | ||||
|         :class="{ 'contact_input-error': isEmailError }" | ||||
|         type="text" | ||||
|         name="email" | ||||
|         placeholder="przemek.kowalski@gmail.com" | ||||
|         {{ messageError }} | ||||
|       </div> | ||||
|       <div | ||||
|         v-else-if="hasMessageOkStatus" | ||||
|         class="w-full p-2 bg-[#27ae60] text-white text-sm border border-lime-600 rounded-md shadow" | ||||
|       > | ||||
|       <span | ||||
|         v-if="isEmailError" | ||||
|         class="error-message" | ||||
|       > | ||||
|         E-mail musi być poprawny, np. przemek.kowalski@gmail.com | ||||
|       </span> | ||||
|       <label | ||||
|         class="label-info" | ||||
|         :class="{ 'label-error': isMessageError }" | ||||
|         for="message" | ||||
|       > | ||||
|         Wiadomość: | ||||
|       </label> | ||||
|       <textarea | ||||
|         id="message" | ||||
|         v-model="messageValue" | ||||
|         class="contact_input" | ||||
|         :class="{ 'contact_input-error': isMessageError }" | ||||
|         name="message" | ||||
|         placeholder="Chciałbym zlecić wykonanie strony..." | ||||
|       /> | ||||
|       <span | ||||
|         v-if="isMessageError" | ||||
|         class="error-message" | ||||
|       > | ||||
|         Wiadomość musi zawierać przynajmniej 3 znaki! | ||||
|       </span> | ||||
|       <label | ||||
|         class="label-info" | ||||
|         :class="{ 'label-error': isSenderError }" | ||||
|         for="sender" | ||||
|       > | ||||
|         Podpis nadawcy: | ||||
|       </label> | ||||
|       <input | ||||
|         id="sender" | ||||
|         v-model="senderValue" | ||||
|         class="contact_input" | ||||
|         :class="{ 'contact_input-error': isSenderError }" | ||||
|         type="text" | ||||
|         name="sender" | ||||
|         placeholder="np. Przemek Kowalski" | ||||
|       > | ||||
|       <span | ||||
|         v-if="isSenderError" | ||||
|         class="error-message" | ||||
|       > | ||||
|         Podpis musi zawierać przynajmniej 3 znaki! | ||||
|       </span> | ||||
|         {{ messageOk }} | ||||
|       </div> | ||||
|       <div class="flex flex-col gap-1 w-full"> | ||||
|         <label | ||||
|           class="text-gray-500" | ||||
|           for="message" | ||||
|         > | ||||
|           W czym mogę pomóc? | ||||
|         </label> | ||||
|         <textarea | ||||
|           id="message" | ||||
|           v-model="messageValue" | ||||
|           class="w-full max-w-full min-h-[150px] px-2.5 py-2 border-b-2 border-neutral-300 rounded-md focus:border-neutral-400 hover:border-neutral-500 outline-none" | ||||
|           :class="[ isMessageError ? 'border-red-400 text-red-400 placeholder-red-300' : 'text-gray-900 placeholder-gray-400' ]" | ||||
|           name="message" | ||||
|           placeholder="Chciałbym zlecić wykonanie strony..." | ||||
|         /> | ||||
|         <span | ||||
|           v-if="isMessageError" | ||||
|           class="text-red-400" | ||||
|         > | ||||
|           Wiadomość musi zawierać przynajmniej 3 znaki! | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex flex-col gap-1 w-full"> | ||||
|         <label | ||||
|           class="text-gray-500" | ||||
|           for="email" | ||||
|         > | ||||
|           Gdzie mam odesłać odpowiedź? | ||||
|         </label> | ||||
|         <input | ||||
|           id="email" | ||||
|           v-model="emailValue" | ||||
|           class="w-full px-2.5 py-2 border-b-2 border-neutral-300 rounded-md focus:border-neutral-400 hover:border-neutral-500 outline-none" | ||||
|           :class="[ isEmailError ? 'border-red-400 text-red-400 placeholder-red-300' : 'text-gray-900 placeholder-gray-400' ]" | ||||
|           type="text" | ||||
|           name="email" | ||||
|           placeholder="Twój adres e-mail" | ||||
|         > | ||||
|         <span | ||||
|           v-if="isEmailError" | ||||
|           class="text-red-400" | ||||
|         > | ||||
|           E-mail musi być poprawny, np. przemek.kowalski@gmail.com | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex flex-col gap-1 w-full"> | ||||
|         <label | ||||
|           class="text-gray-500" | ||||
|           for="sender" | ||||
|         > | ||||
|           Podpis | ||||
|         </label> | ||||
|         <input | ||||
|           id="sender" | ||||
|           v-model="senderValue" | ||||
|           class="w-full px-2.5 py-2 border-b-2 border-neutral-300 rounded-md focus:border-neutral-400 hover:border-neutral-500 outline-none" | ||||
|           :class="[ isSenderError ? 'border-red-400 text-red-400 placeholder-red-300' : 'text-gray-900 placeholder-gray-400' ]" | ||||
|           type="text" | ||||
|           name="sender" | ||||
|         > | ||||
|         <span | ||||
|           v-if="isSenderError" | ||||
|           class="text-red-400" | ||||
|         > | ||||
|           Podpis musi zawierać przynajmniej 3 znaki! | ||||
|         </span> | ||||
|       </div> | ||||
|       <BaseButton | ||||
|         is-reverse | ||||
|         class="py-1 w-full" | ||||
|         :disabled="isButtonDisabled" | ||||
|       > | ||||
|         Wyślij | ||||
| @@ -95,7 +103,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import BaseButton from '../../buttons/BaseButton' | ||||
| import BaseButton from '@/components/buttons/BaseButton' | ||||
| import { ref, reactive, watch, computed } from 'vue' | ||||
|  | ||||
| function emailValidate (mailObj) { | ||||
| @@ -199,112 +207,21 @@ function formSubmit(event) { | ||||
|       buttonDisabled.value = false | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   scrollTo('#contact-form') | ||||
| } | ||||
|  | ||||
| function scrollTo(id) { | ||||
|   document.querySelector(id).scrollIntoView({ | ||||
|     behavior: 'smooth' | ||||
|   }) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "scss/media"; | ||||
|  | ||||
| .contact_container { | ||||
|   flex-basis: 500px; | ||||
|  | ||||
|   #form-point { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     align-items: center; | ||||
| @screen md { | ||||
|   .contact_container { | ||||
|     flex-basis: 500px; | ||||
|   } | ||||
|  | ||||
|   .btn { | ||||
|     width: 97%; | ||||
|     margin: 0 20px 5px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .container_head { | ||||
|   padding: 10px; | ||||
|   line-height: 1.6em; | ||||
|   font-size: 1.3em; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| .contact_container { | ||||
|   .label-info { | ||||
|     width: 97%; | ||||
|     padding-bottom: 5px; | ||||
|     color: #7a7a7a; | ||||
|   } | ||||
|  | ||||
|   .error-message { | ||||
|     width: 97%; | ||||
|     padding: 5px 0 10px; | ||||
|     color: #d44950; | ||||
|   } | ||||
|  | ||||
|   input, textarea { | ||||
|     width: 97%; | ||||
|     max-width: 97%; | ||||
|     border: 0; | ||||
|     border-bottom: 2px solid #c9c9c9; | ||||
|     padding: 10px 10px 8px; | ||||
|     font-size: 1em; | ||||
|     font-family: var(--font-family); | ||||
|     line-height: 1.3em; | ||||
|     margin-bottom: 15px; | ||||
|     border-radius: 5px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .contact_input::placeholder { | ||||
|   color: #bdbdbd; | ||||
| } | ||||
|  | ||||
| .contact_input:focus, .contact_input:focus { | ||||
|   outline: none; | ||||
|   border-color: black; | ||||
| } | ||||
|  | ||||
| textarea.contact_input { | ||||
|   max-width: 97%; | ||||
|   min-width: 97%; | ||||
|   min-height: 150px; | ||||
| } | ||||
|  | ||||
| input.contact_input-error, textarea.contact_input-error { | ||||
|   border-color: #d44950; | ||||
|   color: #d44950; | ||||
|   margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .contact_input-error::placeholder, .contact_input-error::placeholder { | ||||
|   color: #d7626a; | ||||
| } | ||||
|  | ||||
| input[disabled].contact_input { | ||||
|   background-color: #cdcdcd; | ||||
|   border-color: gray; | ||||
|   color: black; | ||||
| } | ||||
|  | ||||
| .message { | ||||
|   display: none; | ||||
|   margin: 5px; | ||||
|   padding: 8px; | ||||
|   border-radius: 5px; | ||||
| } | ||||
|  | ||||
| .message_ok, .message_error { | ||||
|   display: block; | ||||
| } | ||||
|  | ||||
| .message_ok { | ||||
|   background-color: #4CAF50; | ||||
|   border: 1px solid #387d3b; | ||||
|   color: white; | ||||
| } | ||||
|  | ||||
| .message_error { | ||||
|   background-color: #f8d7da; | ||||
|   border: 1px solid #f5c6cb; | ||||
|   color: #721c24; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,82 +1,92 @@ | ||||
| <template> | ||||
|   <div class="contact_info"> | ||||
|     <header class="info_head"> | ||||
|       Inne formy kontaktu: | ||||
|   <div class="contact_info w-full bg-neutral-100 rounded-md border border-gray-200 md:max-w-[410px] p-2 shadow"> | ||||
|     <header class="mb-1.5"> | ||||
|       <h3 class="text-xl"> | ||||
|         Inne formy kontaktu: | ||||
|       </h3> | ||||
|     </header> | ||||
|     <div class="contact_element"> | ||||
|       <img | ||||
|         class="contact_element_icon" | ||||
|         src="/assets/img/instagram.jpg" | ||||
|         alt="Instagram" | ||||
|       > | ||||
|       <span | ||||
|         id="instagram" | ||||
|         class="contact_element_text" | ||||
|       > | ||||
|         <a | ||||
|           href="https://www.instagram.com/nikcamii/" | ||||
|           target="_blank" | ||||
|           rel="noopener nofollow noreferrer" | ||||
|         >Instagram: @NiKCamii</a> | ||||
|       </span> | ||||
|     </div> | ||||
|     <div class="contact_element"> | ||||
|       <img | ||||
|         class="contact_element_icon" | ||||
|         src="/assets/img/facebook.jpg" | ||||
|         alt="Facebook" | ||||
|       > | ||||
|       <span | ||||
|         id="facebook" | ||||
|         class="contact_element_text" | ||||
|       > | ||||
|         <a | ||||
|           href="https://www.facebook.com/nikcamii/" | ||||
|           target="_blank" | ||||
|           rel="noopener nofollow noreferrer" | ||||
|         >Facebook: @NiKCamii</a> | ||||
|       </span> | ||||
|     </div> | ||||
|     <div class="contact_element"> | ||||
|       <img | ||||
|         class="contact_element_icon" | ||||
|         src="/assets/img/twitter.jpg" | ||||
|         alt="Twitter" | ||||
|       > | ||||
|       <span | ||||
|         id="twitter" | ||||
|         class="contact_element_text" | ||||
|       > | ||||
|         <a | ||||
|           href="https://twitter.com/nikcamii" | ||||
|           target="_blank" | ||||
|           rel="noopener nofollow noreferrer" | ||||
|         >Twitter: @NiKCamii</a> | ||||
|       </span> | ||||
|     </div> | ||||
|     <div class="contact_element"> | ||||
|       <img | ||||
|         class="contact_element_icon" | ||||
|         src="/assets/img/gg.png" | ||||
|         alt="Gadu-Gadu" | ||||
|       > | ||||
|       <span | ||||
|         id="gg" | ||||
|         class="contact_element_text" | ||||
|       >GG: 38429969</span> | ||||
|     </div> | ||||
|     <div class="contact_element"> | ||||
|       <img | ||||
|         class="contact_element_icon" | ||||
|         src="/assets/img/user.jpg" | ||||
|         alt="E-mail" | ||||
|       > | ||||
|       <span | ||||
|         id="mailto" | ||||
|         class="contact_element_text" | ||||
|       > | ||||
|         <a href="mailto:contact@kamilcraft.com">Email: contact@kamilcraft.com</a> | ||||
|       </span> | ||||
|     <div class="flex flex-col gap-2.5 justify-start items-start"> | ||||
|       <div class="flex items-center gap-2 w-full rounded-md p-1.5 border border-neutral-200 bg-white"> | ||||
|         <img | ||||
|           class="rounded-full w-12 h-12 object-contain border border-neutral-200" | ||||
|           src="/assets/img/instagram.jpg" | ||||
|           alt="Instagram" | ||||
|         > | ||||
|         <span | ||||
|           id="instagram" | ||||
|           class="font-bold" | ||||
|         > | ||||
|           <a | ||||
|             href="https://www.instagram.com/nikcamii/" | ||||
|             target="_blank" | ||||
|             rel="noopener nofollow noreferrer" | ||||
|             class="hover:underline" | ||||
|           >Instagram: @NiKCamii</a> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center gap-2 w-full rounded-md p-1.5 border border-neutral-200 bg-white"> | ||||
|         <img | ||||
|           class="rounded-full w-12 h-12 object-contain border border-neutral-200" | ||||
|           src="/assets/img/facebook.jpg" | ||||
|           alt="Facebook" | ||||
|         > | ||||
|         <span | ||||
|           id="facebook" | ||||
|           class="font-bold" | ||||
|         > | ||||
|           <a | ||||
|             href="https://www.facebook.com/nikcamii/" | ||||
|             target="_blank" | ||||
|             rel="noopener nofollow noreferrer" | ||||
|             class="hover:text-gray-700 hover:underline" | ||||
|           >Facebook: @NiKCamii</a> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center gap-2 w-full rounded-md p-1.5 border border-neutral-200 bg-white"> | ||||
|         <img | ||||
|           class="rounded-full w-12 h-12 object-contain border border-neutral-200" | ||||
|           src="/assets/img/twitter.jpg" | ||||
|           alt="Twitter" | ||||
|         > | ||||
|         <span | ||||
|           id="twitter" | ||||
|           class="font-bold" | ||||
|         > | ||||
|           <a | ||||
|             href="https://twitter.com/nikcamii" | ||||
|             target="_blank" | ||||
|             rel="noopener nofollow noreferrer" | ||||
|             class="hover:text-gray-700 hover:underline" | ||||
|           >Twitter: @NiKCamii</a> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center gap-2 w-full rounded-md p-1.5 border border-neutral-200 bg-white"> | ||||
|         <img | ||||
|           class="rounded-full w-12 h-12 object-contain border border-neutral-200" | ||||
|           src="/assets/img/gg.png" | ||||
|           alt="Gadu-Gadu" | ||||
|         > | ||||
|         <span | ||||
|           id="gg" | ||||
|           class="font-bold" | ||||
|         >GG: 38429969</span> | ||||
|       </div> | ||||
|       <div class="flex items-center gap-2 w-full rounded-md p-1.5 border border-neutral-200 bg-white"> | ||||
|         <img | ||||
|           class="rounded-full w-12 h-12 object-contain border border-neutral-200" | ||||
|           src="/assets/img/user.jpg" | ||||
|           alt="E-mail" | ||||
|         > | ||||
|         <span | ||||
|           id="mailto" | ||||
|           class="font-bold" | ||||
|         > | ||||
|           <a | ||||
|             href="mailto:contact@kamilcraft.com" | ||||
|             class="hover:text-gray-700 hover:underline" | ||||
|           >Email: contact@kamilcraft.com</a> | ||||
|         </span> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| @@ -84,51 +94,18 @@ | ||||
| <style lang="scss" scoped> | ||||
| @import "scss/media"; | ||||
|  | ||||
| .contact_info { | ||||
|   flex-basis: 410px; | ||||
| @screen md { | ||||
|   .contact_info { | ||||
|     flex-basis: 410px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .info_head { | ||||
|   padding: 10px; | ||||
|   line-height: 1.6em; | ||||
|   font-size: 1.3em; | ||||
|   font-weight: bold; | ||||
| } | ||||
| a { | ||||
|   color: inherit; | ||||
|  | ||||
| .contact_element { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   padding: 5px; | ||||
|   background-color: #fff; | ||||
|   border-top: 1px solid #e6e6e6; | ||||
|   border-bottom: 1px solid #e6e6e6; | ||||
|   margin-bottom: 5px; | ||||
|  | ||||
|   a { | ||||
|     color: inherit; | ||||
|     text-decoration: none; | ||||
|  | ||||
|     &:hover { | ||||
|       -webkit-text-fill-color: #444444; | ||||
|       color: #444444; | ||||
|       text-decoration: underline; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &_icon { | ||||
|     border-radius: 50%; | ||||
|     border: 1px solid #e2e2e2; | ||||
|     width: 50px; | ||||
|     height: 50px; | ||||
|     margin-right: 10px; | ||||
|     object-fit: contain; | ||||
|   } | ||||
|  | ||||
|   &_text{ | ||||
|     padding-top: 2px; | ||||
|     line-height: 1.6em; | ||||
|     font-size: 1.1em; | ||||
|     font-weight: bold; | ||||
|   &:hover { | ||||
|     -webkit-text-fill-color: #374151; | ||||
|     color: #374151; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -153,11 +130,4 @@ | ||||
| #gg { | ||||
|   color: #ffa214; | ||||
| } | ||||
|  | ||||
| @include media-tablet { | ||||
|   #instagram, #facebook, #twitter, #mailto, #gg { | ||||
|     font-size: 1em; | ||||
|     line-height: 1.2em; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { createApp } from 'vue' | ||||
| import App from './App.vue' | ||||
| import router from './router' | ||||
| import { store } from './store' | ||||
| import App from '@/App.vue' | ||||
| import router from '@/router' | ||||
| import { store } from '@/store' | ||||
| // import VueMeta from 'vue-meta' | ||||
|  | ||||
| import '../scss/default.scss' | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import { createRouter, createWebHistory } from 'vue-router' | ||||
| import Home from '../views/HomeView' | ||||
| import About from '../views/AboutView' | ||||
| import Projects from '../views/ProjectsView' | ||||
| import Project from '../views/ProjectView' | ||||
| import Contact from '../views/ContactView' | ||||
| import NotFound from '../views/NotFound' | ||||
| import Home from '@/views/HomeView' | ||||
| import About from '@/views/AboutView' | ||||
| import Projects from '@/views/ProjectsView' | ||||
| import Project from '@/views/ProjectView' | ||||
| import Contact from '@/views/ContactView' | ||||
| import NotFound from '@/views/NotFound' | ||||
|  | ||||
| const mainTitle = 'kamilcraft.com' | ||||
|  | ||||
| @@ -77,21 +77,6 @@ const router = createRouter({ | ||||
|       return { left: 0, top: 0 } | ||||
|     } | ||||
|   } | ||||
|   /*scrollBehavior (to, from, savedPosition) { | ||||
|     if (savedPosition) { | ||||
|       return savedPosition | ||||
|     } else if (to.hash) { | ||||
|       return new Promise(resolve => { | ||||
|         setTimeout(() => { | ||||
|           resolve({ | ||||
|             selector: to.hash | ||||
|           }, 1000) | ||||
|         }) | ||||
|       }) | ||||
|     } else { | ||||
|       return { x: 0, y: 0 } | ||||
|     } | ||||
|   }*/ | ||||
| }) | ||||
|  | ||||
| const title = ' :: ' + mainTitle | ||||
|   | ||||
| @@ -1,39 +1,45 @@ | ||||
| <template> | ||||
|   <section id="about"> | ||||
|     <div class="container"> | ||||
|       <p> | ||||
|         <strong>Nazywam się Kamil Niemczycki. Jestem młodym i ambitnym inżynierem oprogramowania. Specjalizuję się w tworzeniu frontendów i backendów. | ||||
|           W projektach wykorzystuję techologie oparte o PHP i JavaScript, tworząc skomplikowane i skalowalne aplikacje internetowe.</strong> | ||||
|       </p> | ||||
|       <h2>Studia</h2> | ||||
|       <p> | ||||
|         Jestem absolwentem Państwowej Wyższej Szkoły Zawodowej im. Witelona w Legnicy. Studiowałem na kierunku <em>Informatyka</em> o specjalności <em>Programowanie Aplikacji Mobilnych i Internetowych.</em> | ||||
|       </p> | ||||
|       <p> | ||||
|         Podczas studiów zdobyłem niezbędną wiedzę z zakresu projektowania, wdrażania i rozwoju aplikacji internetowych, mobilnych i desktopowych. | ||||
|         Zdobyłem także umiejętności pracy w zespole, które owocują tworzeniem merytorycznej dyskusji na temat części lub całości projektu. | ||||
|       </p> | ||||
|       <h3>Kursy</h3> | ||||
|       <p> | ||||
|         W ramach studiów uzyskałem zaświadczenie dotyczące ukończenia kursu: | ||||
|         <strong><a | ||||
|           :href="publicPath + 'download/certyfikat-laravel.pdf'" | ||||
|           target="_blank" | ||||
|           rel="noopener nofollow noreferrer" | ||||
|         > | ||||
|           Architektura aplikacji internetowych opartych o framework Laravel</a></strong>. | ||||
|       </p> | ||||
|       <p> | ||||
|         Umożliwiło mi to szersze spojrzenie na możliwości jakie daje nam Laravel i wzbogaconie poprzednio zdobytej | ||||
|         wiedzy o nowe doświadczenia. | ||||
|       </p> | ||||
|       <h2>Moje zainteresowania</h2> | ||||
|       <p> | ||||
|         W wolnym czasie przyjmuje małe zlecenia na strony lub serwisy internetowe. Uczę się nowych języków | ||||
|         programowania lub frameworków w znanych mi już technologiach. Hobbistycznie, tworzę także rozwiązania do | ||||
|         problemów przy prywatnych projektach. | ||||
|       </p> | ||||
|     </div> | ||||
|   <section class="max-w-screen-xl mx-auto px-6 xl:px-2 py-11"> | ||||
|     <p class="font-bold"> | ||||
|       Nazywam się Kamil Niemczycki. Jestem młodym i ambitnym inżynierem oprogramowania. Specjalizuję się w tworzeniu frontendów i backendów. | ||||
|       W projektach wykorzystuję techologie oparte o PHP i JavaScript, tworząc skomplikowane i skalowalne aplikacje internetowe. | ||||
|     </p> | ||||
|     <h2 class="text-[2rem]"> | ||||
|       Studia | ||||
|     </h2> | ||||
|     <p> | ||||
|       Jestem absolwentem Państwowej Wyższej Szkoły Zawodowej im. Witelona w Legnicy. Studiowałem na kierunku <em>Informatyka</em> o specjalności <em>Programowanie Aplikacji Mobilnych i Internetowych.</em> | ||||
|     </p> | ||||
|     <p> | ||||
|       Podczas studiów zdobyłem niezbędną wiedzę z zakresu projektowania, wdrażania i rozwoju aplikacji internetowych, mobilnych i desktopowych. | ||||
|       Zdobyłem także umiejętności pracy w zespole, które owocują tworzeniem merytorycznej dyskusji na temat części lub całości projektu. | ||||
|     </p> | ||||
|     <h3 class="text-[1.5rem]"> | ||||
|       Kursy | ||||
|     </h3> | ||||
|     <p> | ||||
|       W ramach studiów uzyskałem zaświadczenie dotyczące ukończenia kursu: | ||||
|       <a | ||||
|         :href="publicPath + 'download/certyfikat-laravel.pdf'" | ||||
|         class="text-gray-500 underline hover:text-kamilcraft-green hover:no-underline" | ||||
|         target="_blank" | ||||
|         rel="noopener nofollow noreferrer" | ||||
|       > | ||||
|         Architektura aplikacji internetowych opartych o framework Laravel | ||||
|       </a>. | ||||
|     </p> | ||||
|     <p> | ||||
|       Umożliwiło mi to szersze spojrzenie na możliwości jakie daje nam Laravel i wzbogaconie poprzednio zdobytej | ||||
|       wiedzy o nowe doświadczenia. | ||||
|     </p> | ||||
|     <h2 class="text-[2rem]"> | ||||
|       Moje zainteresowania | ||||
|     </h2> | ||||
|     <p> | ||||
|       W wolnym czasie przyjmuje małe zlecenia na strony lub serwisy internetowe. Uczę się nowych języków | ||||
|       programowania lub frameworków w znanych mi już technologiach. Hobbistycznie, tworzę także rozwiązania do | ||||
|       problemów przy prywatnych projektach. | ||||
|     </p> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| @@ -60,32 +66,3 @@ onUnmounted(() => { | ||||
|   store.commit('resetHeaderDescription') | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| section#about { | ||||
|   padding: 45px 0; | ||||
|   background-color: #fafafa !important; | ||||
|  | ||||
|   h2 { | ||||
|     margin-top: 25px; | ||||
|  | ||||
|     &:first-of-type { | ||||
|       margin-top: 10px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   h3 { | ||||
|     font-size: 1.3em; | ||||
|     margin-top: 8px; | ||||
|     margin-bottom: 10px; | ||||
|   } | ||||
|  | ||||
|   a { | ||||
|     color: #8D8D8D; | ||||
|  | ||||
|     &:hover { | ||||
|       color: #A2CF00; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,9 +1,7 @@ | ||||
| <template> | ||||
|   <section class="contact"> | ||||
|     <div class="container"> | ||||
|       <MailContact /> | ||||
|       <OtherContact /> | ||||
|     </div> | ||||
|   <section class="flex flex-col px-3 py-6 md:flex-row items-start justify-center mx-auto gap-5"> | ||||
|     <MailContact /> | ||||
|     <OtherContact /> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| @@ -11,8 +9,8 @@ | ||||
| import { onMounted } from 'vue' | ||||
| import { useRoute } from 'vue-router' | ||||
| import { useStore } from 'vuex' | ||||
| import MailContact from '../components/sections/contacts/MailContact' | ||||
| import OtherContact from '../components/sections/contacts/OtherContact' | ||||
| import MailContact from '@/components/sections/contacts/MailContact' | ||||
| import OtherContact from '@/components/sections/contacts/OtherContact' | ||||
|  | ||||
| const route = useRoute() | ||||
| const store = useStore() | ||||
| @@ -25,49 +23,3 @@ onMounted(() => { | ||||
|   store.commit('setHeader', header) | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "scss/media"; | ||||
|  | ||||
| .contact { | ||||
|   padding: 25px 0; | ||||
|  | ||||
|   .container { | ||||
|     display: flex; | ||||
|     align-items: flex-start; | ||||
|     justify-content: center; | ||||
|   } | ||||
|  | ||||
|   .contact_container, .contact_info { | ||||
|     margin: 10px; | ||||
|     max-width: 500px; | ||||
|     background-color: #eaeaea; | ||||
|     border: 2px solid #dadada; | ||||
|     border-radius: 2px; | ||||
|     box-shadow: 0 0 5px rgba(0, 0, 0, .2); | ||||
|   } | ||||
|  | ||||
|   @include media-tablet { | ||||
|     .container { | ||||
|       display: block; | ||||
|       margin: 0 auto; | ||||
|  | ||||
|       .contact_container, .contact_info { | ||||
|         margin: 0 auto 25px; | ||||
|         &:last-child { | ||||
|           margin-bottom: 0; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   @include media-mobile { | ||||
|     .container { | ||||
|       padding: 0 10px; | ||||
|  | ||||
|       .contact_container { | ||||
|         max-width: unset; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -10,9 +10,9 @@ | ||||
| import { onMounted, onUnmounted } from 'vue' | ||||
| import { useStore } from 'vuex' | ||||
| import { useRoute } from 'vue-router' | ||||
| import About from '../components/sections/AboutSection' | ||||
| import ExperiencesSection from '../components/sections/ExperiencesSection' | ||||
| import FavoriteProjects from '../components/sections/FavoriteProjects' | ||||
| import About from '@/components/sections/AboutSection' | ||||
| import ExperiencesSection from '@/components/sections/ExperiencesSection' | ||||
| import FavoriteProjects from '@/components/sections/FavoriteProjects' | ||||
|  | ||||
| const store = useStore() | ||||
| const route = useRoute() | ||||
|   | ||||
| @@ -1,74 +1,78 @@ | ||||
| <template> | ||||
|   <section | ||||
|     v-if="isLoaded" | ||||
|     class="project" | ||||
|     class="max-w-screen-xl mx-auto px-6 xl:px-2 py-8" | ||||
|   > | ||||
|     <header class="project_header"> | ||||
|       <h1>{{ project.title }}</h1> | ||||
|       <ul class="project_info"> | ||||
|         <li class="info_text"> | ||||
|           <font-awesome-icon | ||||
|             class="icon" | ||||
|     <header class="text-neutral-800 font-roboto"> | ||||
|       <h1 class="text-center text-4xl font-light pb-5"> | ||||
|         {{ project.title }} | ||||
|       </h1> | ||||
|       <ul class="grid grid-cols-2 gap-3 md:flex md:gap-5 justify-center list-none"> | ||||
|         <li class="flex items-center gap-2"> | ||||
|           <FontAwesomeIcon | ||||
|             class="w-4" | ||||
|             :icon="['far', 'clock']" | ||||
|           /> | ||||
|           <span>{{ project.release_date }}</span> | ||||
|         </li> | ||||
|         <li class="info_text"> | ||||
|           <font-awesome-icon | ||||
|             class="icon" | ||||
|         <li class="flex items-center gap-2"> | ||||
|           <FontAwesomeIcon | ||||
|             class="w-4" | ||||
|             :icon="['far', 'user']" | ||||
|           /> | ||||
|           <span>{{ project.author }}</span> | ||||
|         </li> | ||||
|         <li class="info_text"> | ||||
|           <font-awesome-icon | ||||
|             class="icon" | ||||
|         <li class="flex items-center gap-2"> | ||||
|           <FontAwesomeIcon | ||||
|             class="w-4" | ||||
|             :icon="['far', 'folder']" | ||||
|           /> | ||||
|           <span>{{ getCategoryName(project.categories) }}</span> | ||||
|         </li> | ||||
|         <li class="info_text"> | ||||
|           <font-awesome-icon | ||||
|             class="icon" | ||||
|         <li class="flex items-center gap-2"> | ||||
|           <FontAwesomeIcon | ||||
|             class="w-4" | ||||
|             :icon="['fas', 'code-branch']" | ||||
|           /> | ||||
|           <span>{{ project.project_version }}</span> | ||||
|         </li> | ||||
|         <li | ||||
|           v-if="project.project_url" | ||||
|           class="info_text" | ||||
|           class="flex items-center gap-2" | ||||
|         > | ||||
|           <font-awesome-icon | ||||
|             class="icon" | ||||
|           <FontAwesomeIcon | ||||
|             class="w-4" | ||||
|             :icon="['fas', 'link']" | ||||
|           /> | ||||
|           <span><a | ||||
|             :href="project.project_url" | ||||
|             target="_blank" | ||||
|             rel="noopener nofollow noreferrer" | ||||
|           >Link</a></span> | ||||
|           <span> | ||||
|             <a | ||||
|               :href="project.project_url" | ||||
|               target="_blank" | ||||
|               rel="noopener nofollow noreferrer" | ||||
|             > | ||||
|               Link | ||||
|             </a> | ||||
|           </span> | ||||
|         </li> | ||||
|       </ul> | ||||
|     </header> | ||||
|     <div class="container"> | ||||
|       <component | ||||
|         :is="`figure`" | ||||
|         class="project-photo" | ||||
|       > | ||||
|     <div class="pt-5"> | ||||
|       <figure class="w-full shadow-xl"> | ||||
|         <img | ||||
|           :src="`${project.images.large}`" | ||||
|           class="block max-h-[31.25rem] object-cover" | ||||
|           :src="project.images.large" | ||||
|           :alt="project.title" | ||||
|         > | ||||
|       </component> | ||||
|       </figure> | ||||
|       <div | ||||
|         class="content" | ||||
|         class="markdown mt-9" | ||||
|         v-html="markdownToHtml" | ||||
|       /> | ||||
|     </div> | ||||
|   </section> | ||||
|   <div | ||||
|     v-else | ||||
|     class="loading" | ||||
|     class="flex items-center" | ||||
|   > | ||||
|     <div class="loading_animation" /> | ||||
|   </div> | ||||
| @@ -127,143 +131,57 @@ function loadProject(id) { | ||||
| <style lang="scss"> | ||||
| @import "scss/default"; | ||||
|  | ||||
| .loading { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
| a { | ||||
|   @apply text-neutral-800 hover:text-kamilcraft-green; | ||||
| } | ||||
|  | ||||
| .project { | ||||
|   .project_header { | ||||
|     @extend .container; | ||||
|     text-align: center; | ||||
|     margin-bottom: 25px; | ||||
| .markdown { | ||||
|   h1 { | ||||
|     @apply text-4xl; | ||||
|   } | ||||
|  | ||||
|     h1 { | ||||
|       font-size: 2.2em; | ||||
|       font-weight: lighter; | ||||
|       line-height: 2.4em; | ||||
|     } | ||||
|   h2 { | ||||
|     @apply text-[2rem]; | ||||
|   } | ||||
|  | ||||
|     .project_info { | ||||
|       display: flex; | ||||
|       list-style: none; | ||||
|       justify-content: center; | ||||
|   h3 { | ||||
|     @apply text-[1.5rem]; | ||||
|   } | ||||
|  | ||||
|       .info_text { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|   p, ol li, ul li { | ||||
|     @apply text-lg; | ||||
|   } | ||||
|  | ||||
|         .icon { | ||||
|           width: 2em; | ||||
|         } | ||||
|   p + ol, p + ul, p + blockquote { | ||||
|     @apply -mb-2.5; | ||||
|   } | ||||
|  | ||||
|         span { | ||||
|           font-weight: lighter; | ||||
|           white-space: nowrap; | ||||
|         } | ||||
|   ol { | ||||
|     @apply list-decimal; | ||||
|   } | ||||
|  | ||||
|         &:not(&:last-child) { | ||||
|           margin-right: 15px; | ||||
|         } | ||||
|       } | ||||
|       @include media-tablet { | ||||
|         display: grid; | ||||
|         grid-template-columns: repeat(2, 1fr); | ||||
|         row-gap: 15px; | ||||
|   ul { | ||||
|     @apply list-disc; | ||||
|   } | ||||
|  | ||||
|         .info-text { | ||||
|           &:not(&:last-child) { | ||||
|             margin-right: 0; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|   ol, ul { | ||||
|     @apply mb-2.5; | ||||
|     padding-inline-start: 1.75rem; | ||||
|  | ||||
|     li img { | ||||
|       @apply block w-full pr-1 pb-1 mt-3.5; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .container { | ||||
|     .project-photo { | ||||
|       box-shadow: 5px 5px 10px rgba(0, 0, 0, .3); | ||||
|     } | ||||
|   p { | ||||
|     @apply mb-2.5 text-justify; | ||||
|   } | ||||
|  | ||||
|     .project-photo, .project-photo img { | ||||
|       width: 100%; | ||||
|     } | ||||
|   blockquote { | ||||
|     @apply pl-6 ml-5 border-neutral-400; | ||||
|  | ||||
|     .project-photo img { | ||||
|       display: block; | ||||
|       object-fit: cover; | ||||
|       max-height: 500px; | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|       margin: 35px 0; | ||||
|  | ||||
|       a { | ||||
|         color: #8D8D8D; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #A2CF00; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       h2, h3 { | ||||
|         margin-top: 15px; | ||||
|         margin-bottom: 5px; | ||||
|       } | ||||
|  | ||||
|       h2:first-of-type { | ||||
|         margin-top: 0; | ||||
|       } | ||||
|  | ||||
|       h2 { | ||||
|         font-size: 1.6em; | ||||
|       } | ||||
|  | ||||
|       h3 { | ||||
|         font-size: 1.4em; | ||||
|       } | ||||
|  | ||||
|       p, ol li, ul li { | ||||
|         line-height: 1.8em; | ||||
|         font-size: 1.1em; | ||||
|  | ||||
|         @include media-tablet { | ||||
|           font-size: 1.2em; | ||||
|           line-height: 1.5em; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       p + ol, p + ul, p + blockquote { | ||||
|         margin-top: -10px; | ||||
|       } | ||||
|  | ||||
|       ol, ul { | ||||
|         margin-bottom: 10px; | ||||
|         padding-inline-start: 2.1em; | ||||
|  | ||||
|         li img { | ||||
|           display: block; | ||||
|           width: 100%; | ||||
|           padding: 0 5px 5px; | ||||
|           margin-top: .9em; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       p { | ||||
|         margin-bottom: 10px; | ||||
|         text-align: justify; | ||||
|         /* text-indent: 1.5em; */ | ||||
|       } | ||||
|  | ||||
|       blockquote { | ||||
|         padding-left: 25px; | ||||
|         margin-left: 1.3em; | ||||
|         border-left: 1px solid rgb(116, 116, 116); | ||||
|  | ||||
|         p { | ||||
|           text-indent: unset; | ||||
|         } | ||||
|       } | ||||
|     p { | ||||
|       text-indent: unset; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,38 +1,38 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div class="project_categories"> | ||||
|       <ul class="categories"> | ||||
|   <SelectedProjects :projects="projects"> | ||||
|     <div class="pb-9"> | ||||
|       <ul class="flex justify-center list-none"> | ||||
|         <li | ||||
|           v-for="category in getCategories" | ||||
|           :key="category.slug" | ||||
|           class="categories_element" | ||||
|           :class="{ 'categories_element-active': categories.active === category.slug }" | ||||
|           class="relative cursor-pointer mr-3 md:mr-5 last:mr-0 after:translate-y-2" | ||||
|           :class="{ 'category-active': selectedCategory(category.slug) }" | ||||
|           @click="changeCategory(category.slug)" | ||||
|         > | ||||
|           <a :title="`Kategoria ${category.name}`">{{ category.name }}</a> | ||||
|           <a | ||||
|             class="text-gray-500 hover:text-black" | ||||
|             :title="`Kategoria ${category.name}`" | ||||
|           >{{ category.name }}</a> | ||||
|         </li> | ||||
|       </ul> | ||||
|     </div> | ||||
|     <SelectedProjects :projects="projects" /> | ||||
|     <div | ||||
|       v-if="projects.length === 0" | ||||
|       class="loading" | ||||
|     > | ||||
|       <div class="loading_animation" /> | ||||
|     </div> | ||||
|   </SelectedProjects> | ||||
|   <div | ||||
|     v-if="projects.length === 0" | ||||
|     class="loading" | ||||
|   > | ||||
|     <div class="loading_animation" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { reactive, computed, onMounted, onUnmounted } from 'vue' | ||||
| import { ref, reactive, computed, onMounted, onUnmounted } from 'vue' | ||||
| import { useStore } from 'vuex' | ||||
| import SelectedProjects from '../components/SelectedProjects' | ||||
| import SelectedProjects from '@/components/SelectedProjects' | ||||
|  | ||||
| const store = useStore() | ||||
|  | ||||
| const categories = reactive({ | ||||
|   active: 'all' | ||||
| }) | ||||
| const activeCategory = ref('all') | ||||
| const projects = reactive([]) | ||||
|  | ||||
| const getCategories = computed(() => store.getters.getCategories) | ||||
| @@ -72,64 +72,22 @@ function loadListWhereCategory(category) { | ||||
| } | ||||
|  | ||||
| function changeCategory(category) { | ||||
|   categories.active = category | ||||
|   activeCategory.value = category | ||||
|   loadListWhereCategory(category) | ||||
| } | ||||
|  | ||||
| function selectedCategory(categorySlug) { | ||||
|   return activeCategory.value === categorySlug | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "scss/media"; | ||||
|  | ||||
| .project_categories { | ||||
|   padding-top: 45px; | ||||
|  | ||||
|   .categories { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     list-style: none; | ||||
|  | ||||
|     .categories_element { | ||||
|       position: relative; | ||||
|       cursor: pointer; | ||||
|       margin-right: 25px; | ||||
|  | ||||
|       a { | ||||
|         color: var(--text-color); | ||||
|         &:hover { | ||||
|           color: black; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|  | ||||
|       &-active { | ||||
|         &::after { | ||||
|           content: ''; | ||||
|           position: absolute; | ||||
|           margin: 0 auto; | ||||
|           left: 0; | ||||
|           right: 0; | ||||
|           bottom: 0; | ||||
|           width: 0; | ||||
|           height: 2px; | ||||
|           background-color: #A2CF00; | ||||
|           transform: translateY(8px); | ||||
|           animation: load-underline 300ms forwards; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       @include media-mobile { | ||||
|         margin-right: 15px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .projects { | ||||
|   padding-top: 25px; | ||||
|   padding-bottom: 25px; | ||||
| .category-active::after { | ||||
|   @apply absolute mx-auto left-0 right-0 bottom-0 h-0.5; | ||||
|   background-color: #A2CF00; | ||||
|   animation: load-underline 300ms forwards; | ||||
| } | ||||
|  | ||||
| @keyframes loading-animation { | ||||
|   | ||||
| @@ -1,6 +1,14 @@ | ||||
| const path = require("path") | ||||
| const { defineConfig } = require('@vue/cli-service') | ||||
|  | ||||
| module.exports = defineConfig({ | ||||
|   publicPath: '/', | ||||
|   transpileDependencies: true | ||||
|   transpileDependencies: true, | ||||
|   configureWebpack: { | ||||
|     resolve: { | ||||
|       alias: { | ||||
|         '@': path.resolve(__dirname, 'src/'), | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user