Compare commits
8 Commits
031beba8ac
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aeb763dd43 | ||
|
|
50d8eb31d6 | ||
|
|
9e1fae4f2e | ||
|
|
d0175025ad | ||
|
|
3153200eb3 | ||
|
|
ffad0ecf54 | ||
|
|
71ad6bbc2e | ||
|
|
aa36e00576 |
58
README.md
@@ -1,50 +1,32 @@
|
|||||||
# blog
|
# apoena.dev
|
||||||
|
|
||||||
[îles]: https://github.com/ElMassimo/iles
|
Julien Calixte's blog, built with [îles](https://github.com/ElMassimo/iles).
|
||||||
[configuration reference]: https://iles-docs.netlify.app/config
|
|
||||||
|
|
||||||
This template should help get you started developing with [îles].
|
Live at [apoena.dev](https://apoena.dev).
|
||||||
|
|
||||||
## Recommended IDE Setup
|
## Requirements
|
||||||
|
|
||||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur).
|
- Node.js >= 22
|
||||||
|
- pnpm 10
|
||||||
|
|
||||||
## Type Support for `.vue` Imports in TS
|
## Scripts
|
||||||
|
|
||||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic `PageComponent` type by default. In most cases this is fine if you don't really care about component prop types outside of templates.
|
|
||||||
|
|
||||||
However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can run `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
|
||||||
|
|
||||||
## Customize configuration
|
|
||||||
|
|
||||||
See îles [Configuration Reference].
|
|
||||||
|
|
||||||
## Project Setup
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
pnpm install # install dependencies
|
||||||
|
pnpm dev # start the dev server
|
||||||
|
pnpm build # build for production
|
||||||
|
pnpm preview # preview the production build on port 5050
|
||||||
|
pnpm typecheck # run vue-tsc
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compile and Hot-Reload for Development
|
## AT Protocol notes (`/pub`)
|
||||||
|
|
||||||
```sh
|
Pages under `/pub/:rkey/:slug` are generated at build time from records
|
||||||
npm run dev
|
published to my AT Protocol repository.
|
||||||
```
|
|
||||||
|
|
||||||
### Type-Check, Compile and Minify for Production
|
- DID: `did:plc:4m3kouplb7s7xozjd3whinvl`
|
||||||
|
- Collection: `site.standard.document`
|
||||||
|
- PDS endpoint is resolved via [plc.directory](https://plc.directory),
|
||||||
|
then records are listed with `com.atproto.repo.listRecords`.
|
||||||
|
|
||||||
```sh
|
See `src/api/fetch-notes.ts` and `src/pages/pub/[rkey]/[slug].vue`.
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Unit Tests with [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/introduction)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run test:unit # or `npm run test:unit:ci` for headless testing
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run End-to-End Tests with [Cypress](https://www.cypress.io/)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run test:e2e # or `npm run test:e2e:ci` for headless testing
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ server {
|
|||||||
location / {
|
location / {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ =404;
|
try_files $uri $uri.html $uri/index.html $uri/index.htm =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /.well-known/ {
|
location /.well-known/ {
|
||||||
@@ -13,11 +13,7 @@ server {
|
|||||||
add_header Access-Control-Allow-Methods "GET, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, OPTIONS";
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 404 /404.html;
|
error_page 403 404 =302 /;
|
||||||
location = /404.html {
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
location = /50x.html {
|
location = /50x.html {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -8,7 +8,7 @@ export const getServiceEndpoint = async () => {
|
|||||||
if (serviceEndpoint) {
|
if (serviceEndpoint) {
|
||||||
return serviceEndpoint
|
return serviceEndpoint
|
||||||
}
|
}
|
||||||
const response = await fetch(`https://plc.wtf/${did}`)
|
const response = await fetch(`https://plc.directory/${did}`)
|
||||||
const {
|
const {
|
||||||
service: [{ serviceEndpoint: endpoint }],
|
service: [{ serviceEndpoint: endpoint }],
|
||||||
} = await response.json()
|
} = await response.json()
|
||||||
@@ -34,5 +34,8 @@ export const fetchNotes = async (): Promise<Note[]> => {
|
|||||||
limit: 50,
|
limit: 50,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (records || []).map((record) => record.value)
|
const notes = (records || []).map((record) => record.value as Note)
|
||||||
|
return notes.sort((a, b) =>
|
||||||
|
a.publishedAt < b.publishedAt ? 1 : a.publishedAt > b.publishedAt ? -1 : 0,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 430 B |
|
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 879 B |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -1,16 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { fetchNotes } from "@/api/fetch-notes"
|
import { fetchNotes } from "@/api/fetch-notes"
|
||||||
|
|
||||||
const notes = await fetchNotes()
|
const notes = (await fetchNotes()).slice(0, 15)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="blog-notes" v-if="notes.length > 0">
|
<div class="blog-notes" v-if="notes.length > 0">
|
||||||
<h2>Last notes</h2>
|
<h2>Last notes</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="note in notes" :key="note.href">
|
<li v-for="note in notes" :key="note.path">
|
||||||
<a :href="note.path">{{ note.title }}</a>
|
<a :href="note.path">{{ note.title }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p><a href="/pub">See all articles →</a></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
28
src/pages/pub/index.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { fetchNotes } from "@/api/fetch-notes"
|
||||||
|
|
||||||
|
const notes = await fetchNotes()
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: "Articles",
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="pub-list">
|
||||||
|
<h1>Articles</h1>
|
||||||
|
<ul>
|
||||||
|
<li v-for="note in notes" :key="note.path">
|
||||||
|
<a :href="note.path">{{ note.title }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.pub-list {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||