aboutsummaryrefslogtreecommitdiff
path: root/src/layouts
diff options
context:
space:
mode:
Diffstat (limited to 'src/layouts')
-rw-r--r--src/layouts/ContactPageLayout.astro99
-rw-r--r--src/layouts/HomePageLayout.astro62
-rw-r--r--src/layouts/Layout.astro28
-rw-r--r--src/layouts/PortfolioPageLayout.astro113
-rw-r--r--src/layouts/TrajectoryPageLayout.astro81
5 files changed, 375 insertions, 8 deletions
diff --git a/src/layouts/ContactPageLayout.astro b/src/layouts/ContactPageLayout.astro
new file mode 100644
index 0000000..3b3c278
--- /dev/null
+++ b/src/layouts/ContactPageLayout.astro
@@ -0,0 +1,99 @@
+---
+import { useTranslations } from "../i18n";
+import Layout from "./Layout.astro";
+
+const t = useTranslations(Astro.currentLocale);
+
+const schema = {
+ "@context": "https://schema.org",
+ "@type": "ContactPage",
+ url: "https://www.costas.dev/contact",
+ headline: t.contactPage.headline,
+};
+---
+
+<Layout title={t.contactPage.title} description={t.contactPage.description}>
+ <script
+ is:inline
+ type="application/ld+json"
+ slot="head-jsonld"
+ set:html={JSON.stringify(schema)}
+ />
+
+ <h1>{t.contactPage.headline}</h1>
+
+ <noscript>
+ <div role="alert" class="warning">
+ {t.contactPage.enableJs}
+ </div>
+ </noscript>
+
+ <p set:html={t.contactPage.intro} />
+
+ <p>{t.contactPage.socialMedia}</p>
+
+ <dl>
+ <dt>GitHub</dt>
+ <dd><a href="https://github.com/arielcostas">@arielcostas</a></dd>
+ <dt>LinkedIn</dt>
+ <dd>
+ <a href="https://www.linkedin.com/in/ariel-costas/"
+ >/in/ariel-costas</a>
+ </dd>
+ <dt>BlueSky</dt>
+ <dd><a href="https://bsky.app/profile/costas.dev">@costas.dev</a></dd>
+ </dl>
+</Layout>
+
+<script>
+ const encryptedEmail = "LygNLiMmFRo/GlQZaFIWBA==";
+ const encryptedPhoneNumber = "ZWlQfX1QT0Z+XgVd";
+ const key = "NZdKOfvuLn5jF6sryF0Q";
+
+ const emailAddrLink = document.getElementById(
+ "email-addr",
+ ) as HTMLAnchorElement;
+ const phoneNumberLink = document.getElementById(
+ "phone-number",
+ ) as HTMLAnchorElement;
+
+ (() => {
+ if (emailAddrLink == null || phoneNumberLink == null) {
+ return;
+ }
+
+ const emailAddress = xorData(encryptedEmail, key);
+ const phoneNumber = xorData(encryptedPhoneNumber, key);
+
+ emailAddrLink.href = `mailto:${emailAddress}`;
+ emailAddrLink.textContent = emailAddress;
+
+ phoneNumberLink.href = `tel:${phoneNumber}`;
+ phoneNumberLink.textContent = phoneNumber;
+ })();
+
+ function xorData(data: string, key: string): string {
+ let actualData = atob(data);
+ let actualKey = key;
+ const keyLength = key.length;
+ const dataLength = actualData.length;
+ const result = new Array(dataLength);
+
+ // If the key is 12 characters but the data is 30 characters, the key should be repeated 3 times and truncated to 30 characters
+ if (keyLength < dataLength) {
+ actualKey = key
+ .repeat(Math.ceil(dataLength / keyLength))
+ .substring(0, dataLength);
+ } else if (keyLength > dataLength) {
+ actualKey = key.substring(0, dataLength);
+ }
+
+ for (let i = 0; i < dataLength; i++) {
+ result[i] = String.fromCharCode(
+ actualData.charCodeAt(i) ^ actualKey.charCodeAt(i),
+ );
+ }
+
+ return result.join("");
+ }
+</script>
diff --git a/src/layouts/HomePageLayout.astro b/src/layouts/HomePageLayout.astro
new file mode 100644
index 0000000..146eaec
--- /dev/null
+++ b/src/layouts/HomePageLayout.astro
@@ -0,0 +1,62 @@
+---
+import { getCollection } from "astro:content";
+import Layout from "./Layout.astro";
+import { useTranslations } from "../i18n";
+
+const blogCollection = (await getCollection("blog")).sort((a, b) => {
+ return b.data.publishedAt.getTime() - a.data.publishedAt.getTime();
+});
+
+const t = useTranslations(Astro.currentLocale);
+
+const schema = {
+ "@context": "http://schema.org",
+ "@type": "WebSite",
+ id: "https://www.costas.dev/",
+ url: "https://www.costas.dev/",
+ headline: t.homePage.title,
+};
+---
+
+<Layout title={t.homePage.title} description={t.homePage.description}>
+ <script
+ is:inline
+ type="application/ld+json"
+ slot="head-jsonld"
+ set:html={JSON.stringify(schema)}
+ />
+
+ <h1>{t.homePage.title}</h1>
+ <p>{t.homePage.welcome}</p>
+
+ <h2>{t.homePage.whoAmI}</h2>
+ <p>{t.homePage.whoAmIDesc}</p>
+ <a href="/trajectory">{t.homePage.moreAboutMe}</a>
+
+ <h2>{t.homePage.whatIDo}</h2>
+ <p>{t.homePage.whatIDoDesc}</p>
+ <a href="/portfolio">{t.homePage.myPortfolio}</a>
+
+ <h2>{t.homePage.latestBlogPosts}</h2>
+ <ul>
+ {
+ blogCollection.slice(0, 5).map((p) => {
+ const date = Intl.DateTimeFormat(Astro.currentLocale, {
+ day: "2-digit",
+ month: "short",
+ year: "numeric",
+ }).format(p.data.publishedAt);
+ return (
+ <li>
+ <time datetime={p.data.publishedAt.toISOString()}>
+ {date}
+ </time>
+ <a href={`/blog/${p.id}`}>{p.data.title}</a>
+ </li>
+ );
+ })
+ }
+ </ul>
+ <a href="/blog">{t.homePage.viewAllPosts}</a>
+
+</Layout>
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index 4952d55..eda1716 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -13,7 +13,7 @@ const { title, description } = Astro.props;
---
<!doctype html>
-<html lang="es">
+<html lang={Astro.currentLocale}>
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
@@ -53,6 +53,7 @@ const { title, description } = Astro.props;
<style is:global lang="scss">
@use "../../styles/shared.scss" as *;
+ @use "sass:color";
html,
body {
@@ -82,7 +83,7 @@ const { title, description } = Astro.props;
}
*::selection {
- background-color: transparentize($accent, 0.85);
+ background-color: color.adjust($accent, $alpha: -0.85);
}
li > time {
@@ -93,12 +94,17 @@ const { title, description } = Astro.props;
padding: 1rem;
margin-block: 1rem;
border-radius: 0.5rem;
-
- box-shadow: 0 0 0 1px $accent;
-
+
&.note {
background-color: $noteBackground;
color: $noteText;
+ box-shadow: 0 0 0 1px $noteText;
+ }
+
+ &.warning {
+ background-color: $warningBackground;
+ color: $warningText;
+ box-shadow: 0 0 0 1px $warningText;
}
}
@@ -132,10 +138,15 @@ const { title, description } = Astro.props;
}
}
- main a, footer a {
+ main a {
color: $accentDark;
- transition: color 0.2s ease-in-out,
- box-shadow 0.2s ease-in-out;
+ }
+
+ footer a {
+ color: $accentLight;
+ }
+
+ main a, footer a {
text-decoration: none;
padding: 0.1rem;
box-shadow: 0 1px $accent;
@@ -145,6 +156,7 @@ const { title, description } = Astro.props;
}
&:focus {
+ color: $accentDark;
outline: none;
background-color: $secondary;
box-shadow: 0 4px #0b0c0c;
diff --git a/src/layouts/PortfolioPageLayout.astro b/src/layouts/PortfolioPageLayout.astro
new file mode 100644
index 0000000..0ade4ba
--- /dev/null
+++ b/src/layouts/PortfolioPageLayout.astro
@@ -0,0 +1,113 @@
+---
+import Layout from "./Layout.astro";
+import { useTranslations } from "../i18n";
+import TechnologyBadge from "../partials/TechnologyBadge.astro";
+
+const t = useTranslations(Astro.currentLocale);
+
+const schema = {
+ "@context": "https://schema.org",
+ "@type": "WebPage",
+ url: "https://www.costas.dev/portfolio",
+ headline: t.portfolioPage.headline,
+};
+---
+
+<Layout title={t.portfolioPage.title} description={t.portfolioPage.description}>
+ <script
+ is:inline
+ type="application/ld+json"
+ slot="head-jsonld"
+ set:html={JSON.stringify(schema)}
+ ></script>
+
+ <h1>{t.portfolioPage.headline}</h1>
+
+ <p set:html={t.portfolioPage.intro} />
+
+ <h2>{t.portfolioPage.freelanceTitle}</h2>
+
+ <p>{t.portfolioPage.freelanceDesc}</p>
+
+ <section>
+ <article>
+ <h3>{t.portfolioPage.orderExtractorTitle}</h3>
+
+ <p set:html={t.portfolioPage.orderExtractorDesc} />
+
+ <TechnologyBadge code="java" />
+ <TechnologyBadge code="windows" />
+ </article>
+
+ <article>
+ <h3>{t.portfolioPage.touristInfoTitle}</h3>
+
+ <p set:html={t.portfolioPage.touristInfoDesc} />
+
+ <TechnologyBadge code="php" />
+ <TechnologyBadge code="mysql" />
+ </article>
+
+ <article>
+ <h3>{t.portfolioPage.wpConsultingTitle}</h3>
+
+ <p set:html={t.portfolioPage.wpConsultingDesc} />
+
+ <TechnologyBadge code="php" />
+ </article>
+ </section>
+
+ <h2>{t.portfolioPage.ownProjectsTitle}</h2>
+
+ <p>{t.portfolioPage.ownProjectsDesc}</p>
+
+ <section>
+ <article>
+ <h3>{t.portfolioPage.personalWebTitle}</h3>
+
+ <p>{t.portfolioPage.personalWebDesc}</p>
+
+ <TechnologyBadge code="astro" />
+ <TechnologyBadge code="azure" />
+ </article>
+
+ <article>
+ <h3>{t.portfolioPage.mientrenoTitle}</h3>
+
+ <p set:html={t.portfolioPage.mientrenoDesc} />
+
+ <TechnologyBadge code="dotnet" />
+ <TechnologyBadge code="sqlserver" />
+ <TechnologyBadge code="azure" />
+ <TechnologyBadge code="rabbitmq" />
+ </article>
+
+ <article>
+ <h3>{t.portfolioPage.vigo360Title}</h3>
+
+ <p set:html={t.portfolioPage.vigo360Desc} />
+
+ <TechnologyBadge code="go" />
+ <TechnologyBadge code="mysql" />
+ <TechnologyBadge code="linux" />
+ </article>
+ </section>
+</Layout>
+
+<style>
+ section {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
+ gap: 1rem;
+ }
+
+ article {
+ padding: 1rem;
+ border: 1px solid var(--accent);
+ border-radius: 0.5rem;
+ }
+
+ article h3 {
+ margin-top: 0;
+ }
+</style> \ No newline at end of file
diff --git a/src/layouts/TrajectoryPageLayout.astro b/src/layouts/TrajectoryPageLayout.astro
new file mode 100644
index 0000000..1739a32
--- /dev/null
+++ b/src/layouts/TrajectoryPageLayout.astro
@@ -0,0 +1,81 @@
+---
+import { useTranslations } from "../i18n";
+import Layout from "./Layout.astro";
+
+const t = useTranslations(Astro.currentLocale);
+
+const schema = {
+ "@context": "https://schema.org",
+ "@type": "WebPage",
+ url: "https://www.costas.dev/trajectory",
+ headline: t.trajectoryPage.headline,
+};
+---
+
+<Layout title={t.trajectoryPage.title} description={t.trajectoryPage.description}>
+ <script
+ is:inline
+ type="application/ld+json"
+ slot="head-jsonld"
+ set:html={JSON.stringify(schema)}
+ />
+
+ <h1>{t.trajectoryPage.headline}</h1>
+
+ <p>{t.trajectoryPage.intro}</p>
+
+ <h2>{t.trajectoryPage.techTitle}</h2>
+
+ <p>{t.trajectoryPage.techDescription1}</p>
+
+ <p>{t.trajectoryPage.techDescription2}</p>
+
+ <h2>{t.trajectoryPage.educationTitle}</h2>
+
+ <ul>
+ <li>
+ <strong>{t.trajectoryPage.efsetCert1}</strong>
+ {t.trajectoryPage.efsetCert2} <a
+ href="https://cert.efset.org/es/Yxzc9L"
+ >{t.trajectoryPage.viewCertificate}</a
+ >
+ </li>
+
+ <li>
+ <strong>{t.trajectoryPage.azureDeveloperCert1}</strong>
+ {t.trajectoryPage.azureDeveloperCert2} <a
+ href="https://learn.microsoft.com/api/credentials/share/en-us/ariel-costas/E15072607CCF2DA9?sharingId=149A1CD9C13790F4"
+ >{t.trajectoryPage.viewCredential}</a
+ >.
+ </li>
+
+ <li>
+ <strong>{t.trajectoryPage.azureDevOpsCert1}</strong>
+ {t.trajectoryPage.azureDevOpsCert2} <a
+ href="https://learn.microsoft.com/api/credentials/share/en-us/ariel-costas/5FB94876A1701595?sharingId=149A1CD9C13790F4"
+ >{t.trajectoryPage.viewCredential}</a
+ >
+ </li>
+
+ <li>
+ <strong>{t.trajectoryPage.higherTechCert1}</strong>
+ {t.trajectoryPage.higherTechCert2} <a href="https://iesteis.es/">{t.trajectoryPage.higherTechCert3}</a> {t.trajectoryPage.higherTechCert4}
+ </li>
+ </ul>
+
+ <h2>{t.trajectoryPage.experienceTitle}</h2>
+
+ <h3>{t.trajectoryPage.estelaria1}</h3>
+
+ <p>{t.trajectoryPage.estelaria2}</p>
+
+ <p>{t.trajectoryPage.estelaria3}</p>
+
+ <h3>{t.trajectoryPage.polygon1}</h3>
+
+ <p>{t.trajectoryPage.polygon2}</p>
+
+ <h2>{t.trajectoryPage.projectsTitle}</h2>
+
+ <p set:html={t.trajectoryPage.projectsDescription} />
+</Layout>