diff --git a/src/components/cool_link.rs b/src/components/cool_link.rs new file mode 100644 index 0000000..3f81a6a --- /dev/null +++ b/src/components/cool_link.rs @@ -0,0 +1,14 @@ +use sycamore::prelude::*; + +#[component] +pub fn CoolLink(cx: Scope, CoolLinkProps { to, text }: CoolLinkProps) -> View { + view! {cx, + a(href=(to), class="cool-link", data-text=(text)){span{(text)}} + } +} + +#[derive(Prop)] +pub struct CoolLinkProps { + to: &'static str, + text: &'static str, +} diff --git a/src/components/header.rs b/src/components/header.rs new file mode 100644 index 0000000..58aa00e --- /dev/null +++ b/src/components/header.rs @@ -0,0 +1,23 @@ +use sycamore::prelude::*; + +use crate::components::cool_link::CoolLink; + +#[component] +pub fn Header(cx: Scope) -> View { + view! {cx, + header(class="header") { + div(class="header__container") { + ul(class="header__left") { + li(class="header--xs") { CoolLink(text="Home", to="") } + li(class="header--sm") { CoolLink(text="Reviews", to="#") } + li { CoolLink(text="Projects", to="#") } + li(class="header--sm") { CoolLink(text="Insights", to="#") } + li(class="header--sm") { CoolLink(text="Faq", to="#") } + } + div(class="header__right") { + button(class="cool-button") {span{"Contact"}} + } + } + } + } +} diff --git a/src/components/intro.rs b/src/components/intro.rs new file mode 100644 index 0000000..862d0a4 --- /dev/null +++ b/src/components/intro.rs @@ -0,0 +1,14 @@ +use sycamore::prelude::*; + +#[component] +pub fn Intro(cx: Scope) -> View { + view! {cx, + div(class="intro") { + h4 { "Hi 👋, My name is" } + h1 { "Binh Tran" } + h2 { "Full stack web developer" } + h2 { "Automation tester" } + h2 { "from Vietnam" } + } + } +} diff --git a/src/components/landing.rs b/src/components/landing.rs new file mode 100644 index 0000000..8d3e98d --- /dev/null +++ b/src/components/landing.rs @@ -0,0 +1,14 @@ +use crate::components::{header::Header, intro::Intro, scroll_down::ScrollDown, social::Social}; +use sycamore::prelude::*; + +#[component] +pub fn Landing(cx: Scope) -> View { + view! {cx, + main(class="landing") { + Header + Social + Intro + ScrollDown + } + } +} diff --git a/src/components/layout.rs b/src/components/loader.rs similarity index 63% rename from src/components/layout.rs rename to src/components/loader.rs index 8e191c8..f712ba9 100644 --- a/src/components/layout.rs +++ b/src/components/loader.rs @@ -1,13 +1,17 @@ +use std::fs; + use sycamore::prelude::*; #[component] -pub fn Layout<'a, G: Html>(cx: Scope<'a>, LayoutProps { children }: LayoutProps<'a, G>) -> View { - let children = children.call(cx); - - view! { cx, +pub fn Loader(cx: Scope) -> View { + view! {cx, div(class="loader") { + style { (fs::read_to_string("static/styles/loader.css").expect("Cannot read loader.css")) } div(class="loader__box") { - img(src=".perseus/static/assets/images/mangekyou-sharingan.svg", alt="Loader image", class="loader__image") + img(src=".perseus/static/assets/images/mangekyou-sharingan.svg", + loading="lazy", + alt="Loader image", + class="loader__image") div(class="loader__text") { "L" div(class="loader__text--dot") @@ -22,15 +26,7 @@ pub fn Layout<'a, G: Html>(cx: Scope<'a>, LayoutProps { children }: LayoutProps< span(class="loader__counter--number") {"0%"} } } - script(src=".perseus/static/scripts/loader.js", defer=true) - } - main { - (children) } + script { (fs::read_to_string("static/scripts/loader.js").expect("Cannot read loader.js")) } } } - -#[derive(Prop)] -pub struct LayoutProps<'a, G: Html> { - pub children: Children<'a, G>, -} diff --git a/src/components/mod.rs b/src/components/mod.rs index 6738e8c..9fe3947 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,2 +1,9 @@ -pub mod layout; +pub mod cool_link; +pub mod header; +pub mod intro; +pub mod landing; +pub mod loader; +pub mod scroll_down; pub mod seo; +pub mod social; +pub mod social_link; diff --git a/src/components/scroll_down.rs b/src/components/scroll_down.rs new file mode 100644 index 0000000..ba9538f --- /dev/null +++ b/src/components/scroll_down.rs @@ -0,0 +1,17 @@ +use sycamore::prelude::*; + +#[component] +pub fn ScrollDown(cx: Scope) -> View { + view!{cx, + div(class="scroll-down") { + div(class="scroll-down__wheel") { + div(class="scroll-down__wheel--inner") + } + div(class="scroll-down__arrows") { + span(class="scroll-down__arrow") + span(class="scroll-down__arrow") + span(class="scroll-down__arrow") + } + } + } +} diff --git a/src/components/social.rs b/src/components/social.rs new file mode 100644 index 0000000..89920e2 --- /dev/null +++ b/src/components/social.rs @@ -0,0 +1,19 @@ +use std::fs; + +use sycamore::prelude::*; + +use crate::components::social_link::{SocialLink, SocialType}; + +#[component] +pub fn Social(cx: Scope) -> View { + view! {cx, + div(class="social") { + style { (fs::read_to_string("static/styles/social-icon.css").expect("Cannot read social-icon.css")) } + SocialLink(to="https://www.linkedin.com/in/binhtran432k", typ=SocialType::LinkedIn) + SocialLink(to="https://github.com/binhtran432k", typ=SocialType::GitHub) + SocialLink(to="#", typ=SocialType::Instagram) + SocialLink(to="https://www.facebook.com/binhtran432k", typ=SocialType::Facebook) + SocialLink(to="https://www.youtube.com/@binhtran432k", typ=SocialType::Youtube) + } + } +} diff --git a/src/components/social_link.rs b/src/components/social_link.rs new file mode 100644 index 0000000..e359cda --- /dev/null +++ b/src/components/social_link.rs @@ -0,0 +1,43 @@ +use std::fmt; + +use sycamore::prelude::*; + +#[component] +pub fn SocialLink(cx: Scope, SocialProps { to, typ }: SocialProps) -> View { + view! {cx, + a(href=to, + target="_blank", + title=format!("Social link of {}", typ.to_string()), + class=format!("icon icon--{} colored-icon", typ.to_string())) + { + span{} + } + } +} + +#[derive(Clone, Copy)] +pub enum SocialType { + GitHub, + Youtube, + Instagram, + Facebook, + LinkedIn, +} + +impl fmt::Display for SocialType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SocialType::GitHub => write!(f, "github"), + SocialType::Youtube => write!(f, "youtube"), + SocialType::Instagram => write!(f, "instagram"), + SocialType::Facebook => write!(f, "facebook"), + SocialType::LinkedIn => write!(f, "linkedin"), + } + } +} + +#[derive(Prop)] +pub struct SocialProps { + pub to: &'static str, + pub typ: SocialType, +} diff --git a/src/error_views.rs b/src/error_views.rs index 1064f88..bdd69f1 100644 --- a/src/error_views.rs +++ b/src/error_views.rs @@ -1,14 +1,16 @@ use perseus::{errors::ClientError, prelude::*}; use sycamore::prelude::*; +use crate::layouts::error::{Error, ErrorHead}; + fn get_error_page(cx: Scope, title: String, message: String) -> (View, View) { ( view! { cx, title { (title) } + ErrorHead }, view! { cx, - // Don't worry, there are much better ways of styling in Perseus! - div(class="test") { + Error { h1 { (title) } p { (message) } } @@ -17,7 +19,7 @@ fn get_error_page(cx: Scope, title: String, message: String) -> (View() -> ErrorViews { - ErrorViews::new(|cx, err, _err_info, _err_pos| { + ErrorViews::new(|cx, err, _err_info, _err_pos| -> (View, View) { match err { ClientError::ServerError { status, message: _ } => match status { 404 => get_error_page( diff --git a/src/layouts/error.rs b/src/layouts/error.rs new file mode 100644 index 0000000..2f357ff --- /dev/null +++ b/src/layouts/error.rs @@ -0,0 +1,33 @@ +use perseus::prelude::*; +use sycamore::prelude::*; + +use crate::components::{header::Header, loader::Loader, social::Social}; + +#[component] +pub fn Error<'a, G: Html>(cx: Scope<'a>, ErrorProps { children }: ErrorProps<'a, G>) -> View { + let children = children.call(cx); + + view! { cx, + Loader + main(class="error") { + Header + Social + div(class="error__content") { + (children) + } + } + } +} + +#[component] +pub fn ErrorHead(cx: Scope) -> View { + view! { cx, + link(rel="stylesheet", href=".perseus/static/styles/layout.css") + link(rel="stylesheet", href=".perseus/static/styles/cool-item.css") + } +} + +#[derive(Prop)] +pub struct ErrorProps<'a, G: Html> { + pub children: Children<'a, G>, +} diff --git a/src/layouts/index.rs b/src/layouts/index.rs new file mode 100644 index 0000000..c77438f --- /dev/null +++ b/src/layouts/index.rs @@ -0,0 +1,27 @@ +use perseus::prelude::*; +use sycamore::prelude::*; + +use crate::components::loader::Loader; + +#[component] +pub fn Index<'a, G: Html>(cx: Scope<'a>, IndexProps { children }: IndexProps<'a, G>) -> View { + let children = children.call(cx); + + view! { cx, + Loader() + (children) + } +} + +#[component] +pub fn IndexHead(cx: Scope) -> View { + view! { cx, + link(rel="stylesheet", href=".perseus/static/styles/layout.css") + link(rel="stylesheet", href=".perseus/static/styles/cool-item.css") + } +} + +#[derive(Prop)] +pub struct IndexProps<'a, G: Html> { + pub children: Children<'a, G>, +} diff --git a/src/layouts/mod.rs b/src/layouts/mod.rs new file mode 100644 index 0000000..691cc3e --- /dev/null +++ b/src/layouts/mod.rs @@ -0,0 +1,2 @@ +pub mod index; +pub mod error; diff --git a/src/main.rs b/src/main.rs index 1ed206f..7f085cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,13 +5,16 @@ use lol_alloc::{FreeListAllocator, LockedAllocator}; #[cfg(client)] #[global_allocator] -static ALLOCATOR: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); +static ALLOCATOR: LockedAllocator = + LockedAllocator::new(FreeListAllocator::new()); mod components; mod error_views; +mod layouts; mod templates; use perseus::prelude::*; +use std::fs; use sycamore::prelude::view; #[perseus::main_export] @@ -29,10 +32,13 @@ pub fn main() -> PerseusApp { // fonts link (rel="preconnect", href="https://fonts.googleapis.com") link (rel="preconnect", href="https://fonts.gstatic.com", crossorigin="crossorigin") - link (href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&family=Orbitron:wght@400;700&display=swap", rel="stylesheet") + link (rel="preload", href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700&family=Orbitron:wght@400;700&display=swap", as="style", onload="this.onload=null;this.rel='stylesheet'") // styles - link(rel="stylesheet", href=".perseus/static/styles/base.css") - link(rel="stylesheet", href=".perseus/static/styles/loader.css") + style { (fs::read_to_string("static/styles/base.css").expect("Cannot read base.css")) } + // No scripts alternative + noscript { + link (href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700&family=Orbitron:wght@400;700&display=swap", rel="stylesheet") + } } body { // Quirk: this creates a wrapper `
` around the root `
` by necessity diff --git a/src/templates/index.rs b/src/templates/index.rs index 35340e1..fe10835 100644 --- a/src/templates/index.rs +++ b/src/templates/index.rs @@ -1,17 +1,15 @@ use perseus::prelude::*; use sycamore::prelude::*; -use crate::components::layout::Layout; +use crate::{ + components::landing::Landing, + layouts::index::{Index, IndexHead}, +}; fn index_page(cx: Scope) -> View { view! { cx, - Layout { - h1 { "Welcome to Perseus!" } - p { - "This is just an example app. Try changing some code inside " - code { "src/templates/index.rs" } - " and you'll be able to see the results here!" - } + Index { + Landing } } } @@ -20,6 +18,7 @@ fn index_page(cx: Scope) -> View { fn head(cx: Scope) -> View { view! { cx, title { "BINH TRAN - Fullstack Developer" } + IndexHead } } diff --git a/static/assets/images/background.jpg b/static/assets/images/background.jpg new file mode 100644 index 0000000..b6bc736 Binary files /dev/null and b/static/assets/images/background.jpg differ diff --git a/static/assets/svg/facebook.svg b/static/assets/svg/facebook.svg new file mode 100644 index 0000000..b97a838 --- /dev/null +++ b/static/assets/svg/facebook.svg @@ -0,0 +1 @@ + diff --git a/static/assets/svg/github.svg b/static/assets/svg/github.svg new file mode 100644 index 0000000..7ddcfdc --- /dev/null +++ b/static/assets/svg/github.svg @@ -0,0 +1 @@ + diff --git a/static/assets/svg/instagram.svg b/static/assets/svg/instagram.svg new file mode 100644 index 0000000..0795a95 --- /dev/null +++ b/static/assets/svg/instagram.svg @@ -0,0 +1 @@ + diff --git a/static/assets/svg/linkedin.svg b/static/assets/svg/linkedin.svg new file mode 100644 index 0000000..035e08c --- /dev/null +++ b/static/assets/svg/linkedin.svg @@ -0,0 +1 @@ + diff --git a/static/assets/svg/youtube.svg b/static/assets/svg/youtube.svg new file mode 100644 index 0000000..0a718cd --- /dev/null +++ b/static/assets/svg/youtube.svg @@ -0,0 +1 @@ + diff --git a/static/sass/_variables.scss b/static/sass/_variables.scss new file mode 100644 index 0000000..afd2ad8 --- /dev/null +++ b/static/sass/_variables.scss @@ -0,0 +1,13 @@ +$green: #6cff8d; +$red: #FF5555; +$yellow: #F1FA8C; +$purple: #BD93F9; +$cyan: #8BE9FD; +$orange: #FFB86C; +$pink: #FF79C6; +$blue: mix($cyan, blue, $weight: 50%); +$fg: #F8F8F2; +$bg: #282A36; +$green-50: rgba($green, 0.4); +$fg-50: rgba($fg, 0.4); +$bg-50: rgba($bg, 50%); diff --git a/static/sass/base.scss b/static/sass/base.scss index 1aa5be7..d94d52c 100644 --- a/static/sass/base.scss +++ b/static/sass/base.scss @@ -43,10 +43,11 @@ svg { max-width: 100%; } -.test { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 95vh; +a { + text-decoration: none; + color: inherit; +} + +ul { + list-style-type: none; } diff --git a/static/sass/cool-item.scss b/static/sass/cool-item.scss new file mode 100644 index 0000000..33eb88d --- /dev/null +++ b/static/sass/cool-item.scss @@ -0,0 +1,141 @@ +@import "_variables"; + +.cool-link { + $transition-opts: 0.3s cubic-bezier(0.5, 0.5, 0.3, 1); + position: relative; + display: grid; + place-items: center; + width: fit-content; + overflow: hidden; + + & span { + transition: transform $transition-opts; + } + + &::before { + content: ""; + position: absolute; + width: 100%; + height: 0.125rem; + background-color: currentColor; + bottom: 0; + left: 0; + transform: scale3d(0, 1, 1); + transform-origin: right; + transition: transform $transition-opts; + } + + &:hover::before { + transform: scale3d(1, 1, 1); + transform-origin: left; + } + + &::after { + position: absolute; + content: attr(data-text); + top: 0; + left: 0; + height: 100%; + transform: translate3d(150%, 0, 0); + transition: transform $transition-opts; + } + + &:hover::after { + transform: translate3d(0, 0, 0); + } + + &:hover span { + transform: translate3d(-150%, 0, 0); + } +} + +.cool-button { + $transition-opts: 0.3s cubic-bezier(0.5, 2.5, 0.5, 0.5); + position: relative; + border: none; + cursor: pointer; + width: 11rem; + height: 7.5rem; + background: none; + color: $fg; + + @media (max-width: 800px) { + font-size: 1.4em; + transform-origin: right; + transform: scale3d(0.7, 0.7, 0.7); + } + + &::before, + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + } + + &::before { + width: 100%; + height: 100%; + background-color: $fg; + clip-path: path("M154,88 C131,113 62,110 30,89 C-2,69 -3.5,42 4,25 C12.5,9 33,-6 85,3 C136,13 178,63 154,88 Z"); + transition: clip-path $transition-opts; + } + + &:hover::before { + clip-path: path("M143,77 C117,96 74,100 45,91 C17,82 -10,57 5,31 C21,6 79,-5 130,4 C182,13 169,58 143,77 Z"); + } + + &::after { + width: 95%; + height: 85%; + top: 0.375rem; + border: 0.0625rem solid $fg; + border-radius: 58% 42% 55% 45% / 56% 45% 55% 44%; + transform: rotate(-20deg); + transition: transform $transition-opts; + } + + &:hover::after { + transform: translate3d(0, -0.375rem, 0); + } + + & span { + mix-blend-mode: difference; + font-weight: 500; + } +} + +.colored-icon { + $bs: 0.14em -0.11em; + $be: 0.14em 0.11em; + $ts: -0.14em -0.17em; + $te: -0.23em 0.11em; + $ts2: -0.14em 0; + font-size: 2.1rem; + + &:hover { + animation: colored-icon-animation 0.2s infinite; + } + + @keyframes colored-icon-animation { + 0% { + filter: drop-shadow($be $red) drop-shadow($ts $blue); + } + + 25% { + filter: drop-shadow($ts $red) drop-shadow($be $blue); + } + + 50% { + filter: drop-shadow($bs $red) drop-shadow($te $blue); + } + + 75% { + filter: drop-shadow($te $red) drop-shadow($ts $blue); + } + + 100% { + filter: drop-shadow($ts2 $red) drop-shadow($bs $blue); + } + } +} diff --git a/static/sass/layout.scss b/static/sass/layout.scss new file mode 100644 index 0000000..ceb5400 --- /dev/null +++ b/static/sass/layout.scss @@ -0,0 +1,199 @@ +@import "_variables"; + +.landing, +.error { + position: relative; + width: 100%; + height: 100vh; + background-color: $bg; + background-image: linear-gradient($bg-50, $bg-50), url("../assets/images/background.jpg"); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + color: $fg; + overflow: hidden; +} + +.error { + &__content { + padding: 1rem; + text-align: center; + } + .social { + bottom: 3rem; + } +} + +.social { + position: absolute; + left: 50%; + bottom: 30%; + width: 100%; + transform: translateX(-50%); + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 1rem; + + @media (max-height: 500px) { + flex-wrap: wrap-reverse; + left: 100%; + transform: translateX(-100%); + flex-direction: column; + width: auto; + bottom: 0; + max-height: calc(100vh - 8rem); + } +} + +.header { + padding-top: 1rem; + + &__left { + padding: 0 0.5rem; + } + + &__container { + margin: auto; + padding: 0.625rem; + display: flex; + align-items: center; + justify-content: space-between; + max-width: 1200px; + width: 100vw; + + @media (max-height: 500px) { + padding-top: 0; + } + } + + &--sm { + @media (max-width: 650px) { + display: none; + } + } + + &--xs { + @media (max-width: 370px) { + display: none; + } + } + + &__left { + display: flex; + align-items: center; + gap: 2rem; + + & li { + font-size: 1.125rem; + font-weight: 700; + + @media (max-width: 500px) { + font-size: 1rem; + } + } + } +} + +.scroll-down { + position: absolute; + left: 50%; + bottom: 3rem; + transform: translateX(-50%); + + &__wheel { + width: 1.5rem; + height: 2.63rem; + border-radius: 0.625rem; + border: 2px solid $fg; + + &--inner { + position: absolute; + left: 50%; + top: 15%; + width: 0.25rem; + height: 0.25rem; + border-radius: 50%; + background-color: $fg; + transform: translateX(-50%); + animation: movingwheel 0.2s linear alternate infinite; + + @keyframes movingwheel { + 0% { + top: 8%; + } + + 100% { + top: 14%; + } + } + } + } + + &__arrows { + display: flex; + flex-direction: column; + align-items: center; + + .scroll-down__arrow { + $border: 2px solid $fg; + width: 15px; + height: 15px; + border-right: $border; + border-bottom: $border; + transform: rotate(45deg); + animation: scroll-animation 0.7s alternate infinite; + opacity: 0; + + @for $i from 1 through 3 { + &:nth-child(#{$i}) { + animation-delay: $i * 0.1s; + } + } + + @keyframes scroll-animation { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } + } + } +} + +.intro { + padding: 0 1rem; + width: 100%; + font-family: "Orbitron", sans-serif; + + @media (max-width: 600px) { + h1 { + font-size: 1.5rem; + } + + h2 { + font-size: 1.25rem; + } + + h4 { + font-size: 0.875rem; + } + } + + @media (max-width: 370px) or (max-height: 370px) { + h1 { + font-size: 1.25rem; + } + + h2 { + font-size: 1rem; + } + + h4 { + font-size: 0.75rem; + } + } +} diff --git a/static/sass/loader.scss b/static/sass/loader.scss index 1bbdeb2..5e627c1 100644 --- a/static/sass/loader.scss +++ b/static/sass/loader.scss @@ -1,8 +1,7 @@ +@import "_variables"; + .loader { - $green: #6cff8d; - $green-50: rgba($green, 0.4); - $fg: #fff; - $bg: #0b134f; + $size: min(500px, 100vw, 100vh); position: fixed; top: 0; right: 0; @@ -26,7 +25,7 @@ &__box { position: relative; - max-width: 500px; + max-width: $size; width: 90%; padding: 1rem; border: 0.1875rem solid $green; @@ -44,12 +43,12 @@ 50% { border-radius: 50%; - min-height: min(500px, 100vw); + min-height: $size; } 100% { border-radius: 50%; - min-height: min(500px, 100vw); + min-height: $size; border-color: transparent; } } @@ -59,7 +58,7 @@ width: 90%; height: 0.625rem; margin: 2rem auto 3rem auto; - background-color: #ccc; + background-color: $fg-50; &--inner { width: 0; @@ -163,37 +162,38 @@ width: 85%; height: auto; opacity: 0; - filter: hue-rotate(310deg); } - &--loaded &__image { - animation: image-amination 70s forwards; + @media (min-width: 500px) and (min-height: 500px) { + &--loaded &__image { + animation: image-amination 1.2s ease-out forwards; - @keyframes image-amination { - 0% { - opacity: 0; - } - - 2% { - opacity: 1; - rotate: -60deg; - } + @keyframes image-amination { + 0% { + opacity: 0; + } - 100% { - opacity: 1; - rotate: -720deg; + 100% { + opacity: 1; + rotate: -180deg; + filter: hue-rotate(-70deg); + } } } } &--loaded { animation: loaded-animation 600ms forwards; - animation-delay: 600ms; + + @media (min-width: 500px) and (min-height: 500px) { + animation-delay: 600ms; + } @keyframes loaded-animation { to { background-color: transparent; - opacity: 0.3; + opacity: 0; + display: none; } } } diff --git a/static/sass/social-icon.scss b/static/sass/social-icon.scss new file mode 100644 index 0000000..5c2d323 --- /dev/null +++ b/static/sass/social-icon.scss @@ -0,0 +1,39 @@ +.icon { + position: relative; + + span { + width: 1em; + height: 1em; + /* Add dimensions to span */ + display: inline-block; + /* Add background color */ + background-color: currentColor; + /* Add mask image, use variable to reduce duplication */ + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + } + + &--linkedin { + --svg: url('.perseus/static/assets/svg/linkedin.svg'); + } + + &--github { + --svg: url('.perseus/static/assets/svg/github.svg'); + } + + &--instagram { + --svg: url('.perseus/static/assets/svg/instagram.svg'); + } + + &--facebook { + --svg: url('.perseus/static/assets/svg/facebook.svg'); + } + + &--youtube { + --svg: url('.perseus/static/assets/svg/youtube.svg'); + } +}