Upgrade to vue 3 (#1)

* updated dependencies

* updated readme

* upgrade to vue 3

* updated buttons

* duplicate id removed

* updated contact
This commit is contained in:
2022-07-13 09:48:44 +02:00
committed by GitHub
parent 0bd0d31947
commit 7475bb5671
36 changed files with 9847 additions and 19845 deletions

View File

@@ -3,23 +3,40 @@
<div class="container">
<div id="grid">
<div id="grid-text">
<h2 class="name">Kamil Niemczycki</h2>
<div class="tagline">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>
<h2 class="name">
Kamil Niemczycki
</h2>
<div class="tagline">
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">
<base-btn has-icon
icon="portrait"
is-reverse
@click.native="scrollTo('.selected-projects')">Wybrane projekty</base-btn>
<base-btn has-icon
icon="user"
@click.native="$router.push('about')">Więcej o mnie</base-btn>
<BaseButton
has-icon
icon="portrait"
is-reverse
@click="scrollTo('.selected-projects')"
>
Wybrane projekty
</BaseButton>
<BaseButton
has-icon
icon="user"
@click="router.push('about')"
>
Więcej o mnie
</BaseButton>
</div>
</div>
<div id="grid-photo">
<figure id="about-photo">
<img :src="`${publicPath}assets/me.jpg`" />
<img
:src="`${publicPath}assets/me.jpg`"
alt="Moje zdjęcie"
>
</figure>
</div>
</div>
@@ -27,6 +44,20 @@
</div>
</template>
<script setup>
import BaseButton from '../buttons/BaseButton'
import { useRouter } from 'vue-router'
const router = useRouter()
const publicPath = process.env.VUE_APP_BASE_URL + '/'
function scrollTo(id) {
document.querySelector(id).scrollIntoView({
behavior: 'smooth'
})
}
</script>
<style lang="scss">
@import "scss/media";
@@ -122,24 +153,3 @@
}
}
</style>
<script>
import BaseButton from '../BaseButton'
export default {
data () {
return {
publicPath: process.env.VUE_APP_BASE_URL + '/'
}
},
methods: {
scrollTo (id) {
document.querySelector(id).scrollIntoView({
behavior: 'smooth'
})
}
},
components: {
'base-btn': BaseButton
}
}
</script>

View File

@@ -1,253 +0,0 @@
<template>
<div class="experiences">
<div class="container">
<h2>Wykorzystywane technologie</h2>
<p>
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 v-for="(skill, key) in list" :key="key" class="skill-group">
<header class="skill-header">
<div class="tech-icons">
<font-awesome-icon
v-for="(icon, keyIcon) in skill.icons"
:key="keyIcon" :class="icon.class"
:icon="['fab', icon.name]"
:alt="icon.alt"
:title="icon.title" />
</div>
<h3>{{ skill.header }}</h3>
</header>
<p v-if="skill.showMore || skill.description.length < 200">{{ skill.description }}</p>
<p v-else>{{ parseText(skill.description) }}... <a @click="changeMoreStatus(skill)">Więcej</a></p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Experiences',
data () {
return {
list: []
}
},
mounted () {
this.list = [
{
icons: [
{
class: 'icon-php',
name: 'php',
alt: 'Ikona przedstawiająca język PHP',
title: 'Ikona PHP'
},
{
class: 'icon-laravel',
name: 'laravel',
alt: 'Ikona przedstawiająca framework Laravel',
title: 'Ikona Laravel'
}
],
header: 'PHP & Laravel',
showMore: false,
description: `PHP wraz z frameworkiem Laravel wykorzystuję do tworzenia nowych projektów. Laravel znacznie
przyspiesza pisanie części backendowej, odciążając programistę od pisania skomplikownych filtrów i monotonnych
walidacji przyjmowanych danych od użytkowników. Jednakże, choć dobrze pracuje mi się w środowisku Laravel
w miarę możliwości staram się pisać kod w samym PHP z wykorzystaniem bibliotek i paczek autorskich.`
},
{
icons: [
{
class: 'icon-js',
name: 'js-square',
alt: 'Ikona przedstawiająca język JavaScript',
title: 'Ikona JavaScript'
}
],
header: 'JavaScript Vanilla',
showMore: false,
description: `JavaScript wykorzystuję głównie do logiki frontendowej jak i pisania kodu wykonywalnego po stronie
przeglądarki internetowej. Wykorzystując możliwości reaktywnych frameworków mogę przyspieszyć pisanie UI.`
},
{
icons: [
{
class: 'icon-vue',
name: 'vuejs',
alt: 'Ikona przedstawiająca framework Vue.js',
title: 'Ikona Vue.js'
}
],
header: 'Vue',
showMore: false,
description: `Framework ten wspomaga mnie w pisaniu aplikacji frontendowej. Przyspiesza tworzenie warstwy
wizualnej, obsługę interakcji z użytkownikiem i bindowanie zdefiniowanych pól, które są odpowiednio renderowane
przez przeglądarkę. To wszystko, umożliwia łatwe łączenie CSS i HTML z logiką i otrzymanymi danymi z API.`
},
{
icons: [
{
class: 'icon-html5',
name: 'html5',
alt: 'Ikona przedstawiająca HTML5',
title: 'Ikona HTML5'
},
{
class: 'icon-css3',
name: 'css3-alt',
alt: 'Ikona przedstawiająca CSS3',
title: 'Ikona CSS3'
}
],
header: 'HTML & CSS',
showMore: false,
description: `HTML i CSS to już nieodłączne technologie, które w łatwy sposób umożliwiają nadanie wizualnej
spójności dla treści, obrazów lub ułożenia elementów. Nie raz, odpowednie zaprojektowanie interfejsu użytkownika
przyspiesza integrację z naszą stroną/sklepem. Ma to przełożenie na zyski dla obu stron - firmy (finanse)
i klienta (czas).`
},
{
icons: [
{
class: 'icon-node',
name: 'node',
alt: 'Ikona przedstawiająca Node.js',
title: 'Ikona Node.js'
}
],
header: 'Node.js',
showMore: false,
description: `Node jest wieloplatformowym środowiskiem uruchomieniowym, umożliwiającym uruchomienie kodu
JavaScript po stronie backendowej. Jest to bardzo przyjemny język, który ułatwia projektowanie logiki biznesowej
aplikacji, dla mniej wymagających serwisów pod względem analizy i przetwarzania danych.`
},
{
icons: [
{
class: 'icon-sass',
name: 'sass',
alt: 'Ikona przedstawiająca Sass',
title: 'Ikona Sass'
}
],
header: 'Sass',
showMore: false,
description: `Sass zwiększa czytelność kodu dla programisty. Zawiera abstrakcje znane z języków obiektowych,
przy czym ogranicza powtarzalność i umożliwia optymalizację kodu. Kompilacja napisanego stylu w Sass jest
przekształcana do formy czytelnej dla silnika graficznego przeglądarki, co przyspiesza proces generowania strony.`
}
]
},
methods: {
parseText (text) {
let shortText = text.substr(0, 200)
if (shortText.slice(-1) === ' ') {
shortText = text.substr(0, 199)
}
return shortText
},
changeMoreStatus (skill) {
skill.showMore = !skill.showMore
}
}
}
</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);
}
}
}
}
.icon-js {
color: #F1DE4F;
}
.icon-php {
color: #777bb3;
}
.icon-laravel {
color: #FF2D20;
}
.icon-vue {
color: #64B687;
}
.icon-html5 {
color: #DE6E3C;
}
.icon-node {
color: #64B687;
}
.icon-css3 {
color: #53A7DC;
}
.icon-sass {
color: #BF6B97;
}
</style>

View File

@@ -0,0 +1,255 @@
<template>
<div class="experiences">
<div class="container">
<h2>Wykorzystywane technologie</h2>
<p>
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
v-for="(skill, skillKey) in list"
:key="skillKey"
class="skill-group"
>
<header class="skill-header">
<div class="tech-icons">
<font-awesome-icon
v-for="(icon, iconKey) in skill.icons"
:key="iconKey"
:class="icon.class"
:icon="['fab', icon.name]"
:alt="icon.alt"
:title="icon.title"
/>
</div>
<h3>{{ skill.header }}</h3>
</header>
<p v-if="skill.showMore.value || skill.description.length < 200">
{{ skill.description }}
</p>
<p v-else>
{{ parseText(skill.description) }}... <a @click="changeMoreStatus(skill)">Więcej</a>
</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let list = [
{
icons: [
{
class: 'icon-php',
name: 'php',
alt: 'Ikona przedstawiająca język PHP',
title: 'Ikona PHP'
},
{
class: 'icon-laravel',
name: 'laravel',
alt: 'Ikona przedstawiająca framework Laravel',
title: 'Ikona Laravel'
}
],
header: 'PHP & Laravel',
showMore: ref(false),
description: `PHP wraz z frameworkiem Laravel wykorzystuję do tworzenia nowych projektów. Laravel znacznie
przyspiesza pisanie części backendowej, odciążając programistę od pisania skomplikownych filtrów i monotonnych
walidacji przyjmowanych danych od użytkowników. Jednakże, choć dobrze pracuje mi się w środowisku Laravel
w miarę możliwości staram się pisać kod w samym PHP z wykorzystaniem bibliotek i paczek autorskich.`
},
{
icons: [
{
class: 'icon-js',
name: 'js-square',
alt: 'Ikona przedstawiająca język JavaScript',
title: 'Ikona JavaScript'
}
],
header: 'JavaScript Vanilla',
showMore: ref(false),
description: `JavaScript wykorzystuję głównie do logiki frontendowej jak i pisania kodu wykonywalnego po stronie
przeglądarki internetowej. Wykorzystując możliwości reaktywnych frameworków mogę przyspieszyć pisanie UI.`
},
{
icons: [
{
class: 'icon-vue',
name: 'vuejs',
alt: 'Ikona przedstawiająca framework Vue.js',
title: 'Ikona Vue.js'
}
],
header: 'Vue',
showMore: ref(false),
description: `Framework ten wspomaga mnie w pisaniu aplikacji frontendowej. Przyspiesza tworzenie warstwy
wizualnej, obsługę interakcji z użytkownikiem i bindowanie zdefiniowanych pól, które są odpowiednio renderowane
przez przeglądarkę. To wszystko, umożliwia łatwe łączenie CSS i HTML z logiką i otrzymanymi danymi z API.`
},
{
icons: [
{
class: 'icon-html5',
name: 'html5',
alt: 'Ikona przedstawiająca HTML5',
title: 'Ikona HTML5'
},
{
class: 'icon-css3',
name: 'css3-alt',
alt: 'Ikona przedstawiająca CSS3',
title: 'Ikona CSS3'
}
],
header: 'HTML & CSS',
showMore: ref(false),
description: `HTML i CSS to już nieodłączne technologie, które w łatwy sposób umożliwiają nadanie wizualnej
spójności dla treści, obrazów lub ułożenia elementów. Nie raz, odpowednie zaprojektowanie interfejsu użytkownika
przyspiesza integrację z naszą stroną/sklepem. Ma to przełożenie na zyski dla obu stron - firmy (finanse)
i klienta (czas).`
},
{
icons: [
{
class: 'icon-node',
name: 'node',
alt: 'Ikona przedstawiająca Node.js',
title: 'Ikona Node.js'
}
],
header: 'Node.js',
showMore: ref(false),
description: `Node jest wieloplatformowym środowiskiem uruchomieniowym, umożliwiającym uruchomienie kodu
JavaScript po stronie backendowej. Jest to bardzo przyjemny język, który ułatwia projektowanie logiki biznesowej
aplikacji, dla mniej wymagających serwisów pod względem analizy i przetwarzania danych.`
},
{
icons: [
{
class: 'icon-sass',
name: 'sass',
alt: 'Ikona przedstawiająca Sass',
title: 'Ikona Sass'
}
],
header: 'Sass',
showMore: ref(false),
description: `Sass zwiększa czytelność kodu dla programisty. Zawiera abstrakcje znane z języków obiektowych,
przy czym ogranicza powtarzalność i umożliwia optymalizację kodu. Kompilacja napisanego stylu w Sass jest
przekształcana do formy czytelnej dla silnika graficznego przeglądarki, co przyspiesza proces generowania strony.`
}
]
function parseText(text) {
let shortText = text.substr(0, 200)
if (shortText.slice(-1) === ' ') {
shortText = text.substr(0, 199)
}
return shortText
}
function changeMoreStatus(skill) {
skill.showMore.value = !skill.showMore.value
}
</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);
}
}
}
}
.icon-js {
color: #F1DE4F;
}
.icon-php {
color: #777bb3;
}
.icon-laravel {
color: #FF2D20;
}
.icon-vue {
color: #64B687;
}
.icon-html5 {
color: #DE6E3C;
}
.icon-node {
color: #64B687;
}
.icon-css3 {
color: #53A7DC;
}
.icon-sass {
color: #BF6B97;
}
</style>

View File

@@ -7,41 +7,33 @@
</div>
</projects>
<div class="more-button">
<GhostButton @click.native="$router.push('projects')">
<GhostButton @click="router.push('projects')">
ZOBACZ WIĘCEJ
</GhostButton>
</div>
</section>
</template>
<script>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import Projects from '../SelectedProjects'
import GhostButton from '../GhostButton'
import GhostButton from '../buttons/GhostButton'
export default {
name: 'FavoriteProjects',
data () {
return {
publicPath: process.env.VUE_APP_BASE_URL + '/',
select_projects: []
}
},
mounted () {
this.loadProjectList()
},
methods: {
loadProjectList () {
fetch(process.env.VUE_APP_API_URL + '/projects?category=selected')
.then(response => response.json())
.then(data => {
this.select_projects = data
})
}
},
components: {
GhostButton,
Projects
}
const router = useRouter()
let select_projects = ref([])
onMounted(() => {
loadProjectList()
})
function loadProjectList() {
fetch(process.env.VUE_APP_API_URL + '/projects?category=selected')
.then(response => response.json())
.then(data => {
select_projects.value = data
})
}
</script>

View File

@@ -1,22 +1,106 @@
<template>
<div class="contact_container">
<div class="message"></div>
<header class="container_head">Formularz kontaktowy:</header>
<form id="form-point" @submit="formSubmit">
<input v-model="emailValue" class="contact_input" type="text" name="email" placeholder="Twój adres e-mail." />
<textarea v-model="messageValue" class="contact_input" name="message" placeholder="Twoja wiadomość."></textarea>
<input v-model="senderValue" class="contact_input" type="text" name="sender" placeholder="Twój podpis." />
<base-btn is-reverse :disabled="buttonDisabled">Wyślij</base-btn>
<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:
</header>
<form
id="form-point"
@submit="formSubmit"
>
<label
class="label-info"
:class="{ 'label-error': isEmailError }"
for="email"
>
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"
>
<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>
<BaseButton
is-reverse
:disabled="isButtonDisabled"
>
Wyślij
</BaseButton>
</form>
</div>
</template>
<script>
import BaseButton from '../../BaseButton'
<script setup>
import BaseButton from '../../buttons/BaseButton'
import { ref, reactive, watch, computed } from 'vue'
function emailValidate (mailObj) {
const mailFormat = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/
return !!mailObj.value.match(mailFormat)
return mailObj.match(mailFormat)
}
async function postData (url = '', data = {}) {
@@ -31,99 +115,89 @@ async function postData (url = '', data = {}) {
return response.json()
}
export default {
name: 'MailContact',
data () {
return {
buttonDisabled: false,
statusError: 0,
email: {},
emailValue: '',
message: {},
messageValue: '',
sender: {},
senderValue: ''
}
},
components: {
'base-btn': BaseButton
},
watch: {
emailValue (value) {
if (this.statusError > 0 && emailValidate(this.email)) {
this.email.classList.remove('contact_input-error')
}
},
messageValue (value) {
if (this.statusError > 0 && value !== '') {
this.message.classList.remove('contact_input-error')
}
},
senderValue (value) {
if (this.statusError > 0 && value !== '') {
this.sender.classList.remove('contact_input-error')
}
}
},
methods: {
clearErrors () {
this.statusError = 0
this.email.classList.remove('contact_input-error')
this.message.classList.remove('contact_input-error')
this.sender.classList.remove('contact_input-error')
},
checkForm () {
if (!emailValidate(this.email)) {
this.email.classList.add('contact_input-error')
this.statusError++
}
if (this.message.value === '') {
this.message.classList.add('contact_input-error')
this.statusError++
}
if (this.sender.value === '') {
this.sender.classList.add('contact_input-error')
this.statusError++
}
},
formSubmit (event) {
event.preventDefault()
const buttonDisabled = ref(false)
const statusError = ref(0)
const emailValue = ref('')
const messageValue = ref('')
const senderValue = ref('')
this.email = event.target[0]
this.message = event.target[1]
this.sender = event.target[2]
const messageError = ref('')
const messageOk = ref('')
this.clearErrors()
this.checkForm()
const errors = reactive({
email: false,
message: false,
sender: false
})
const messageElement = document.querySelector('.message')
messageElement.classList.remove('message_ok', 'message_error')
const isButtonDisabled = computed(() => buttonDisabled.value || errors.email || errors.message || errors.sender)
const isEmailError = computed(() => errors.email)
const isMessageError = computed(() => errors.message)
const isSenderError = computed(() => errors.sender)
const hasMessageError = computed(() => messageError.value)
const hasMessageOkStatus = computed(() => messageOk.value && !hasMessageError.value)
if (this.statusError === 0) {
this.buttonDisabled = true
postData('/send', {
email: this.emailValue,
message: this.messageValue,
sender: this.senderValue
}).then(result => {
messageElement.classList.add(
result.error ? 'message_error' : 'message_ok'
)
watch([statusError, emailValue], ([errorCount, value]) => {
errors.email = errorCount > 0 && !emailValidate(value)
})
messageElement.textContent = result.message
if (!result.error) {
this.messageValue = ''
this.emailValue = ''
this.senderValue = ''
}
this.buttonDisabled = false
}).catch(() => {
messageElement.classList.add('message_error')
messageElement.textContent = 'Wystąpił błąd podczas wysyłania wiadomości. Proszę spróbować później.'
this.buttonDisabled = false
})
watch([statusError, messageValue], ([errorCount, value]) => {
errors.message = errorCount > 0 && (value === '' || value.length < 3)
})
watch([statusError, senderValue], ([errorCount, value]) => {
errors.sender = errorCount > 0 && (value === '' || value.length < 3)
})
function clearErrors() {
statusError.value = 0
errors.email = false
errors.message = false
errors.sender = false
}
function checkForm() {
clearErrors()
if (!emailValidate(emailValue.value)) {
errors.email = true
statusError.value++
}
if (messageValue.value === '') {
errors.message = true
statusError.value++
}
if (senderValue.value === '') {
errors.sender = true
statusError.value++
}
}
function formSubmit(event) {
event.preventDefault()
checkForm()
if (statusError.value === 0) {
console.log('Send!')
buttonDisabled.value = true
postData('https://kamilcraft.com/send', {
email: emailValue.value,
message: messageValue.value,
sender: senderValue.value
}).then(result => {
if (result.error) {
messageError.value = result.message
} else {
messageOk.value = result.message
messageValue.value = ''
emailValue.value = ''
senderValue.value = ''
}
}
buttonDisabled.value = false
}).catch(() => {
messageError.value = 'Wystąpił błąd podczas wysyłania wiadomości. Proszę spróbować później.'
buttonDisabled.value = false
})
}
}
</script>
@@ -153,17 +227,35 @@ export default {
font-weight: bold;
}
.contact_container input, .contact_container 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: 10px;
border-radius: 5px;
.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 {
@@ -177,14 +269,14 @@ textarea.contact_input {
min-height: 150px;
}
.contact_input-error, .contact_input-error {
background-color: #ffc3b0;
border-color: #ff865f;
color: #c90000;
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: #c9000094;
color: #d7626a;
}
input[disabled].contact_input {
@@ -211,8 +303,8 @@ input[disabled].contact_input {
}
.message_error {
background-color: #ffc3b0;
border: 1px solid #ff865f;
color: #c90000;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
</style>

View File

@@ -1,53 +1,86 @@
<template>
<div class="contact_info">
<header class="info_head">Inne formy kontaktu:</header>
<header class="info_head">
Inne formy kontaktu:
</header>
<div class="contact_element">
<img class="contact_element_icon"
src="/assets/img/instagram.jpg" />
<span id="instagram" class="contact_element_text">
<a href="https://www.instagram.com/nikcamii/"
target="_blank"
rel="noopener nofollow noreferrer">Instagram: @NiKCamii</a>
<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" />
<span id="facebook" class="contact_element_text">
<a href="https://www.facebook.com/nikcamii/"
target="_blank"
rel="noopener nofollow noreferrer">Facebook: @NiKCamii</a>
<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" />
<span id="twitter" class="contact_element_text">
<a href="https://twitter.com/nikcamii"
target="_blank"
rel="noopener nofollow noreferrer">Twitter: @NiKCamii</a>
<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" />
<span id="gg" class="contact_element_text">GG: 38429969</span>
<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" />
<span id="email" class="contact_element_text">
<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>
</div>
</template>
<script>
export default {
name: 'OtherContact'
}
</script>
<style lang="scss" scoped>
@import "scss/media";
@@ -113,7 +146,7 @@ export default {
color: #5eaade;
}
#email {
#mailto {
color: #696969;
}
@@ -122,7 +155,7 @@ export default {
}
@include media-tablet {
#instagram, #facebook, #twitter, #email, #gg {
#instagram, #facebook, #twitter, #mailto, #gg {
font-size: 1em;
line-height: 1.2em;
}