Compare commits
No commits in common. "d54aabd6213554b9e6d2088fbd5466a3f79ab640" and "1ff33bfd648b9c72d0bbb2732d56e33277845ef7" have entirely different histories.
d54aabd621
...
1ff33bfd64
178
.drone.yml
Normal file
178
.drone.yml
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
---
|
||||||
|
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
|
@ -1,41 +0,0 @@
|
|||||||
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,4 +3,3 @@ node_modules
|
|||||||
.cache
|
.cache
|
||||||
/content/.vuepress/dist/*
|
/content/.vuepress/dist/*
|
||||||
*.md
|
*.md
|
||||||
/.yarn/
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
enableMessageNames: false
|
|
||||||
|
|
||||||
nodeLinker: node-modules
|
|
@ -4,8 +4,9 @@ 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 LoaderAnimation from './components/LoaderAnimation.vue';
|
import Loader from './components/Loader.vue';
|
||||||
import FetchError from './components/FetchError.vue';
|
import Cache from './components/Cache.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({
|
||||||
@ -15,8 +16,9 @@ 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('LoaderAnimation', LoaderAnimation);
|
app.component('Loader', Loader);
|
||||||
app.component('FetchError', FetchError);
|
app.component('Cache', Cache);
|
||||||
|
app.component('Error', Error);
|
||||||
app.component('Icon', Icon);
|
app.component('Icon', Icon);
|
||||||
},
|
},
|
||||||
setup() {},
|
setup() {},
|
||||||
|
@ -1,22 +1,31 @@
|
|||||||
<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">
|
||||||
<LoaderAnimation />
|
<Loader />
|
||||||
</slot>
|
</slot>
|
||||||
<slot v-else-if="error" name="error">
|
<slot v-else-if="error" name="error">
|
||||||
<FetchError :url="props.url" />
|
<Error :url="props.url" />
|
||||||
</slot>
|
</slot>
|
||||||
<slot v-else> </slot>
|
<slot v-else> </slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LoaderAnimation from './LoaderAnimation.vue';
|
import Cache from './Cache.vue';
|
||||||
import FetchError from './FetchError.vue';
|
import Loader from './Loader.vue';
|
||||||
|
import Error from './Error.vue';
|
||||||
|
|
||||||
import { useFetchAndCache } from '../composables/fetchAndCache';
|
import { Ref, ref } from 'vue';
|
||||||
|
import { Observable, catchError, switchMap, throwError } from 'rxjs';
|
||||||
|
import { fromFetch } from 'rxjs/fetch';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
url: {
|
url: {
|
||||||
default: '',
|
default: false,
|
||||||
required: true,
|
required: true,
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@ -26,11 +35,31 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
alreadyKnownData: Object,
|
alreadyKnownData: Object,
|
||||||
});
|
});
|
||||||
|
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
|
||||||
|
|
||||||
const emits = defineEmits(['loaded', 'error', 'loading']);
|
const error: Ref<Error> = ref(null);
|
||||||
|
const loading: Ref<boolean> = ref(true);
|
||||||
|
|
||||||
const { loading, error } = useFetchAndCache(props.url, {
|
const fetchData = (): Observable<any> => {
|
||||||
emits: emits,
|
return fromFetch(props.url).pipe(
|
||||||
cacheName: props.cacheName,
|
switchMap((response: Response) => response.json()),
|
||||||
});
|
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>
|
||||||
|
67
content/.vuepress/components/Cache.vue
Normal file
67
content/.vuepress/components/Cache.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<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" @loaded="filterRepos" cache-name="repos" />
|
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos" />
|
||||||
<slot />
|
<slot />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType, ref } from 'vue';
|
import { PropType } from 'vue';
|
||||||
import { GithubRepo } from '../../types/github';
|
import { GithubRepo } from '../../composables/github';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sortBy: {
|
sortBy: {
|
||||||
default: 'none',
|
default: 'none',
|
||||||
@ -23,12 +23,15 @@ 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[]) => {
|
||||||
repos.value = response
|
emits(
|
||||||
|
'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;
|
||||||
@ -40,7 +43,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"
|
||||||
@loaded="(repo: GithubRepo) => (repository = repo)"
|
@data-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 '../../types/github';
|
import { GithubRepo } from '../../composables/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 | null> = ref(null);
|
const repository: Ref<GithubRepo> = ref(null);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@ -78,12 +78,5 @@ const repository: Ref<GithubRepo | null> = 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"
|
||||||
@loaded="(response: GithubRepo[]) => (repos = response)"
|
@data-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 '../../types/github';
|
import { GithubRepo } from '../../composables/github';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sortBy: {
|
sortBy: {
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
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 };
|
|
||||||
};
|
|
@ -1,72 +0,0 @@
|
|||||||
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,46 +1,24 @@
|
|||||||
import { defaultTheme } from '@vuepress/theme-default';
|
import { defineUserConfig, defaultTheme } from 'vuepress';
|
||||||
import { viteBundler } from '@vuepress/bundler-vite';
|
import { removeHtmlExtensionPlugin } from 'vuepress-plugin-remove-html-extension';
|
||||||
import { defineUserConfig } from 'vuepress';
|
import head from './head';
|
||||||
import { searchProPlugin } from 'vuepress-plugin-search-pro';
|
import locales from './locales';
|
||||||
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: [
|
plugins: [removeHtmlExtensionPlugin()],
|
||||||
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,11 +1,9 @@
|
|||||||
import { HeadAttrsConfig } from 'vuepress';
|
|
||||||
|
|
||||||
interface SimplifiedHeader {
|
interface SimplifiedHeader {
|
||||||
tag: string;
|
tag: string;
|
||||||
content: HeadAttrsConfig[];
|
content: [any];
|
||||||
}
|
}
|
||||||
|
|
||||||
const simplifiedHead: SimplifiedHeader[] = [
|
const simplifiedHead = [
|
||||||
{
|
{
|
||||||
tag: 'meta',
|
tag: 'meta',
|
||||||
content: [
|
content: [
|
||||||
@ -37,10 +35,6 @@ const simplifiedHead: SimplifiedHeader[] = [
|
|||||||
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' },
|
||||||
@ -123,16 +117,12 @@ const simplifiedHead: SimplifiedHeader[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const headBuilder = [];
|
let head = [];
|
||||||
simplifiedHead.forEach((tag) => {
|
simplifiedHead.forEach((tag) => {
|
||||||
tag.content.forEach((element) => {
|
tag.content.forEach((element: any) => {
|
||||||
headBuilder.push([tag.tag, element]);
|
head.push([tag.tag, element]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
headBuilder.push([
|
head.push(['a', { rel: 'me', href: 'https://emacs.ch/@phundrak' }, 'Mastodon']);
|
||||||
'a',
|
|
||||||
{ rel: 'me', href: 'https://emacs.ch/@phundrak' },
|
|
||||||
'Mastodon',
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const head = headBuilder;
|
export default head;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { SearchProLocaleConfig } from 'vuepress-plugin-search-pro';
|
const locales = {
|
||||||
|
|
||||||
export const locales = {
|
|
||||||
'/': {
|
'/': {
|
||||||
lang: 'fr-FR',
|
lang: 'fr-FR',
|
||||||
title: 'Lucien Cartier-Tilet',
|
title: 'Lucien Cartier-Tilet',
|
||||||
@ -18,37 +16,4 @@ export const locales = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const searchLocales: SearchProLocaleConfig = {
|
export default locales;
|
||||||
'/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= (tell me you come from here,
|
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (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 colour theme.
|
preferences, such as your preferred language or its color theme. These
|
||||||
These cookies are not and cannot be used to track you.
|
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 ad blocker should do the trick. I personally recommend
|
website, a good adblocker should do the trick. I personally recommend
|
||||||
[[https://ublockorigin.com/][uBlock Origin]], one of the most effective ad blockers I know of if not
|
[[https://ublockorigin.com/][uBlock Origin]], one of the most effective adblockers 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,19 +43,7 @@ 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.
|
||||||
|
|
||||||
*** But is there any tracking at all on this website?
|
This site does not use them at all.
|
||||||
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
|
||||||
@ -67,10 +55,16 @@ 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).
|
website behaves, or if I notice errors on this page (such as typos). I
|
||||||
|
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 than happy to chat with you by
|
And I have the answers! I’ll be more thang 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= (dites-moi que vous venez
|
- {{{icon(discord)}}} *Discord* : =Phundrak#0001= (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= (dise me ce tu veni de asi,
|
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (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,15 +16,19 @@ 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.
|
la lingua o la motif ce te ia eleje. Lo ance usa cucis de mi personal
|
||||||
|
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 recorda cucis, un bon anti-comersial como
|
Si te no vole ce Cloudflare o Matomo recorda cucis, un bon
|
||||||
[[https://ublockorigin.com/][uBlock Origin]] ta pote te proteje (es la plu eficas ce me conose).
|
anti-comersial como [[https://ublockorigin.com/][uBlock Origin]] ta pote
|
||||||
|
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,
|
||||||
@ -36,32 +40,21 @@ 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, lo ave metodos de trasa asi?
|
Ma esa loca ueb no usa lo.
|
||||||
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.
|
|
||||||
|
|
||||||
Si an tal te ansiosa consernante tua vida privata, tu avec du
|
*** Esa loca ueb usa comersiales intendeda?
|
||||||
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.
|
cambias de funsiona de mea loca ueb, o si me trova eras. Te pote trove
|
||||||
|
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és sur d’autres
|
=labs.phundrak.com= et =mail.phundrak.com=, sont hébergé 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
|
||||||
pareillement héberger quelques cookies afin par exemple de se souvenir
|
également 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 par ailleurs supprimer manuellement les cookies de votre
|
Vous pouvez également 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,29 +44,15 @@ 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 de plus possible de stocker des cookies Flash ou des
|
petites). Il est également possible de stocker des cookies Flash ou
|
||||||
objets locaux partagés.
|
des objets locaux partagés.
|
||||||
|
|
||||||
*** Mais, est-ce qu’il y a du tracking sur ce site ?
|
Ce site n’en utilise absolument pas.
|
||||||
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é piraté. Si
|
vient en effet de mon site web, cela veut dire qu’il a été hacké. 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.
|
||||||
@ -74,7 +60,11 @@ 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.
|
sur la page. Il se peut aussi que j’ajoute un jour un tracking des
|
||||||
|
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
5295
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -8,26 +8,23 @@
|
|||||||
"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.4.0",
|
"git-cliff": "^1.1.2",
|
||||||
"vuepress": "2.0.0-rc.13",
|
"vuepress": "2.0.0-beta.61"
|
||||||
"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.2.0",
|
"less": "^4.1.3",
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
nodejs_22
|
|
||||||
];
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user