Compare commits
7 Commits
1ff33bfd64
...
d54aabd621
Author | SHA1 | Date | |
---|---|---|---|
d54aabd621 | |||
24d558e0f5 | |||
bc36bdec90 | |||
1b54860f93 | |||
37f9b36b2f | |||
4b447369c2 | |||
cf1147204c |
178
.drone.yml
178
.drone.yml
@ -1,178 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: CD
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: restore cache node
|
|
||||||
image: drillster/drone-volume-cache
|
|
||||||
volumes:
|
|
||||||
- name: main-website-node
|
|
||||||
path: /cache/phundrak.com/node
|
|
||||||
settings:
|
|
||||||
restore: true
|
|
||||||
mount:
|
|
||||||
- ./node_modules
|
|
||||||
|
|
||||||
- name: restore cache emacs
|
|
||||||
image: drillster/drone-volume-cache
|
|
||||||
volumes:
|
|
||||||
- name: main-website-emacs
|
|
||||||
path: /cache/phundrak.com/emacs
|
|
||||||
settings:
|
|
||||||
restore: true
|
|
||||||
mount:
|
|
||||||
- /var/emacs
|
|
||||||
|
|
||||||
- name: generate emacs
|
|
||||||
image: silex/emacs:master-alpine
|
|
||||||
commands:
|
|
||||||
- mkdir -p /var/emacs
|
|
||||||
- apk update && apk add git
|
|
||||||
- emacs --init-directory=/var/emacs --script export.el
|
|
||||||
depends_on:
|
|
||||||
- "restore cache emacs"
|
|
||||||
|
|
||||||
- name: generate node
|
|
||||||
image: node:19-alpine
|
|
||||||
commands:
|
|
||||||
- yarn install
|
|
||||||
- yarn build
|
|
||||||
depends_on:
|
|
||||||
- "restore cache node"
|
|
||||||
- "generate emacs"
|
|
||||||
|
|
||||||
- name: rebuild cache emacs
|
|
||||||
image: drillster/drone-volume-cache
|
|
||||||
volumes:
|
|
||||||
- name: conlang-emacs
|
|
||||||
path: /cache/conlang/emacs
|
|
||||||
settings:
|
|
||||||
rebuild: true
|
|
||||||
mount:
|
|
||||||
- /var/emacs
|
|
||||||
depends_on:
|
|
||||||
- "generate emacs"
|
|
||||||
|
|
||||||
- name: rebuild cache node
|
|
||||||
image: drillster/drone-volume-cache
|
|
||||||
volumes:
|
|
||||||
- name: main-website-node
|
|
||||||
path: /cache/phundrak.com/node
|
|
||||||
settings:
|
|
||||||
rebuild: true
|
|
||||||
mount:
|
|
||||||
- ./node_modules
|
|
||||||
depends_on:
|
|
||||||
- "generate node"
|
|
||||||
|
|
||||||
- name: deploy web stable
|
|
||||||
image: appleboy/drone-scp
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: ssh_host
|
|
||||||
target:
|
|
||||||
from_secret: ssh_target
|
|
||||||
source: content/.vuepress/dist/*
|
|
||||||
strip_components: 3
|
|
||||||
username:
|
|
||||||
from_secret: ssh_username
|
|
||||||
password:
|
|
||||||
from_secret: ssh_password
|
|
||||||
port:
|
|
||||||
from_secret: ssh_port
|
|
||||||
depends_on:
|
|
||||||
- "generate node"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- main
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
- name: deploy gemini
|
|
||||||
image: appleboy/drone-scp
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: ssh_host
|
|
||||||
target:
|
|
||||||
from_secret: ssh_target_gemini
|
|
||||||
source: gemini/*
|
|
||||||
strip_components: 1
|
|
||||||
username:
|
|
||||||
from_secret: ssh_username
|
|
||||||
password:
|
|
||||||
from_secret: ssh_password
|
|
||||||
port:
|
|
||||||
from_secret: ssh_port
|
|
||||||
depends_on:
|
|
||||||
- "generate emacs"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- main
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
- name: purge cache stable
|
|
||||||
image: jetrails/drone-cloudflare-caching
|
|
||||||
settings:
|
|
||||||
api_token:
|
|
||||||
from_secret: cloudflare_cache_api
|
|
||||||
zone_identifier:
|
|
||||||
from_secret: phundrak_com_zone_id
|
|
||||||
action: purge_files
|
|
||||||
list:
|
|
||||||
- https://beta.phundrak.com
|
|
||||||
depends_on:
|
|
||||||
- "deploy web stable"
|
|
||||||
- "deploy gemini"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- main
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
- name: deploy web devel
|
|
||||||
image: appleboy/drone-scp
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: ssh_host
|
|
||||||
target:
|
|
||||||
from_secret: ssh_target_devel
|
|
||||||
source: content/.vuepress/dist/*
|
|
||||||
strip_components: 3
|
|
||||||
username:
|
|
||||||
from_secret: ssh_username
|
|
||||||
password:
|
|
||||||
from_secret: ssh_password
|
|
||||||
port:
|
|
||||||
from_secret: ssh_port
|
|
||||||
depends_on:
|
|
||||||
- "generate node"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- devel
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
- name: purge cache devel
|
|
||||||
image: jetrails/drone-cloudflare-caching
|
|
||||||
settings:
|
|
||||||
api_token:
|
|
||||||
from_secret: cloudflare_cache_api
|
|
||||||
zone_identifier:
|
|
||||||
from_secret: phundrak_com_zone_id
|
|
||||||
action: purge_files
|
|
||||||
list:
|
|
||||||
- https://alpha.phundrak.com
|
|
||||||
depends_on:
|
|
||||||
- "deploy web devel"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- devel
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- pull_request
|
|
41
.gitea/workflows/deploy.yaml
Normal file
41
.gitea/workflows/deploy.yaml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: deploy
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22.x
|
||||||
|
- run: npm ci
|
||||||
|
- uses: purcell/setup-emacs@master
|
||||||
|
with:
|
||||||
|
version: 29.1
|
||||||
|
- name: "Export org to md"
|
||||||
|
run: emacs -Q --script export.el
|
||||||
|
- run: npm run build
|
||||||
|
- name: "Deploy on the Web"
|
||||||
|
uses: appleboy/scp-action@v0.1.7
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: content/.vuepress/dist/*
|
||||||
|
target: ${{ secrets.DESTPATH }}
|
||||||
|
strip_components: 3
|
||||||
|
- name: "Deploy on Gemini"
|
||||||
|
uses: appleboy/scp-action@v0.1.7
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.KEY }}
|
||||||
|
port: ${{ secrets.PORT }}
|
||||||
|
source: gemini/*
|
||||||
|
target: ${{ secrets.DESTPATH_GMI }}
|
||||||
|
strip_components: 1
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ node_modules
|
|||||||
.cache
|
.cache
|
||||||
/content/.vuepress/dist/*
|
/content/.vuepress/dist/*
|
||||||
*.md
|
*.md
|
||||||
|
/.yarn/
|
||||||
|
3
.yarnrc.yml
Normal file
3
.yarnrc.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
enableMessageNames: false
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
@ -4,9 +4,8 @@ import ListRepositories from './components/GitHub/ListRepositories.vue';
|
|||||||
import FetchRepositories from './components/GitHub/FetchRepositories.vue';
|
import FetchRepositories from './components/GitHub/FetchRepositories.vue';
|
||||||
import GithubRepository from './components/GitHub/GithubRepository.vue';
|
import GithubRepository from './components/GitHub/GithubRepository.vue';
|
||||||
import ApiLoader from './components/ApiLoader.vue';
|
import ApiLoader from './components/ApiLoader.vue';
|
||||||
import Loader from './components/Loader.vue';
|
import LoaderAnimation from './components/LoaderAnimation.vue';
|
||||||
import Cache from './components/Cache.vue';
|
import FetchError from './components/FetchError.vue';
|
||||||
import Error from './components/Error.vue';
|
|
||||||
import Icon from './components/Icon.vue';
|
import Icon from './components/Icon.vue';
|
||||||
|
|
||||||
export default defineClientConfig({
|
export default defineClientConfig({
|
||||||
@ -16,9 +15,8 @@ export default defineClientConfig({
|
|||||||
app.component('FetchRepositories', FetchRepositories);
|
app.component('FetchRepositories', FetchRepositories);
|
||||||
app.component('GithubRepository', GithubRepository);
|
app.component('GithubRepository', GithubRepository);
|
||||||
app.component('ApiLoader', ApiLoader);
|
app.component('ApiLoader', ApiLoader);
|
||||||
app.component('Loader', Loader);
|
app.component('LoaderAnimation', LoaderAnimation);
|
||||||
app.component('Cache', Cache);
|
app.component('FetchError', FetchError);
|
||||||
app.component('Error', Error);
|
|
||||||
app.component('Icon', Icon);
|
app.component('Icon', Icon);
|
||||||
},
|
},
|
||||||
setup() {},
|
setup() {},
|
||||||
|
@ -1,31 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<Cache
|
|
||||||
:name="props.cacheName"
|
|
||||||
:callback="fetchData"
|
|
||||||
:already-known-data="alreadyKnownData"
|
|
||||||
@cached="processCachedData"
|
|
||||||
/>
|
|
||||||
<slot v-if="loading" name="loader">
|
<slot v-if="loading" name="loader">
|
||||||
<Loader />
|
<LoaderAnimation />
|
||||||
</slot>
|
</slot>
|
||||||
<slot v-else-if="error" name="error">
|
<slot v-else-if="error" name="error">
|
||||||
<Error :url="props.url" />
|
<FetchError :url="props.url" />
|
||||||
</slot>
|
</slot>
|
||||||
<slot v-else> </slot>
|
<slot v-else> </slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Cache from './Cache.vue';
|
import LoaderAnimation from './LoaderAnimation.vue';
|
||||||
import Loader from './Loader.vue';
|
import FetchError from './FetchError.vue';
|
||||||
import Error from './Error.vue';
|
|
||||||
|
|
||||||
import { Ref, ref } from 'vue';
|
import { useFetchAndCache } from '../composables/fetchAndCache';
|
||||||
import { Observable, catchError, switchMap, throwError } from 'rxjs';
|
|
||||||
import { fromFetch } from 'rxjs/fetch';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
url: {
|
url: {
|
||||||
default: false,
|
default: '',
|
||||||
required: true,
|
required: true,
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@ -35,31 +26,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
alreadyKnownData: Object,
|
alreadyKnownData: Object,
|
||||||
});
|
});
|
||||||
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
|
|
||||||
|
|
||||||
const error: Ref<Error> = ref(null);
|
const emits = defineEmits(['loaded', 'error', 'loading']);
|
||||||
const loading: Ref<boolean> = ref(true);
|
|
||||||
|
|
||||||
const fetchData = (): Observable<any> => {
|
const { loading, error } = useFetchAndCache(props.url, {
|
||||||
return fromFetch(props.url).pipe(
|
emits: emits,
|
||||||
switchMap((response: Response) => response.json()),
|
cacheName: props.cacheName,
|
||||||
catchError((errorResponse: Error) => {
|
});
|
||||||
error.value = errorResponse;
|
|
||||||
return Error;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const processCachedData = (data: Observable<any>) => {
|
|
||||||
data.subscribe({
|
|
||||||
next: (response: any) => {
|
|
||||||
loading.value = false;
|
|
||||||
emits('dataLoaded', response);
|
|
||||||
},
|
|
||||||
error: (responseError: Error) => {
|
|
||||||
loading.value = false;
|
|
||||||
error.value = responseError;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
<template>
|
|
||||||
<slot />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { Observable, of, tap } from 'rxjs';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
name: {
|
|
||||||
required: true,
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
callback: {
|
|
||||||
required: true,
|
|
||||||
type: Function,
|
|
||||||
},
|
|
||||||
lifetime: {
|
|
||||||
default: 1000 * 60 * 60, // one hour
|
|
||||||
required: false,
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
alreadyKnownData: {
|
|
||||||
default: null,
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const emits = defineEmits(['cached']);
|
|
||||||
|
|
||||||
const isDataOutdated = (name: string): boolean => {
|
|
||||||
const lastUpdated: number = +localStorage.getItem(name + '-timestamp');
|
|
||||||
const elapsedTime: number = Date.now() - lastUpdated;
|
|
||||||
return elapsedTime > props.lifetime;
|
|
||||||
};
|
|
||||||
|
|
||||||
const storeInCache = (
|
|
||||||
callback: Function,
|
|
||||||
data: any,
|
|
||||||
name: string,
|
|
||||||
): Observable<any> => {
|
|
||||||
let response: Observable<any> = data ? of(data) : callback();
|
|
||||||
return response.pipe(
|
|
||||||
tap((response) => {
|
|
||||||
localStorage.setItem(name, JSON.stringify(response));
|
|
||||||
localStorage.setItem(name + '-timestamp', `${Date.now()}`);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isDataOutdated(props.name)) {
|
|
||||||
emits(
|
|
||||||
'cached',
|
|
||||||
storeInCache(props.callback, props.alreadyKnownData, props.name),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let data = localStorage.getItem(props.name);
|
|
||||||
try {
|
|
||||||
emits('cached', of(JSON.parse(data)));
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Could not parse data found in cache: ${err}`);
|
|
||||||
emits(
|
|
||||||
'cached',
|
|
||||||
storeInCache(props.callback, props.alreadyKnownData, props.name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos" />
|
<ApiLoader :url="fetchUrl" @loaded="filterRepos" cache-name="repos" />
|
||||||
<slot />
|
<slot />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType } from 'vue';
|
import { PropType, ref } from 'vue';
|
||||||
import { GithubRepo } from '../../composables/github';
|
import { GithubRepo } from '../../types/github';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sortBy: {
|
sortBy: {
|
||||||
default: 'none',
|
default: 'none',
|
||||||
@ -23,15 +23,12 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const emits = defineEmits(['loaded']);
|
||||||
const emits = defineEmits(['dataLoaded']);
|
|
||||||
|
|
||||||
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
|
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
|
||||||
|
const repos = ref<GithubRepo[]>([]);
|
||||||
|
|
||||||
const filterRepos = (response: GithubRepo[]) => {
|
const filterRepos = (response: GithubRepo[]) => {
|
||||||
emits(
|
repos.value = response
|
||||||
'dataLoaded',
|
|
||||||
response
|
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (props.sortBy === 'stars') {
|
if (props.sortBy === 'stars') {
|
||||||
return b.stargazers_count - a.stargazers_count;
|
return b.stargazers_count - a.stargazers_count;
|
||||||
@ -43,7 +40,7 @@ const filterRepos = (response: GithubRepo[]) => {
|
|||||||
}
|
}
|
||||||
return b.forks_count - a.forks_count;
|
return b.forks_count - a.forks_count;
|
||||||
})
|
})
|
||||||
.slice(0, +props.limit)
|
.slice(0, +props.limit);
|
||||||
);
|
emits('loaded', repos.value);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -6,23 +6,23 @@
|
|||||||
:cache-name="repoName()"
|
:cache-name="repoName()"
|
||||||
:url="fetchUrl"
|
:url="fetchUrl"
|
||||||
:already-known-data="props.data"
|
:already-known-data="props.data"
|
||||||
@data-loaded="(repo: GithubRepo) => (repository = repo)"
|
@loaded="(repo: GithubRepo) => (repository = repo)"
|
||||||
>
|
>
|
||||||
<h3>{{ repository.name }}</h3>
|
<h3>{{ repository?.name }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{{ repository.description }}
|
{{ repository?.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row flex-start gap-1rem stats">
|
<div class="flex-row flex-start gap-1rem stats">
|
||||||
<div class="stars">
|
<div class="stars">
|
||||||
<Icon name="star" /> {{ repository.stargazers_count }}
|
<Icon name="star" /> {{ repository?.stargazers_count }}
|
||||||
</div>
|
</div>
|
||||||
<div class="forks">
|
<div class="forks">
|
||||||
<Icon name="fork" /> {{ repository.forks_count }}
|
<Icon name="fork" /> {{ repository?.forks_count }}
|
||||||
</div>
|
</div>
|
||||||
<div class="link">
|
<div class="link">
|
||||||
<a :href="repository.html_url"><i class="icon phunic-link" /></a>
|
<a :href="repository?.html_url"><i class="icon phunic-link" /></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ApiLoader>
|
</ApiLoader>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ApiLoader from '../ApiLoader.vue';
|
import ApiLoader from '../ApiLoader.vue';
|
||||||
|
|
||||||
import { GithubRepo } from '../../composables/github';
|
import { GithubRepo } from '../../types/github';
|
||||||
import { PropType, Ref, ref } from 'vue';
|
import { PropType, Ref, ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -45,7 +45,7 @@ const repoName = (): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchUrl = `https://api.github.com/repos/${repoName()}`;
|
const fetchUrl = `https://api.github.com/repos/${repoName()}`;
|
||||||
const repository: Ref<GithubRepo> = ref(null);
|
const repository: Ref<GithubRepo | null> = ref(null);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@ -78,5 +78,12 @@ const repository: Ref<GithubRepo> = ref(null);
|
|||||||
gap: 0.3rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
:sort-by="props.sortBy"
|
:sort-by="props.sortBy"
|
||||||
:user="props.user"
|
:user="props.user"
|
||||||
:limit="props.limit"
|
:limit="props.limit"
|
||||||
@data-loaded="(response: GithubRepo[]) => (repos = response)"
|
@loaded="(response: GithubRepo[]) => (repos = response)"
|
||||||
>
|
>
|
||||||
<GithubRepository
|
<GithubRepository
|
||||||
:data="repo"
|
:data="repo"
|
||||||
@ -22,7 +22,7 @@ import FetchRepositories from './FetchRepositories.vue';
|
|||||||
import GithubRepository from './GithubRepository.vue';
|
import GithubRepository from './GithubRepository.vue';
|
||||||
|
|
||||||
import { PropType, Ref, ref } from 'vue';
|
import { PropType, Ref, ref } from 'vue';
|
||||||
import { GithubRepo } from '../../composables/github';
|
import { GithubRepo } from '../../types/github';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sortBy: {
|
sortBy: {
|
||||||
|
62
content/.vuepress/composables/cache.ts
Normal file
62
content/.vuepress/composables/cache.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Ref, computed, ref, watchEffect } from 'vue';
|
||||||
|
|
||||||
|
interface CacheOptions {
|
||||||
|
lifetime?: number;
|
||||||
|
timestampSuffix?: string;
|
||||||
|
forceUpdate?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache data in local storage.
|
||||||
|
*
|
||||||
|
* The cache is updated if:
|
||||||
|
* - cache data does not exist
|
||||||
|
* - cached data is outdated and `data` is not null
|
||||||
|
* - or `options.forceUpdate` is true, regardless of the value of `data`
|
||||||
|
*
|
||||||
|
* Otherwise, data is retrieved from cache.
|
||||||
|
*
|
||||||
|
* @param {string} name Name of the cached value in local storage
|
||||||
|
* @param {Ref<T>} data Data to cache
|
||||||
|
* @param {CacheOptions} options Tweaks to the behaviour of the function
|
||||||
|
*/
|
||||||
|
export const useCache = <T>(
|
||||||
|
name: string,
|
||||||
|
data: Ref<T>,
|
||||||
|
options: CacheOptions,
|
||||||
|
) => {
|
||||||
|
const error = ref<string>(null);
|
||||||
|
const timestampName = name + (options?.timestampSuffix || '-timestamp');
|
||||||
|
const lifetime = options?.lifetime || 1000 * 60 * 60; // one hour in milliseconds
|
||||||
|
const lastUpdated: number = +localStorage.getItem(timestampName);
|
||||||
|
const cacheAge: number = Date.now() - lastUpdated;
|
||||||
|
const isDataOutdated = computed(() => {
|
||||||
|
return cacheAge > lifetime;
|
||||||
|
});
|
||||||
|
const shouldUpdate = computed(
|
||||||
|
() => options?.forceUpdate || (isDataOutdated.value && data.value != null),
|
||||||
|
);
|
||||||
|
|
||||||
|
const setData = () => {
|
||||||
|
console.log('Setting data in cache with name', name);
|
||||||
|
localStorage.setItem(name, JSON.stringify(data.value));
|
||||||
|
localStorage.setItem(timestampName, `${Date.now()}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getData = () => {
|
||||||
|
console.log('Getting data from cache with name', name);
|
||||||
|
const cached = localStorage.getItem(name);
|
||||||
|
console.log('Value from storage:', cached);
|
||||||
|
try {
|
||||||
|
data.value = JSON.parse(cached);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to parse cached data:', err);
|
||||||
|
data.value = null;
|
||||||
|
error.value = err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getData();
|
||||||
|
watchEffect(() => (shouldUpdate.value ? setData() : getData()));
|
||||||
|
return { error, isDataOutdated };
|
||||||
|
};
|
72
content/.vuepress/composables/fetchAndCache.ts
Normal file
72
content/.vuepress/composables/fetchAndCache.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { ref, Ref } from 'vue';
|
||||||
|
import { useCache } from './cache';
|
||||||
|
|
||||||
|
type FetchAndCacheEmitter = (
|
||||||
|
event: 'loaded' | 'error' | 'loading',
|
||||||
|
...args: any[]
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
interface UseFetchAndCacheOptions {
|
||||||
|
cacheLifetime?: number;
|
||||||
|
cacheName?: string;
|
||||||
|
emits?: FetchAndCacheEmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dummyEmits = (
|
||||||
|
_event: 'loaded' | 'error' | 'loading',
|
||||||
|
..._args: any[]
|
||||||
|
) => {};
|
||||||
|
|
||||||
|
export const useFetchAndCache = <T, E>(
|
||||||
|
url: string,
|
||||||
|
options?: UseFetchAndCacheOptions,
|
||||||
|
) => {
|
||||||
|
const data = ref<T | null>(null) as Ref<T>;
|
||||||
|
const error = ref<E | null>(null) as Ref<E>;
|
||||||
|
const loading = ref<boolean>(true);
|
||||||
|
const cacheLifetime: number = options?.cacheLifetime || 1000 * 60 * 60; // one hour
|
||||||
|
const cacheName: string = options?.cacheName || url;
|
||||||
|
const { isDataOutdated: isCacheOutdated, error: cacheError } = useCache(
|
||||||
|
cacheName,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
lifetime: cacheLifetime,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const emits: FetchAndCacheEmitter = options?.emits || dummyEmits;
|
||||||
|
|
||||||
|
const loaded = () => {
|
||||||
|
loading.value = false;
|
||||||
|
emits('loaded', data.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchData = () => {
|
||||||
|
loading.value = true;
|
||||||
|
emits('loading');
|
||||||
|
console.log('Fetching from URL', url);
|
||||||
|
fetch(url)
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText);
|
||||||
|
}
|
||||||
|
return response.json() as Promise<T>;
|
||||||
|
})
|
||||||
|
.then((responseData) => {
|
||||||
|
data.value = responseData;
|
||||||
|
loaded();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.warn('Caught error!', e);
|
||||||
|
error.value = e;
|
||||||
|
emits('error', e);
|
||||||
|
})
|
||||||
|
.finally(() => (loading.value = false));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isCacheOutdated.value || cacheError.value != null) {
|
||||||
|
fetchData();
|
||||||
|
} else {
|
||||||
|
loaded();
|
||||||
|
}
|
||||||
|
return { data, loading, error };
|
||||||
|
};
|
@ -1,24 +1,46 @@
|
|||||||
import { defineUserConfig, defaultTheme } from 'vuepress';
|
import { defaultTheme } from '@vuepress/theme-default';
|
||||||
import { removeHtmlExtensionPlugin } from 'vuepress-plugin-remove-html-extension';
|
import { viteBundler } from '@vuepress/bundler-vite';
|
||||||
import head from './head';
|
import { defineUserConfig } from 'vuepress';
|
||||||
import locales from './locales';
|
import { searchProPlugin } from 'vuepress-plugin-search-pro';
|
||||||
|
import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics';
|
||||||
|
|
||||||
|
import { head } from './head';
|
||||||
|
import { locales, searchLocales } from './locales';
|
||||||
import { themeLocales } from './themeLocales';
|
import { themeLocales } from './themeLocales';
|
||||||
|
|
||||||
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
export default defineUserConfig({
|
export default defineUserConfig({
|
||||||
lang: 'fr-FR',
|
lang: 'fr-FR',
|
||||||
title: 'Lucien Cartier-Tilet',
|
title: 'Lucien Cartier-Tilet',
|
||||||
description: 'Site web personnel de Lucien Cartier-Tilet',
|
description: 'Site web personnel de Lucien Cartier-Tilet',
|
||||||
head: head,
|
head: head,
|
||||||
|
bundler: viteBundler({}),
|
||||||
markdown: {
|
markdown: {
|
||||||
html: true,
|
html: true,
|
||||||
linkify: true,
|
linkify: true,
|
||||||
typographer: true,
|
typographer: true,
|
||||||
},
|
},
|
||||||
plugins: [removeHtmlExtensionPlugin()],
|
plugins: [
|
||||||
|
searchProPlugin({
|
||||||
|
indexContent: true,
|
||||||
|
locales: searchLocales,
|
||||||
|
}),
|
||||||
|
isProd
|
||||||
|
? umamiAnalyticsPlugin({
|
||||||
|
id: '67166941-8c83-4a19-bc8c-139e44b7f7aa',
|
||||||
|
link: 'https://umami.phundrak.com/script.js',
|
||||||
|
})
|
||||||
|
: [],
|
||||||
|
],
|
||||||
locales: locales,
|
locales: locales,
|
||||||
theme: defaultTheme({
|
theme: defaultTheme({
|
||||||
contributors: false,
|
contributors: false,
|
||||||
locales: themeLocales,
|
locales: themeLocales,
|
||||||
repo: 'https://labs.phundrak.com/phundrak/phundrak.com',
|
repo: 'https://labs.phundrak.com/phundrak/phundrak.com',
|
||||||
|
themePlugins: {
|
||||||
|
copyCode: false,
|
||||||
|
prismjs: false,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import { HeadAttrsConfig } from 'vuepress';
|
||||||
|
|
||||||
interface SimplifiedHeader {
|
interface SimplifiedHeader {
|
||||||
tag: string;
|
tag: string;
|
||||||
content: [any];
|
content: HeadAttrsConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const simplifiedHead = [
|
const simplifiedHead: SimplifiedHeader[] = [
|
||||||
{
|
{
|
||||||
tag: 'meta',
|
tag: 'meta',
|
||||||
content: [
|
content: [
|
||||||
@ -35,6 +37,10 @@ const simplifiedHead = [
|
|||||||
name: 'twitter:creator',
|
name: 'twitter:creator',
|
||||||
content: '@phundrak',
|
content: '@phundrak',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'build-status',
|
||||||
|
content: `value: ${process.env.NODE_ENV}`,
|
||||||
|
},
|
||||||
{ name: 'msapplication-TileColor', content: '#3b4252' },
|
{ name: 'msapplication-TileColor', content: '#3b4252' },
|
||||||
{ name: 'msapplication-TileImage', content: '/ms-icon-144x144.png' },
|
{ name: 'msapplication-TileImage', content: '/ms-icon-144x144.png' },
|
||||||
{ name: 'theme-color', content: '#3b4252' },
|
{ name: 'theme-color', content: '#3b4252' },
|
||||||
@ -117,12 +123,16 @@ const simplifiedHead = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let head = [];
|
const headBuilder = [];
|
||||||
simplifiedHead.forEach((tag) => {
|
simplifiedHead.forEach((tag) => {
|
||||||
tag.content.forEach((element: any) => {
|
tag.content.forEach((element) => {
|
||||||
head.push([tag.tag, element]);
|
headBuilder.push([tag.tag, element]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
head.push(['a', { rel: 'me', href: 'https://emacs.ch/@phundrak' }, 'Mastodon']);
|
headBuilder.push([
|
||||||
|
'a',
|
||||||
|
{ rel: 'me', href: 'https://emacs.ch/@phundrak' },
|
||||||
|
'Mastodon',
|
||||||
|
]);
|
||||||
|
|
||||||
export default head;
|
export const head = headBuilder;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
const locales = {
|
import { SearchProLocaleConfig } from 'vuepress-plugin-search-pro';
|
||||||
|
|
||||||
|
export const locales = {
|
||||||
'/': {
|
'/': {
|
||||||
lang: 'fr-FR',
|
lang: 'fr-FR',
|
||||||
title: 'Lucien Cartier-Tilet',
|
title: 'Lucien Cartier-Tilet',
|
||||||
@ -16,4 +18,37 @@ const locales = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default locales;
|
export const searchLocales: SearchProLocaleConfig = {
|
||||||
|
'/fr/': {
|
||||||
|
cancel: 'Annuler',
|
||||||
|
placeholder: 'Rechercher',
|
||||||
|
search: 'Rechercher',
|
||||||
|
searching: 'Recherche',
|
||||||
|
defaultTitle: 'Documentation',
|
||||||
|
select: 'sélectionner',
|
||||||
|
navigate: 'naviguer',
|
||||||
|
autocomplete: 'auto-complétion',
|
||||||
|
exit: 'fermer',
|
||||||
|
queryHistory: 'Historique de recherche',
|
||||||
|
resultHistory: 'Historique des résultats',
|
||||||
|
emptyHistory: "Vider l'historique de recherche",
|
||||||
|
emptyResult: 'Aucun résultat trouvé',
|
||||||
|
loading: 'Chargement des index de recherche...',
|
||||||
|
},
|
||||||
|
'/lfn/': {
|
||||||
|
cancel: 'Cansela',
|
||||||
|
placeholder: 'Xerca',
|
||||||
|
search: 'Xerca',
|
||||||
|
searching: 'Xercante',
|
||||||
|
defaultTitle: 'Documentos',
|
||||||
|
select: 'eleje',
|
||||||
|
navigate: 'naviga',
|
||||||
|
autocomplete: 'auto-completi',
|
||||||
|
exit: 'sorti',
|
||||||
|
queryHistory: 'Historia de xerca',
|
||||||
|
resultHistory: 'Historia de resultas',
|
||||||
|
emptyHistory: 'Historia vacua',
|
||||||
|
emptyResult: 'Resultas vacua',
|
||||||
|
loading: 'Cargante la indise de xerca...',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -16,7 +16,7 @@ me.
|
|||||||
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] : blog alternative
|
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] : blog alternative
|
||||||
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: short stories,
|
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: short stories,
|
||||||
mainly in French for now
|
mainly in French for now
|
||||||
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (tell me you come from here,
|
- {{{icon(discord)}}} Discord :: =@phundrak= (tell me you come from here,
|
||||||
otherwise there’s a chance I’ll consider your message as spam)
|
otherwise there’s a chance I’ll consider your message as spam)
|
||||||
|
|
||||||
** Other Websites
|
** Other Websites
|
||||||
|
@ -18,8 +18,8 @@ websites to function properly or function properly or more
|
|||||||
efficiently.
|
efficiently.
|
||||||
|
|
||||||
This website uses some functional cookies in order to remember your
|
This website uses some functional cookies in order to remember your
|
||||||
preferences, such as your preferred language or its color theme. These
|
preferences, such as your preferred language or its colour theme.
|
||||||
cookies are not and cannot be used to track you.
|
These cookies are not and cannot be used to track you.
|
||||||
|
|
||||||
However, as this site is protected by Cloudflare, they may also host
|
However, as this site is protected by Cloudflare, they may also host
|
||||||
some cookies to remember, for example, that your browser is safe or to
|
some cookies to remember, for example, that your browser is safe or to
|
||||||
@ -27,8 +27,8 @@ record traffic to the site.
|
|||||||
|
|
||||||
*** How can I control cookies on my computer?
|
*** How can I control cookies on my computer?
|
||||||
If you don't want Cloudflare to record your browsing activity on my
|
If you don't want Cloudflare to record your browsing activity on my
|
||||||
website, a good adblocker should do the trick. I personally recommend
|
website, a good ad blocker should do the trick. I personally recommend
|
||||||
[[https://ublockorigin.com/][uBlock Origin]], one of the most effective adblockers I know of if not
|
[[https://ublockorigin.com/][uBlock Origin]], one of the most effective ad blockers I know of if not
|
||||||
the most effective one.
|
the most effective one.
|
||||||
|
|
||||||
You can also manually delete cookies from your browser, but given the
|
You can also manually delete cookies from your browser, but given the
|
||||||
@ -43,7 +43,19 @@ internet, or even via emails or any web content rendered on the
|
|||||||
screen, such as web beacons (minuscule, invisible images). It is also
|
screen, such as web beacons (minuscule, invisible images). It is also
|
||||||
possible to store Flash cookies or local shared objects.
|
possible to store Flash cookies or local shared objects.
|
||||||
|
|
||||||
This site does not use them at all.
|
*** But is there any tracking at all on this website?
|
||||||
|
Well, there is, but it absolutely respects your privacy. I use my own
|
||||||
|
instance of [[https://umami.is][Umami]] which is an analytics service that is fully GDPR and
|
||||||
|
CCPA compliant. In short, when you visit a web page, some data get
|
||||||
|
sent to my service, but nothing that can identify you. If you come
|
||||||
|
back an hour later, I won’t have any indication that you are the same
|
||||||
|
person.
|
||||||
|
|
||||||
|
If you still worry about your privacy, you have two options:
|
||||||
|
- Activate the Do Not Track setting of your browser (which Umami will
|
||||||
|
honour)
|
||||||
|
- Block the domain =umami.phundrak.com= in uBlock Origin (the only
|
||||||
|
ad blocker I will ever trust)
|
||||||
|
|
||||||
** Is there targeted advertisement on this website?
|
** Is there targeted advertisement on this website?
|
||||||
There’s no advertisement to begin with, and never will be. If you see
|
There’s no advertisement to begin with, and never will be. If you see
|
||||||
@ -55,16 +67,10 @@ is a cry for help.
|
|||||||
|
|
||||||
** How often is this page updated?
|
** How often is this page updated?
|
||||||
It is updated from time to time to reflect any changes in how my
|
It is updated from time to time to reflect any changes in how my
|
||||||
website behaves, or if I notice errors on this page (such as typos). I
|
website behaves, or if I notice errors on this page (such as typos).
|
||||||
might add some user tracking, however don’t worry, Matomo (the service
|
|
||||||
I would use) would only track you on this website and this website
|
|
||||||
only. Matomo respects the privacy of a website’s users.
|
|
||||||
|
|
||||||
The date of the last update of this web page can be found at its very
|
|
||||||
beginning.
|
|
||||||
|
|
||||||
** I have other questions
|
** I have other questions
|
||||||
And I have the answers! I’ll be more thang happy to chat with you by
|
And I have the answers! I’ll be more than happy to chat with you by
|
||||||
email, feel free to send me one at [[mailto:lucien@phundrak.com][lucien@phundrak.com]].
|
email, feel free to send me one at [[mailto:lucien@phundrak.com][lucien@phundrak.com]].
|
||||||
|
|
||||||
#+include: other-links
|
#+include: other-links
|
||||||
|
@ -15,7 +15,7 @@ sociaux où vous pouvez me suivre.
|
|||||||
- {{{icon(writefreely)}}} *Writefreely* :
|
- {{{icon(writefreely)}}} *Writefreely* :
|
||||||
- [[https://write.phundrak.com/phundrak][*@phundrak@write.phundrak.com*]] : billets personnels
|
- [[https://write.phundrak.com/phundrak][*@phundrak@write.phundrak.com*]] : billets personnels
|
||||||
- [[https://write.phundrak.com/phundraks-short-stories][*@phundraks-short-stories@write.phundrak.com*]] : histoires courtes
|
- [[https://write.phundrak.com/phundraks-short-stories][*@phundraks-short-stories@write.phundrak.com*]] : histoires courtes
|
||||||
- {{{icon(discord)}}} *Discord* : =Phundrak#0001= (dites-moi que vous venez
|
- {{{icon(discord)}}} *Discord* : =@phundrak= (dites-moi que vous venez
|
||||||
d’ici, autrement il est possible que je considère le message comme
|
d’ici, autrement il est possible que je considère le message comme
|
||||||
du pourriel)
|
du pourriel)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ On pote trova me sur multe loca ueb e redes sosial do on pote segue me.
|
|||||||
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] :: revistas personal
|
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] :: revistas personal
|
||||||
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: istorias corta (a
|
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: istorias corta (a
|
||||||
multe veses en Frans)
|
multe veses en Frans)
|
||||||
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (dise me ce tu veni de asi,
|
- {{{icon(discord)}}} Discord :: =@phundrak= (dise me ce tu veni de asi,
|
||||||
si no, me pote pensa ce tua mesaje es spam)
|
si no, me pote pensa ce tua mesaje es spam)
|
||||||
|
|
||||||
** Other Websites
|
** Other Websites
|
||||||
|
@ -16,19 +16,15 @@ es an con tota estrema comun. Los capasi esa locas ueb a funsiona
|
|||||||
coreta o plu eficas.
|
coreta o plu eficas.
|
||||||
|
|
||||||
Esa loca ueb usa cucis con la ojeto de recorda tua prefere, como ance
|
Esa loca ueb usa cucis con la ojeto de recorda tua prefere, como ance
|
||||||
la lingua o la motif ce te ia eleje. Lo ance usa cucis de mi personal
|
la lingua o la motif ce te ia eleje.
|
||||||
Matomo par sabe lo ce lo usores de esa loca ueb fa asi, ma Matomo
|
|
||||||
trasa lo sola sur mea locas ueb.
|
|
||||||
|
|
||||||
An tal, esa loca ueb es protejeda par Cloudflare, esa compania ance
|
An tal, esa loca ueb es protejeda par Cloudflare, esa compania ance
|
||||||
pote ospita alga cucis afin lo recorda si tu surfador es un risca par
|
pote ospita alga cucis afin lo recorda si tu surfador es un risca par
|
||||||
me loca ueb o no.
|
me loca ueb o no.
|
||||||
|
|
||||||
*** Como me pote controla la cucis sur mea computa?
|
*** Como me pote controla la cucis sur mea computa?
|
||||||
Si te no vole ce Cloudflare o Matomo recorda cucis, un bon
|
Si te no vole ce Cloudflare recorda cucis, un bon anti-comersial como
|
||||||
anti-comersial como [[https://ublockorigin.com/][uBlock Origin]] ta pote
|
[[https://ublockorigin.com/][uBlock Origin]] ta pote te proteje (es la plu eficas ce me conose).
|
||||||
te proteje (es la plu eficas ce me conose). Matomo ance respecta la
|
|
||||||
demanda “no trasa me” de surfadores.
|
|
||||||
|
|
||||||
Te pote ance supresa con mano la cucis de tua surfador, ma me no pote
|
Te pote ance supresa con mano la cucis de tua surfador, ma me no pote
|
||||||
te dise como, lo ave tro ce esiste. Ma te pote xerca sur DuckDuckGo,
|
te dise como, lo ave tro ce esiste. Ma te pote xerca sur DuckDuckGo,
|
||||||
@ -40,21 +36,32 @@ Lo esista otra metodos plu sutil afin de trasa usores sur la interede,
|
|||||||
o an con epostas o cada contenida ueb, como pixeles spia (imajes
|
o an con epostas o cada contenida ueb, como pixeles spia (imajes
|
||||||
estrema peti), cucis Flash o ojetos local compartida.
|
estrema peti), cucis Flash o ojetos local compartida.
|
||||||
|
|
||||||
Ma esa loca ueb no usa lo.
|
*** Ma, lo ave metodos de trasa asi?
|
||||||
|
Si, ma la lo conserva tua vida privata. Me usa mea propre varia de
|
||||||
|
[[https://umami.is][Umami]] ce es un servi de analise de datos ce respeta completa la GDPR e
|
||||||
|
la CCPA. En noncomplicada parolas, cuando te come a un paje, la
|
||||||
|
informa es enviada ce alga ia visita lo, con alga otra informas. Ma on
|
||||||
|
no pote sabe ci ia visita la loca ueb, e si te va visita lo a otra
|
||||||
|
ves, on no pote sabe ce te ia veni ja.
|
||||||
|
|
||||||
*** Esa loca ueb usa comersiales intendeda?
|
Si an tal te ansiosa consernante tua vida privata, tu avec du
|
||||||
|
posibles:
|
||||||
|
- Ativi la parametre Do Not Track de tua surfador (Umami respeta lo)
|
||||||
|
- Bloci la domina ueb =umami.phundrak.com= en uBlock Origin (la sola
|
||||||
|
blocinte de comersiales ce me fida)
|
||||||
|
|
||||||
|
** Esa loca ueb usa comersiales intendeda?
|
||||||
Lo no ave no comersiales. Si te lo vide asi, te ave un virus sur tua
|
Lo no ave no comersiales. Si te lo vide asi, te ave un virus sur tua
|
||||||
computa o surfador. Si esa comersiales vera ta veni de mea loca ueb,
|
computa o surfador. Si esa comersiales vera ta veni de mea loca ueb,
|
||||||
lo es cracida. Si te pote vide en la arciveria git ce lo es me ce ia
|
lo es cracida. Si te pote vide en la arciveria git ce lo es me ce ia
|
||||||
ajunta esa comersiales, o me ia dementi, o me es secuestrada e lo es
|
ajunta esa comersiales, o me ia dementi, o me es secuestrada e lo es
|
||||||
un sinial de crise.
|
un sinial de crise.
|
||||||
|
|
||||||
*** Ave esa pajina frecuente refrescis?
|
** Ave esa pajina frecuente refrescis?
|
||||||
Me dona esa pajina un refresci aora e alora cuando lo debe a mostra
|
Me dona esa pajina un refresci aora e alora cuando lo debe a mostra
|
||||||
cambias de funsiona de mea loca ueb, o si me trova eras. Te pote trove
|
cambias de funsiona de mea loca ueb, o si me trova eras.
|
||||||
la ultima refresci de esa pajina a supra.
|
|
||||||
|
|
||||||
*** Me ave otra demandas
|
** Me ave otra demandas
|
||||||
Te pote scrive me un eposta a la adirije de eposta
|
Te pote scrive me un eposta a la adirije de eposta
|
||||||
[[mailto:lucien@phundrak.com][lucien@phundrak.com]].
|
[[mailto:lucien@phundrak.com][lucien@phundrak.com]].
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
** Où est hébergé le site ?
|
** Où est hébergé le site ?
|
||||||
Ce site est hébergé sur mon serveur personnel, situé dans la ville de
|
Ce site est hébergé sur mon serveur personnel, situé dans la ville de
|
||||||
Bron en France, comme la majorité de mes sites. Deux autres sites,
|
Bron en France, comme la majorité de mes sites. Deux autres sites,
|
||||||
=labs.phundrak.com= et =mail.phundrak.com=, sont hébergé sur d’autres
|
=labs.phundrak.com= et =mail.phundrak.com=, sont hébergés sur d’autres
|
||||||
serveurs loués à Scaleway et à OVH France respectivement, et les
|
serveurs loués à Scaleway et à OVH France respectivement, et les
|
||||||
serveurs se situent également en France.
|
serveurs se situent également en France.
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ Ces cookies ne sont pas et ne peuvent pas être utilisés pour vous
|
|||||||
traquer.
|
traquer.
|
||||||
|
|
||||||
Cependant, ce site étant protégé par Cloudflare, ce dernier pourra
|
Cependant, ce site étant protégé par Cloudflare, ce dernier pourra
|
||||||
également héberger quelques cookies afin par exemple de se souvenir
|
pareillement héberger quelques cookies afin par exemple de se souvenir
|
||||||
que votre navigateur ne présente pas de risque ou bien pour
|
que votre navigateur ne présente pas de risque ou bien pour
|
||||||
enregistrer le trafic sur le site.
|
enregistrer le trafic sur le site.
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ activités, un bon anti-pub devrait faire l’affaire. Je recommande
|
|||||||
personnellement [[https://ublockorigin.com/][uBlock Origin]], l’un des bloqueurs de pub les plus
|
personnellement [[https://ublockorigin.com/][uBlock Origin]], l’un des bloqueurs de pub les plus
|
||||||
efficaces que je connaisse.
|
efficaces que je connaisse.
|
||||||
|
|
||||||
Vous pouvez également supprimer manuellement les cookies de votre
|
Vous pouvez par ailleurs supprimer manuellement les cookies de votre
|
||||||
navigateur, mais étant donné le nombre de navigateurs existants, il
|
navigateur, mais étant donné le nombre de navigateurs existants, il
|
||||||
sera sans doute plus rapide pour vous de chercher sur DuckDuckGo,
|
sera sans doute plus rapide pour vous de chercher sur DuckDuckGo,
|
||||||
Qwant ou Startpage comment faire pour votre navigateur actuel (si vous
|
Qwant ou Startpage comment faire pour votre navigateur actuel (si vous
|
||||||
@ -44,15 +44,29 @@ voudrez éviter Google).
|
|||||||
Il existe d’autres méthodes plus subtiles qui permettent de traquer
|
Il existe d’autres méthodes plus subtiles qui permettent de traquer
|
||||||
quelqu’un sur internet, ou même via des mails ou tout contenu web
|
quelqu’un sur internet, ou même via des mails ou tout contenu web
|
||||||
rendu à l’écran, comme pixels espions (des images extrêmement
|
rendu à l’écran, comme pixels espions (des images extrêmement
|
||||||
petites). Il est également possible de stocker des cookies Flash ou
|
petites). Il est de plus possible de stocker des cookies Flash ou des
|
||||||
des objets locaux partagés.
|
objets locaux partagés.
|
||||||
|
|
||||||
Ce site n’en utilise absolument pas.
|
*** Mais, est-ce qu’il y a du tracking sur ce site ?
|
||||||
|
Oui, mais en préservant intégralement votre vie privée. J’utilise ma
|
||||||
|
propre instance de [[https://umami.is][Umami]] qui est un service d’analyse de données qui
|
||||||
|
respecte entièrement le RGPD et le [[https://www.oag.ca.gov/privacy/ccpa][CCPA]]. Pour résumer, lorsque vous
|
||||||
|
passez sur une nouvelle page du site, l’information est envoyée qu’une
|
||||||
|
visite s’est produite, avec quelques informations supplémentaires,
|
||||||
|
mais rien qui permet d’identifier qui que ce soit. Si vous revenez
|
||||||
|
dans une heure, je ne saurai pas que vous êtes la même personne.
|
||||||
|
|
||||||
|
Si vous vous inquiétez tout de même de votre vie privée, deux options
|
||||||
|
s’offrent à vous :
|
||||||
|
- Activez l’option Do Not Track de votre navigateur (Umami respecte ce
|
||||||
|
paramètre)
|
||||||
|
- Bloquez le domaine =umami.phundrak.com= dans uBlock Origin (le seul
|
||||||
|
bloqueur de pubs auquel je fais confiance)
|
||||||
|
|
||||||
** Est-ce qu’il y a de la pub ciblée sur ce site ?
|
** Est-ce qu’il y a de la pub ciblée sur ce site ?
|
||||||
Il n’y a tout simplement aucune pub sur ce site. Si vous en voyez,
|
Il n’y a tout simplement aucune pub sur ce site. Si vous en voyez,
|
||||||
vous avez sans doute un virus installé sur votre ordinateur. Si ça
|
vous avez sans doute un virus installé sur votre ordinateur. Si ça
|
||||||
vient en effet de mon site web, cela veut dire qu’il a été hacké. Si
|
vient en effet de mon site web, cela veut dire qu’il a été piraté. Si
|
||||||
vous voyez sur son dépôt de code que c’est bien moi qui ai rajouté ces
|
vous voyez sur son dépôt de code que c’est bien moi qui ai rajouté ces
|
||||||
pubs, cela veut dire que j’ai perdu tout mon sens moral, ou bien que
|
pubs, cela veut dire que j’ai perdu tout mon sens moral, ou bien que
|
||||||
j’ai été kidnappé et il s’agit d’un appel au secours.
|
j’ai été kidnappé et il s’agit d’un appel au secours.
|
||||||
@ -60,11 +74,7 @@ j’ai été kidnappé et il s’agit d’un appel au secours.
|
|||||||
** Est-ce que cette page est souvent mise à jour ?
|
** Est-ce que cette page est souvent mise à jour ?
|
||||||
Je peux la mettre à jour de temps en temps afin de refléter des
|
Je peux la mettre à jour de temps en temps afin de refléter des
|
||||||
changements de fonctionnement du site, ou si je remarque une erreur
|
changements de fonctionnement du site, ou si je remarque une erreur
|
||||||
sur la page. Il se peut aussi que j’ajoute un jour un tracking des
|
sur la page.
|
||||||
utilisateurs sur mon site via Matomo, un service de tracking
|
|
||||||
respectant la vie privée des utilisateurs et qui est tout à fait
|
|
||||||
bloquable. La date de la dernière mise à jour de cette page peut être
|
|
||||||
trouvée à son tout début.
|
|
||||||
|
|
||||||
** J’ai d’autres questions
|
** J’ai d’autres questions
|
||||||
Et je serai heureux d’y répondre par mail. Vous pouvez me contacter
|
Et je serai heureux d’y répondre par mail. Vous pouvez me contacter
|
||||||
|
5295
package-lock.json
generated
Normal file
5295
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -8,23 +8,26 @@
|
|||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vuepress/bundler-vite": "2.0.0-rc.13",
|
||||||
|
"@vuepress/plugin-umami-analytics": "^2.0.0-rc.36",
|
||||||
|
"@vuepress/theme-default": "^2.0.0-rc.36",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"git-cliff": "^1.1.2",
|
"git-cliff": "^1.4.0",
|
||||||
"vuepress": "2.0.0-beta.61"
|
"vuepress": "2.0.0-rc.13",
|
||||||
|
"vuepress-plugin-search-pro": "^2.0.0-rc.43"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vuepress dev content",
|
"dev": "vuepress dev content",
|
||||||
"build": "vuepress build content"
|
"build": "vuepress build content"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"less": "^4.1.3",
|
"less": "^4.2.0",
|
||||||
"nord": "^0.2.1",
|
"nord": "^0.2.1"
|
||||||
"rxjs": "^7.8.1",
|
|
||||||
"vuepress-plugin-remove-html-extension": "^0.1.0"
|
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
"path": "./node_modules/cz-conventional-changelog"
|
"path": "./node_modules/cz-conventional-changelog"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@4.3.0"
|
||||||
}
|
}
|
||||||
|
6
shell.nix
Normal file
6
shell.nix
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
pkgs.mkShell {
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
nodejs_22
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user