not fresh lol
Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
21
frontend/.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# build output
|
||||
dist/
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
13
frontend/.prettierrc
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"semi": true,
|
||||
|
||||
"plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"],
|
||||
"pluginSearchDirs": false,
|
||||
|
||||
"importOrder": ["<THIRD_PARTY_MODULES>", "^@/", "^(./)", "(.*).(css|.min.js)", "(.*).(jpeg|jpg|png|webp|gif)"],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true
|
||||
}
|
4
frontend/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
11
frontend/.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
55
frontend/README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Astro Starter Kit: Basics
|
||||
|
||||
```
|
||||
npm create astro@latest -- --template basics
|
||||
```
|
||||
|
||||
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
|
||||
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
|
||||
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
|
||||
|
||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||
|
||||
![basics](https://user-images.githubusercontent.com/4677417/186188965-73453154-fdec-4d6b-9c34-cb35c248ae5b.png)
|
||||
|
||||
|
||||
## 🚀 Project Structure
|
||||
|
||||
Inside of your Astro project, you'll see the following folders and files:
|
||||
|
||||
```
|
||||
/
|
||||
├── public/
|
||||
│ └── favicon.svg
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ │ └── Card.astro
|
||||
│ ├── layouts/
|
||||
│ │ └── Layout.astro
|
||||
│ └── pages/
|
||||
│ └── index.astro
|
||||
└── package.json
|
||||
```
|
||||
|
||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||
|
||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||
|
||||
Any static assets, like images, can be placed in the `public/` directory.
|
||||
|
||||
## 🧞 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
| Command | Action |
|
||||
| :--------------------- | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro --help` | Get help using the Astro CLI |
|
||||
|
||||
## 👀 Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
8
frontend/astro.config.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import react from '@astrojs/react';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [react(), tailwind()],
|
||||
});
|
11
frontend/lib/cms/client.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { createClient } from '@sanity/client';
|
||||
|
||||
const client = createClient({
|
||||
projectId: 'tzamgyrm',
|
||||
dataset: 'production',
|
||||
apiVersion: '2023-02-08',
|
||||
useCdn: false,
|
||||
token: import.meta.env.PUBLIC_SANITY_TOKEN,
|
||||
});
|
||||
|
||||
export default client;
|
23
frontend/lib/cms/getMostRecentRevisions.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import groq from 'groq';
|
||||
|
||||
export default function getMostRecentRevisions(filter: string) {
|
||||
return groq`
|
||||
{
|
||||
"drafts": select(
|
||||
!$live => *[
|
||||
${filter} &&
|
||||
_id in path("drafts.**")
|
||||
],
|
||||
$live => []
|
||||
),
|
||||
"published": *[
|
||||
${filter} &&
|
||||
!(_id in path("drafts.**"))
|
||||
],
|
||||
}
|
||||
{
|
||||
"current": published[
|
||||
!("drafts." + @._id in ^.drafts[]._id)
|
||||
] + drafts
|
||||
}.current[]`;
|
||||
}
|
22
frontend/lib/cms/queries/blogPosts.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import getMostRecentRevisions from '../getMostRecentRevisions';
|
||||
import groq from 'groq';
|
||||
|
||||
export const forBlogPostPage = groq`
|
||||
${getMostRecentRevisions(groq`_type == "blogPost"`)}
|
||||
{
|
||||
"slug": slug.current,
|
||||
title,
|
||||
content,
|
||||
headerImage,
|
||||
publishDate
|
||||
}`;
|
||||
|
||||
export const forBlogPage = groq`
|
||||
${getMostRecentRevisions(groq`_type == "blogPost"`)}
|
||||
{
|
||||
title,
|
||||
summary,
|
||||
publishDate,
|
||||
"slug": slug.current
|
||||
}
|
||||
`;
|
12
frontend/lib/cms/queries/libraryItems.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import getMostRecentRevisions from '../getMostRecentRevisions';
|
||||
import groq from 'groq';
|
||||
|
||||
export const forLibraryPage = groq`
|
||||
${getMostRecentRevisions(groq`_type == "libraryItem"`)}
|
||||
{
|
||||
title,
|
||||
description,
|
||||
checkedOut,
|
||||
link
|
||||
}
|
||||
`;
|
32
frontend/package.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "personal-website",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/react": "^2.1.1",
|
||||
"@astrojs/tailwind": "^3.1.1",
|
||||
"@portabletext/react": "^2.0.2",
|
||||
"@sanity/client": "^5.4.2",
|
||||
"astro": "^2.2.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@portabletext/types": "^2.0.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"groq": "^3.8.3",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier-plugin-tailwindcss": "^0.2.7",
|
||||
"tailwindcss": "^3.3.1"
|
||||
}
|
||||
}
|
3700
frontend/pnpm-lock.yaml
Normal file
6
frontend/postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
BIN
frontend/public/CV.pdf
Normal file
BIN
frontend/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
frontend/public/favicon/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
frontend/public/favicon/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 511 KiB |
BIN
frontend/public/favicon/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
frontend/public/favicon/favicon-16x16.png
Normal file
After Width: | Height: | Size: 867 B |
BIN
frontend/public/favicon/favicon-32x32.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
frontend/public/me.jpeg
Normal file
After Width: | Height: | Size: 104 KiB |
19
frontend/public/site.webmanifest
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Filipe Medeiros - website pessoal",
|
||||
"short_name": "Filipe",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/favicon/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#14B8A6",
|
||||
"background_color": "#14B8A6",
|
||||
"display": "standalone"
|
||||
}
|
29
frontend/src/components/BlogPostContent.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import {
|
||||
PortableText,
|
||||
type PortableTextBlockComponent,
|
||||
} from '@portabletext/react';
|
||||
import type { PortableTextBlock } from '@portabletext/types';
|
||||
|
||||
export interface Props {
|
||||
content: PortableTextBlock[];
|
||||
}
|
||||
|
||||
export default function BlogPostContent({ content }: Props) {
|
||||
return (
|
||||
<div className="text-justify">
|
||||
<PortableText
|
||||
components={{
|
||||
block: { h1: () => <h1>loli</h1> },
|
||||
marks: {
|
||||
code: ({ children }) => (
|
||||
<code className="bg-stone-800 p-0.5 px-1 text-white">
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
},
|
||||
}}
|
||||
value={content}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
15
frontend/src/components/ButtonLink.astro
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
import type { HTMLAttributes } from 'astro/types';
|
||||
|
||||
export type Props = HTMLAttributes<'a'>;
|
||||
---
|
||||
|
||||
<a
|
||||
class:list={[
|
||||
'bg-primary-800 text-white shadow-[5px_5px] shadow-primary-600 hover:shadow-primary-600 hover:shadow-[3px_3px] active:shadow-none',
|
||||
Astro.props.class,
|
||||
]}
|
||||
{...Astro.props}
|
||||
>
|
||||
<slot />
|
||||
</a>
|
32
frontend/src/components/CardLink.astro
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
export interface Props {
|
||||
link: string;
|
||||
}
|
||||
|
||||
const random = Math.round(Math.random() * 10) % 4;
|
||||
|
||||
const { link } = Astro.props;
|
||||
---
|
||||
|
||||
<li
|
||||
class:list={[
|
||||
'border-primary-800 border-2 w-96 max-w-full mb-3 group/card',
|
||||
{
|
||||
'hover:shadow-[-3px_-3px] over:shadow-primary-800 ctive:shadow-[-5px_-5px] ctive:shadow-primary-800':
|
||||
random === 0,
|
||||
'hover:shadow-[-3px_3px] hover:shadow-primary-800 active:shadow-[-5px_5px] active:shadow-primary-800':
|
||||
random === 1,
|
||||
'hover:shadow-[3px_-3px] hover:shadow-primary-800 active:shadow-[5px_-5px] active:shadow-primary-800':
|
||||
random === 2,
|
||||
'hover:shadow-[3px_3px] hover:shadow-primary-800 active:shadow-[5px_5px] active:shadow-primary-800':
|
||||
random === 3,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<a href={link} class="px-4 py-3 block">
|
||||
<slot />
|
||||
<div class="flex justify-end">
|
||||
<span class="pr-3 text-xl group-hover/card:pr-0">→</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
13
frontend/src/components/InlineLink.astro
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
import type { HTMLAttributes } from 'astro/types';
|
||||
|
||||
export type Props = HTMLAttributes<'a'>;
|
||||
---
|
||||
|
||||
<a
|
||||
class:list={[
|
||||
'text-primary-800 underline hover:text-primary-700',
|
||||
Astro.props.class,
|
||||
]}
|
||||
{...Astro.props}><slot /></a
|
||||
>
|
12
frontend/src/components/PageTitle.astro
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
import type { HTMLAttributes } from 'astro/types';
|
||||
|
||||
export type Props = HTMLAttributes<'h1'>;
|
||||
---
|
||||
|
||||
<h1
|
||||
class:list={['text-primary-800 font-bold text-4xl', Astro.props.class]}
|
||||
{...Astro.props}
|
||||
>
|
||||
<slot />
|
||||
</h1>
|
1
frontend/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/// <reference types="astro/client" />
|
39
frontend/src/layouts/Layout.astro
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
import InlineLink from '../components/InlineLink.astro';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
const { footer } = Astro.slots;
|
||||
const hasFooter = !!footer;
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/favicon" href="/favicon.ico" />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body class="bg-orange-50 font-serif">
|
||||
<main class:list={['px-6 pt-4 md:px-20 md:pt-6', hasFooter && 'mb-32']}>
|
||||
<slot />
|
||||
</main>
|
||||
{
|
||||
hasFooter && (
|
||||
<footer class="fixed bottom-0 p-4 pb-0 flex flex-col w-full gap-2">
|
||||
<slot name="footer" />
|
||||
<div class="flex gap-3 justify-end bg-orange-50 pb-2">
|
||||
<InlineLink href="https://mastodon.green/@filipesm">
|
||||
Mastodon
|
||||
</InlineLink>
|
||||
<InlineLink href="https://codeberg/filipesm">Codeberg</InlineLink>
|
||||
<InlineLink href="https://bandcamp/filipesm">Bandcamp</InlineLink>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
</body>
|
||||
</html>
|
58
frontend/src/pages/biblioteca/index.astro
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
import client from '../../../lib/cms/client';
|
||||
import { forLibraryPage } from '../../../lib/cms/queries/libraryItems';
|
||||
import ButtonLink from '../../components/ButtonLink.astro';
|
||||
import CardLink from '../../components/CardLink.astro';
|
||||
import PageTitle from '../../components/PageTitle.astro';
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
const libraryItems: {
|
||||
description: string;
|
||||
checkedOut: boolean;
|
||||
link: string;
|
||||
title: string;
|
||||
}[] = await client.fetch(forLibraryPage, {
|
||||
live: !import.meta.env.DEV,
|
||||
});
|
||||
---
|
||||
|
||||
<Layout title="Biblioteca - Filipe Medeiros">
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Biblioteca</PageTitle>
|
||||
<h2>
|
||||
Livros, artigos, <span class="italic">etc.</span> que já li e que recomendo
|
||||
ou que quero ler num futuro próximo. Se um item tiver uma marca "<span
|
||||
class="text-primary-700">✓</span
|
||||
>", siginifca que eu já li, vi, etc.
|
||||
</h2>
|
||||
</header>
|
||||
<ol>
|
||||
{
|
||||
libraryItems.map(({ title, description, link, checkedOut }) => (
|
||||
<CardLink link={link}>
|
||||
<span class="text-lg md:text-xl font-medium break-words text-primary-700 block mb-3">
|
||||
{title}
|
||||
</span>
|
||||
<p class="mb-5">{description}</p>
|
||||
{checkedOut && <span class="text-primary-700 text-3xl">✓</span>}
|
||||
</CardLink>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Início
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
53
frontend/src/pages/blog/[slug]/index.astro
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
import type { PortableTextBlock } from '@portabletext/types';
|
||||
import client from '../../../../lib/cms/client';
|
||||
import { forBlogPostPage } from '../../../../lib/cms/queries/blogPosts';
|
||||
import BlogPostContent from '../../../components/BlogPostContent';
|
||||
import ButtonLink from '../../../components/ButtonLink.astro';
|
||||
import PageTitle from '../../../components/PageTitle.astro';
|
||||
import Layout from '../../../layouts/Layout.astro';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts: {
|
||||
slug: string;
|
||||
title: string;
|
||||
content: PortableTextBlock[];
|
||||
publishDate: string;
|
||||
}[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV });
|
||||
|
||||
return posts.map(({ slug, title, content, publishDate }) => {
|
||||
return {
|
||||
params: { slug },
|
||||
props: { title, content, publishDate },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { title, content, publishDate } = Astro.props;
|
||||
---
|
||||
|
||||
<Layout title={`${title} - Filipe Medeiros`}>
|
||||
<article class="max-w-prose m-auto">
|
||||
<header class="mb-5">
|
||||
<PageTitle class="mb-2 break-words">{title}</PageTitle>
|
||||
<time datetime={publishDate} class="text-xl">{publishDate}</time>
|
||||
</header>
|
||||
<BlogPostContent content={content} />
|
||||
</article>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
55
frontend/src/pages/blog/index.astro
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
import client from '../../../lib/cms/client';
|
||||
import { forBlogPage } from '../../../lib/cms/queries/blogPosts';
|
||||
import ButtonLink from '../../components/ButtonLink.astro';
|
||||
import CardLink from '../../components/CardLink.astro';
|
||||
import PageTitle from '../../components/PageTitle.astro';
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
const posts: {
|
||||
title: string;
|
||||
publishDate: string;
|
||||
summary: string;
|
||||
slug: string;
|
||||
}[] = await client.fetch(forBlogPage, { live: !import.meta.env.DEV });
|
||||
---
|
||||
|
||||
<Layout title="Blog - Filipe Medeiros">
|
||||
<header class="mb-10">
|
||||
<PageTitle class="mb-3">Blog</PageTitle>
|
||||
<h2>Uma coleção de artigos que vou escrevendo. Sobretudo por diversão.</h2>
|
||||
</header>
|
||||
<ol>
|
||||
{
|
||||
posts.map(({ title, slug, publishDate, summary }) => (
|
||||
<CardLink link={`/blog/${slug}`}>
|
||||
<article class="flex flex-col">
|
||||
<span class="text-lg md:text-xl font-medium break-words text-primary-700">
|
||||
{title}
|
||||
</span>
|
||||
<time datetime={publishDate} class="text-sm text-primary-800">
|
||||
{publishDate}
|
||||
</time>
|
||||
<span>{summary}</span>
|
||||
</article>
|
||||
</CardLink>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Início
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
88
frontend/src/pages/index.astro
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
import ButtonLink from '../components/ButtonLink.astro';
|
||||
import InlineLink from '../components/InlineLink.astro';
|
||||
import PageTitle from '../components/PageTitle.astro';
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
---
|
||||
|
||||
<Layout title="Página inicial - Filipe Medeiros">
|
||||
<PageTitle class="mb-10">
|
||||
Filipe<br />Medeiros
|
||||
</PageTitle>
|
||||
|
||||
<div class="max-w-[60ch]">
|
||||
<p class="mb-3">
|
||||
Sou um engenheiro de <InlineLink
|
||||
href="https://www.usability.gov/what-and-why/user-experience.html"
|
||||
class="italic"
|
||||
>
|
||||
UX
|
||||
</InlineLink> (não me perguntem o que é, que nem eu sei bem).
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Gosto de programar interfaces e aplicações web, mas também de política, de
|
||||
ler sobre economia e de animais. Não gosto de cozinhar (ainda) nem de
|
||||
vento frio.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Estou a tentar trazer à superfície o potencial da humanidade. Sou a favor
|
||||
de <InlineLink href="https://www.w3.org/standards/faq#std" class="italic">
|
||||
standards
|
||||
</InlineLink>, software de código aberto (<InlineLink
|
||||
href="https://codeberg.org/filipesm/personal-website"
|
||||
>
|
||||
como é este site!
|
||||
</InlineLink>), <InlineLink href="https://pt.wikipedia.org/wiki/Copyleft">
|
||||
licenças <span class="italic">copyleft</span>
|
||||
</InlineLink>
|
||||
e de
|
||||
<InlineLink
|
||||
href="https://www.ica.coop/en/cooperatives/what-is-a-cooperative"
|
||||
>
|
||||
cooperativas
|
||||
</InlineLink> em vez de monopólios.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Sou apaixonado pela <InlineLink
|
||||
href="https://doughnuteconomics.org/about-doughnut-economics"
|
||||
class="italic"
|
||||
>
|
||||
Economia do Donut
|
||||
</InlineLink> e por economia social e ambiental. Gostava de, um dia, ser economista
|
||||
em vez de programador. Quem sabe, para a União Europeia.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Moro em <InlineLink href="https://www.oeiras.pt">
|
||||
Oeiras, Lisboa, Portugal
|
||||
</InlineLink>.
|
||||
</p>
|
||||
<p class="mb-3">
|
||||
Se quiseres ver, tens <InlineLink href="/me.jpeg">aqui</InlineLink> uma foto
|
||||
minha!
|
||||
</p>
|
||||
<p>
|
||||
Este site tenta ser o mais sustentável possível: poupamos energia no teu
|
||||
dispositivo e em servidores. Teve muita inspiração da{' '}
|
||||
<InlineLink href="https://solar.lowtechmagazine.com">
|
||||
versão solar da Low Tech Magazine
|
||||
</InlineLink>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Fragment slot="footer">
|
||||
<nav class="flex gap-4">
|
||||
<ButtonLink
|
||||
href="/blog"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Blog
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
href="/biblioteca"
|
||||
class="text-3xl flex-1 py-2 flex justify-center px-2"
|
||||
>
|
||||
Biblioteca
|
||||
</ButtonLink>
|
||||
</nav>
|
||||
</Fragment>
|
||||
</Layout>
|
23
frontend/tailwind.config.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#e5fff7',
|
||||
100: '#b3ffe8',
|
||||
200: '#80ffd8',
|
||||
300: '#4dffc9',
|
||||
400: '#1affb9',
|
||||
500: '#00e6a0',
|
||||
600: '#00b37c',
|
||||
700: '#008059',
|
||||
800: '#004d35',
|
||||
900: '#001a12',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
7
frontend/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "react"
|
||||
}
|
||||
}
|