Compare commits
13 Commits
1ff33bfd64
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| cc62d0bb95 | |||
| 727ec58600 | |||
|
333b7a7562
|
|||
|
baf999ea1c
|
|||
|
9a92f57986
|
|||
|
c8ce7ca6da
|
|||
|
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
|
||||
50
.github/workflows/deploy.yaml
vendored
Normal file
50
.github/workflows/deploy.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
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 to Cloudflare Pages"
|
||||
uses: cloudflare/pages-action@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.ACCOUNT_ID }}
|
||||
projectName: phundrak-com
|
||||
directory: content/.vuepress/dist/
|
||||
githubToken: ${{ secrets.TOKEN }}
|
||||
|
||||
# - 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
|
||||
/content/.vuepress/dist/*
|
||||
*.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 GithubRepository from './components/GitHub/GithubRepository.vue';
|
||||
import ApiLoader from './components/ApiLoader.vue';
|
||||
import Loader from './components/Loader.vue';
|
||||
import Cache from './components/Cache.vue';
|
||||
import Error from './components/Error.vue';
|
||||
import LoaderAnimation from './components/LoaderAnimation.vue';
|
||||
import FetchError from './components/FetchError.vue';
|
||||
import Icon from './components/Icon.vue';
|
||||
|
||||
export default defineClientConfig({
|
||||
@@ -16,9 +15,8 @@ export default defineClientConfig({
|
||||
app.component('FetchRepositories', FetchRepositories);
|
||||
app.component('GithubRepository', GithubRepository);
|
||||
app.component('ApiLoader', ApiLoader);
|
||||
app.component('Loader', Loader);
|
||||
app.component('Cache', Cache);
|
||||
app.component('Error', Error);
|
||||
app.component('LoaderAnimation', LoaderAnimation);
|
||||
app.component('FetchError', FetchError);
|
||||
app.component('Icon', Icon);
|
||||
},
|
||||
setup() {},
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
<template>
|
||||
<Cache
|
||||
:name="props.cacheName"
|
||||
:callback="fetchData"
|
||||
:already-known-data="alreadyKnownData"
|
||||
@cached="processCachedData"
|
||||
/>
|
||||
<slot v-if="loading" name="loader">
|
||||
<Loader />
|
||||
<LoaderAnimation />
|
||||
</slot>
|
||||
<slot v-else-if="error" name="error">
|
||||
<Error :url="props.url" />
|
||||
<FetchError :url="props.url" />
|
||||
</slot>
|
||||
<slot v-else> </slot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Cache from './Cache.vue';
|
||||
import Loader from './Loader.vue';
|
||||
import Error from './Error.vue';
|
||||
import LoaderAnimation from './LoaderAnimation.vue';
|
||||
import FetchError from './FetchError.vue';
|
||||
|
||||
import { Ref, ref } from 'vue';
|
||||
import { Observable, catchError, switchMap, throwError } from 'rxjs';
|
||||
import { fromFetch } from 'rxjs/fetch';
|
||||
import { useFetchAndCache } from '../composables/fetchAndCache';
|
||||
|
||||
const props = defineProps({
|
||||
url: {
|
||||
default: false,
|
||||
default: '',
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
@@ -35,31 +26,11 @@ const props = defineProps({
|
||||
},
|
||||
alreadyKnownData: Object,
|
||||
});
|
||||
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
|
||||
|
||||
const error: Ref<Error> = ref(null);
|
||||
const loading: Ref<boolean> = ref(true);
|
||||
const emits = defineEmits(['loaded', 'error', 'loading']);
|
||||
|
||||
const fetchData = (): Observable<any> => {
|
||||
return fromFetch(props.url).pipe(
|
||||
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;
|
||||
},
|
||||
const { loading, error } = useFetchAndCache(props.url, {
|
||||
emits: emits,
|
||||
cacheName: props.cacheName,
|
||||
});
|
||||
};
|
||||
</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>
|
||||
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos" />
|
||||
<ApiLoader :url="fetchUrl" @loaded="filterRepos" cache-name="repos" />
|
||||
<slot />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { GithubRepo } from '../../composables/github';
|
||||
import { PropType, ref } from 'vue';
|
||||
import { GithubRepo } from '../../types/github';
|
||||
const props = defineProps({
|
||||
sortBy: {
|
||||
default: 'none',
|
||||
@@ -23,15 +23,12 @@ const props = defineProps({
|
||||
type: Number,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['dataLoaded']);
|
||||
|
||||
const emits = defineEmits(['loaded']);
|
||||
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
|
||||
const repos = ref<GithubRepo[]>([]);
|
||||
|
||||
const filterRepos = (response: GithubRepo[]) => {
|
||||
emits(
|
||||
'dataLoaded',
|
||||
response
|
||||
repos.value = response
|
||||
.sort((a, b) => {
|
||||
if (props.sortBy === 'stars') {
|
||||
return b.stargazers_count - a.stargazers_count;
|
||||
@@ -43,7 +40,7 @@ const filterRepos = (response: GithubRepo[]) => {
|
||||
}
|
||||
return b.forks_count - a.forks_count;
|
||||
})
|
||||
.slice(0, +props.limit)
|
||||
);
|
||||
.slice(0, +props.limit);
|
||||
emits('loaded', repos.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,23 +6,23 @@
|
||||
:cache-name="repoName()"
|
||||
:url="fetchUrl"
|
||||
: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>
|
||||
<p>
|
||||
{{ repository.description }}
|
||||
{{ repository?.description }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex-row flex-start gap-1rem stats">
|
||||
<div class="stars">
|
||||
<Icon name="star" /> {{ repository.stargazers_count }}
|
||||
<Icon name="star" /> {{ repository?.stargazers_count }}
|
||||
</div>
|
||||
<div class="forks">
|
||||
<Icon name="fork" /> {{ repository.forks_count }}
|
||||
<Icon name="fork" /> {{ repository?.forks_count }}
|
||||
</div>
|
||||
<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>
|
||||
</ApiLoader>
|
||||
@@ -32,7 +32,7 @@
|
||||
<script setup lang="ts">
|
||||
import ApiLoader from '../ApiLoader.vue';
|
||||
|
||||
import { GithubRepo } from '../../composables/github';
|
||||
import { GithubRepo } from '../../types/github';
|
||||
import { PropType, Ref, ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -45,7 +45,7 @@ const repoName = (): string => {
|
||||
};
|
||||
|
||||
const fetchUrl = `https://api.github.com/repos/${repoName()}`;
|
||||
const repository: Ref<GithubRepo> = ref(null);
|
||||
const repository: Ref<GithubRepo | null> = ref(null);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@@ -78,5 +78,12 @@ const repository: Ref<GithubRepo> = ref(null);
|
||||
gap: 0.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:sort-by="props.sortBy"
|
||||
:user="props.user"
|
||||
:limit="props.limit"
|
||||
@data-loaded="(response: GithubRepo[]) => (repos = response)"
|
||||
@loaded="(response: GithubRepo[]) => (repos = response)"
|
||||
>
|
||||
<GithubRepository
|
||||
:data="repo"
|
||||
@@ -22,7 +22,7 @@ import FetchRepositories from './FetchRepositories.vue';
|
||||
import GithubRepository from './GithubRepository.vue';
|
||||
|
||||
import { PropType, Ref, ref } from 'vue';
|
||||
import { GithubRepo } from '../../composables/github';
|
||||
import { GithubRepo } from '../../types/github';
|
||||
|
||||
const props = defineProps({
|
||||
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,56 @@
|
||||
import { defineUserConfig, defaultTheme } from 'vuepress';
|
||||
import { removeHtmlExtensionPlugin } from 'vuepress-plugin-remove-html-extension';
|
||||
import head from './head';
|
||||
import locales from './locales';
|
||||
import { defaultTheme } from '@vuepress/theme-default';
|
||||
import { viteBundler } from '@vuepress/bundler-vite';
|
||||
import { defineUserConfig } from 'vuepress';
|
||||
import { slimsearchPlugin } from '@vuepress/plugin-slimsearch';
|
||||
import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics';
|
||||
|
||||
import { head } from './head';
|
||||
import { locales, searchLocaleLfn } from './locales';
|
||||
import { themeLocales } from './themeLocales';
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
export default defineUserConfig({
|
||||
lang: 'fr-FR',
|
||||
title: 'Lucien Cartier-Tilet',
|
||||
description: 'Site web personnel de Lucien Cartier-Tilet',
|
||||
head: head,
|
||||
bundler: isProd
|
||||
? viteBundler({})
|
||||
: viteBundler({
|
||||
viteOptions: {
|
||||
server: {
|
||||
allowedHosts: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
markdown: {
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
},
|
||||
plugins: [removeHtmlExtensionPlugin()],
|
||||
plugins: [
|
||||
slimsearchPlugin({
|
||||
indexContent: true,
|
||||
indexLocaleOptions: {
|
||||
'/lfn': searchLocaleLfn,
|
||||
},
|
||||
}),
|
||||
isProd
|
||||
? umamiAnalyticsPlugin({
|
||||
id: '67166941-8c83-4a19-bc8c-139e44b7f7aa',
|
||||
link: 'https://umami.phundrak.com/script.js',
|
||||
})
|
||||
: [],
|
||||
],
|
||||
locales: locales,
|
||||
theme: defaultTheme({
|
||||
contributors: false,
|
||||
locales: themeLocales,
|
||||
repo: 'https://labs.phundrak.com/phundrak/phundrak.com',
|
||||
themePlugins: {
|
||||
copyCode: false,
|
||||
prismjs: false,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { HeadAttrsConfig } from 'vuepress';
|
||||
|
||||
interface SimplifiedHeader {
|
||||
tag: string;
|
||||
content: [any];
|
||||
content: HeadAttrsConfig[];
|
||||
}
|
||||
|
||||
const simplifiedHead = [
|
||||
const simplifiedHead: SimplifiedHeader[] = [
|
||||
{
|
||||
tag: 'meta',
|
||||
content: [
|
||||
@@ -11,6 +13,10 @@ const simplifiedHead = [
|
||||
name: 'author',
|
||||
content: 'Lucien Cartier-Tilet',
|
||||
},
|
||||
{
|
||||
name: 'fediverse:creator',
|
||||
content: '@phundrak@mastodon.phundrak.com',
|
||||
},
|
||||
{
|
||||
property: 'og:image',
|
||||
content: 'https://cdn.phundrak.com/img/rich_preview.png',
|
||||
@@ -35,6 +41,10 @@ const simplifiedHead = [
|
||||
name: 'twitter:creator',
|
||||
content: '@phundrak',
|
||||
},
|
||||
{
|
||||
name: 'build-status',
|
||||
content: `value: ${process.env.NODE_ENV}`,
|
||||
},
|
||||
{ name: 'msapplication-TileColor', content: '#3b4252' },
|
||||
{ name: 'msapplication-TileImage', content: '/ms-icon-144x144.png' },
|
||||
{ name: 'theme-color', content: '#3b4252' },
|
||||
@@ -117,12 +127,16 @@ const simplifiedHead = [
|
||||
},
|
||||
];
|
||||
|
||||
let head = [];
|
||||
const headBuilder = [];
|
||||
simplifiedHead.forEach((tag) => {
|
||||
tag.content.forEach((element: any) => {
|
||||
head.push([tag.tag, element]);
|
||||
tag.content.forEach((element) => {
|
||||
headBuilder.push([tag.tag, element]);
|
||||
});
|
||||
});
|
||||
head.push(['a', { rel: 'me', href: 'https://emacs.ch/@phundrak' }, 'Mastodon']);
|
||||
headBuilder.push([
|
||||
'a',
|
||||
{ rel: 'me', href: 'https://mastodon.phundrak.com/@phundrak' },
|
||||
'Mastodon',
|
||||
]);
|
||||
|
||||
export default head;
|
||||
export const head = headBuilder;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const locales = {
|
||||
import SlimSarchLocaleData from '@vuepress/plugin-slimsearch';
|
||||
|
||||
export const locales = {
|
||||
'/': {
|
||||
lang: 'fr-FR',
|
||||
title: 'Lucien Cartier-Tilet',
|
||||
@@ -16,4 +18,19 @@ const locales = {
|
||||
},
|
||||
};
|
||||
|
||||
export default locales;
|
||||
export const searchLocaleLfn: SlimSarchLocaleData = {
|
||||
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...',
|
||||
};
|
||||
|
||||
@@ -7,26 +7,25 @@ I am on various websites and some social networks where you can follow
|
||||
me.
|
||||
|
||||
** Social Networks
|
||||
- {{{icon(mastodon)}}} Mastodon :: [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] should work,
|
||||
otherwise head over to [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]]
|
||||
- {{{icon(twitter)}}} Twitter :: [[https://twitter.com/phundrak][@phundrak]], though I harldy use it anymore
|
||||
- {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
|
||||
- {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], though I harldy use it anymore
|
||||
and mostly reshare my Mastodon messages when I think to, and
|
||||
sometimes they get truncated
|
||||
- {{{icon(writefreely)}}} Writefreely ::
|
||||
- {{{icon(writefreely)}}} *Writefreely* ::
|
||||
- [[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,
|
||||
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)
|
||||
|
||||
** Other Websites
|
||||
- {{{icon(envelope)}}} Email :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} Blog :: [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} Gitea :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} GitHub :: [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} YouTube :: [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} Reddit :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
|
||||
- {{{icon(linkedin)}}} LinkedIn :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} Twitch :: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
- {{{icon(envelope)}}} *Email* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
|
||||
- {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
|
||||
#+include: other-links
|
||||
|
||||
@@ -18,8 +18,8 @@ websites to function properly or function properly or more
|
||||
efficiently.
|
||||
|
||||
This website uses some functional cookies in order to remember your
|
||||
preferences, such as your preferred language or its color theme. These
|
||||
cookies are not and cannot be used to track you.
|
||||
preferences, such as your preferred language or its colour theme.
|
||||
These cookies are not and cannot be used to track you.
|
||||
|
||||
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
|
||||
@@ -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
|
||||
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?
|
||||
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?
|
||||
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
|
||||
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.
|
||||
website behaves, or if I notice errors on this page (such as typos).
|
||||
|
||||
** 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]].
|
||||
|
||||
#+include: other-links
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
Startup specialized in the creation of French virtual singers using
|
||||
vocal synthesis. Its best known product is ALYS. [[./vocal-synthesis.md][More here]].
|
||||
|
||||
- Co-founder
|
||||
- Co-founder, CTO
|
||||
- Development of singing synthesis vocal libraries
|
||||
- Linguistic research
|
||||
- User support
|
||||
@@ -30,30 +30,24 @@ Studied for a year and a half until the creation of [[./resume.md#voxwave-2014-2
|
||||
|
||||
** Web Programming
|
||||
*** Front-end
|
||||
- Regularly using Angular, Vue, and Node.js
|
||||
- Good knowledge in HTML5, CSS3 (including SASS, SCSS, and LESS), and
|
||||
Javascript
|
||||
- I know my way around in Python, Dart, and TypeScript
|
||||
- Learning React and Next.js
|
||||
- Professional use of Angular and TypeScript
|
||||
- Personal use of Vue (including Nuxt)
|
||||
|
||||
*** Back-end
|
||||
- Regularly using Rust ([[https://actix.rs/][actix-web]] and [[https://rocket.rs/][Rocket]]) and Java Spring Boot
|
||||
- Professional use of Java SpringBoot and SpringBatch
|
||||
- Professional and personal use of PostgreSQL
|
||||
- Personal use of Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] and [[https://rocket.rs/][Rocket]])
|
||||
- Some experience in back-end development with Django (Python)
|
||||
- Some experience communicating with a database with Django’s and
|
||||
[[https://diesel.rs][Diesel]]’s ORM. Know my way around EmacSQL.
|
||||
- Used MySQL and PostgreSQL
|
||||
- Personal use of MySQL and SQLite
|
||||
|
||||
** System Programming
|
||||
- Experienced in Rust, C and EmacsLisp knowledge
|
||||
- I know my way around C++, Python, and UNIX shells (bash, fish,
|
||||
Eshell)
|
||||
- Limited knowledge in Prolog and Scheme
|
||||
- Frequent usage of Rust, C, EmacsLisp, and UNIX shells (bash, fish, Eshell)
|
||||
- Occasional use of C++, Python, and CommonLisp
|
||||
|
||||
** Development Tools
|
||||
*** IDEs and Text Editors
|
||||
- Professional use of VS Code, Eclipse, and Git
|
||||
- Advanced user of Emacs, including its LSP and Git integrations
|
||||
- Good knowledge of Git (including Magit under Emacs), VS Code, and
|
||||
Eclipse
|
||||
- Basic knowledge of Vim, CLion, Pycharm, and WebStorm
|
||||
|
||||
*** CI/CD and Deploying to the Web
|
||||
@@ -64,14 +58,14 @@ Studied for a year and a half until the creation of [[./resume.md#voxwave-2014-2
|
||||
|
||||
** Operating Systems
|
||||
- Usage and administration of Linux (Arch Linux, Void Linux, Debian,
|
||||
Ubuntu, Alpine Linux)
|
||||
Ubuntu, Alpine Linux, NixOS)
|
||||
- Administration of web servers and storage servers (Arch Linux,
|
||||
Debian, Raspbian, Alpine Linux)
|
||||
- Basic knowledge with Guix System and NixOS, and Windows XP through
|
||||
10 (except Vista)
|
||||
Debian, Raspbian, Alpine Linux, NixOS)
|
||||
- Basic knowledge with Guix System and Windows XP through 10 (except
|
||||
Vista)
|
||||
|
||||
** Office Applications
|
||||
- Good knowledge with org-mode (main tool), LaTeX
|
||||
- Good knowledge with [[https://orgmode.org/][org-mode]] (main tool), LaTeX
|
||||
- I know my way around LibreOffice, Microsoft Office, OnlyOffice, and
|
||||
WPS Office
|
||||
|
||||
|
||||
@@ -7,26 +7,25 @@ Je suis présent sur différentes plateformes et quelques réseaux
|
||||
sociaux où vous pouvez me suivre.
|
||||
|
||||
** Réseaux sociaux
|
||||
- {{{icon(mastodon)}}} *Mastodon* : [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] devrait
|
||||
fonctionner, sinon direction [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]]
|
||||
- {{{icon(twitter)}}} *Twitter* : [[https://twitter.com/phundrak][@phundrak]], cependant je n’y suis plus très
|
||||
- {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
|
||||
- {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], cependant je n’y suis plus très
|
||||
actif et j’y repartage principalement mes messages Mastodon qui
|
||||
parfois se font tronquer
|
||||
- {{{icon(writefreely)}}} *Writefreely* :
|
||||
- {{{icon(writefreely)}}} *Writefreely* ::
|
||||
- [[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
|
||||
- {{{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
|
||||
du pourriel)
|
||||
|
||||
** Autres plateformes
|
||||
- {{{icon(envelope)}}} *Courriel* : [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} *Blog* : [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} *Gitea* : [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} *GitHub* : [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} *YouTube* : [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} *Reddit*: [/u/phundrak](https://www.reddit.com/user/phundrak)
|
||||
- {{{icon(linkedin)}}} *LinkedIn*: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} *Twitch*: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
- {{{icon(envelope)}}} *Courriel* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
|
||||
- {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
|
||||
#+include: other-links
|
||||
|
||||
@@ -5,25 +5,24 @@
|
||||
On pote trova me sur multe loca ueb e redes sosial do on pote segue me.
|
||||
|
||||
** Redes sosial
|
||||
- {{{icon(mastodon)}}} Mastodon :: [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] ta debe funsiona,
|
||||
si no, visita [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]]
|
||||
- {{{icon(twitter)}}} Twitter :: [[https://twitter.com/phundrak][@phundrak]], ma me usa lo a poca veses, la
|
||||
- {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
|
||||
- {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], ma me usa lo a poca veses, la
|
||||
plu de mea tuitas es mea mesajes mastodon ce es a vesas truncada
|
||||
- {{{icon(writefreely)}}} Writefreely ::
|
||||
- {{{icon(writefreely)}}} *Writefreely* ::
|
||||
- [[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
|
||||
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)
|
||||
|
||||
** Other Websites
|
||||
- {{{icon(envelope)}}} Eposta :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} Blog :: [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} Gitea :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} GitHub :: [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} YouTube :: [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} Reddit :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
|
||||
- {{{icon(linkedin)}}} LinkedIn :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} Twitch :: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
- {{{icon(envelope)}}} *Eposta* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
|
||||
- {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
|
||||
- {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
|
||||
- {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
|
||||
- {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
|
||||
- {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
|
||||
- {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
|
||||
- {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
|
||||
|
||||
#+include: other-links
|
||||
|
||||
@@ -16,19 +16,15 @@ es an con tota estrema comun. Los capasi esa locas ueb a funsiona
|
||||
coreta o plu eficas.
|
||||
|
||||
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
|
||||
Matomo par sabe lo ce lo usores de esa loca ueb fa asi, ma Matomo
|
||||
trasa lo sola sur mea locas ueb.
|
||||
la lingua o la motif ce te ia eleje.
|
||||
|
||||
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
|
||||
me loca ueb o no.
|
||||
|
||||
*** Como me pote controla la cucis sur mea computa?
|
||||
Si te no vole ce Cloudflare o Matomo recorda cucis, un bon
|
||||
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.
|
||||
Si te no vole ce Cloudflare recorda cucis, un bon anti-comersial como
|
||||
[[https://ublockorigin.com/][uBlock Origin]] ta pote te proteje (es la plu eficas ce me conose).
|
||||
|
||||
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,
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
ajunta esa comersiales, o me ia dementi, o me es secuestrada e lo es
|
||||
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
|
||||
cambias de funsiona de mea loca ueb, o si me trova eras. Te pote trove
|
||||
la ultima refresci de esa pajina a supra.
|
||||
cambias de funsiona de mea loca ueb, o si me trova eras.
|
||||
|
||||
*** Me ave otra demandas
|
||||
** Me ave otra demandas
|
||||
Te pote scrive me un eposta a la adirije de eposta
|
||||
[[mailto:lucien@phundrak.com][lucien@phundrak.com]].
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Compania spesialida en la developa de cantantes virtual en franses ce
|
||||
usa sintese vocal. La produi la plu selebra es ALYS. Plu de informa
|
||||
[[./vocal-synthesis.md][aci]].
|
||||
|
||||
- Cofundor
|
||||
- Cofundor, dirije tecnical
|
||||
- Programi de voses de sintese per la canta
|
||||
- Rexerca linguistica
|
||||
- Suporta de usadores
|
||||
@@ -36,44 +36,42 @@ de [[./resume.md#voxwave-2014-2018][VoxWave]].
|
||||
|
||||
** Programi ueb
|
||||
*** Front-end
|
||||
- Usa fidosa de Angular, Vue e Node.JS
|
||||
- Bon conose de HTML5, CSS3 (incluinte SASS, SCSS e LESS) e Javascript
|
||||
- Conoses de Python, Dart e Typescript
|
||||
- Aprende React e Next.js
|
||||
- Usa profesal de Angular e TypeScript
|
||||
- Usa personal de Vue (inclui Nuxt)
|
||||
|
||||
*** Backend
|
||||
- Usa fidosa de Rust ([[https://actix.rs/][actix-web]] e [[https://rocket.rs/][Rocket]]) e Java Spring Boot
|
||||
- Usa profesional de Java SpringBoot e SpringBatch
|
||||
- Usa profesional e personal de PostgreSQL
|
||||
- Usa personal de Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] e [[https://rocket.rs/][Rocket]])
|
||||
- Esperia en programi de backend con Django (Python)
|
||||
- Esperia en comunica con banco de datos con [[https://diesel.rs][Diesel]] (Rust) e Django,
|
||||
conose alga EmacSQL
|
||||
- Usa de PostgreSQL e MySQL
|
||||
- Usa personal de PostgreSQL e SQLite
|
||||
|
||||
** Programi sistem
|
||||
- Esperia con Rust, C e EmacsLisp
|
||||
- Conoses de C++, Python, CommonLisp e shelles UNIX (bash, fish, eshell)
|
||||
- Conoses limitada de Prolog e Scheme
|
||||
- Usa personal e frecuente de Rust, C, shelles UNIX (bash, fish,
|
||||
Eshell) e EmacsLisp
|
||||
Usa personal nonfrecuente de C++, Python e CommonLisp
|
||||
|
||||
** Utiles de developa
|
||||
*** IDEs e editadores
|
||||
- Usa profesional de VS Code, Eclipse e Git
|
||||
- Conoses esperta de Emacs, inclui con la incluis de LSP e Git
|
||||
- Bon conoses de Git (inclui sua interfas Magit per Emacs), VS Code e
|
||||
Eclipse
|
||||
- Conoses fundal de Vim, CLion, PyCharm e WebStorm
|
||||
|
||||
** CI/CD e desplia ueb
|
||||
*** CI/CD e desplia ueb
|
||||
- Esperia con la servadores ueb Nginx e Caddyserver
|
||||
- Bon conoses de Docker, Drone.io e GitHub Actions per despia ueb
|
||||
- Bon conoses de Docker e Docker Compose, Drone.io e GitHub Actions
|
||||
per despia ueb
|
||||
|
||||
** Sistemes de opera
|
||||
- Usa et manejablia de Linux (Arch Linux, Void Linux, Debian, Ubuntu,
|
||||
Alpine Linux)
|
||||
Alpine Linux, NixOS)
|
||||
- Manjablia de servidores ueb e servidores de conserva (Arch Linux,
|
||||
Debian, Ubuntu, Alpine Linux)
|
||||
- Conosas fundal de Guix System, NixOS e Windows (de XP a 10, con
|
||||
eseta de Vista)
|
||||
Debian, Ubuntu, Alpine Linux, NixOS)
|
||||
- Conosas fundal de Guix System e Windows (de XP a 10, con eseta de
|
||||
Vista)
|
||||
|
||||
** Program de ofisia
|
||||
- Bon conosas con org-mode (Emacs) e LaTeX
|
||||
- Bon conosas con [[https://orgmode.org/][org-mode]] (Emacs) e LaTeX
|
||||
- Conosas con LibreOffice, Microsoft Office, WPS Office e OnlyOffice
|
||||
|
||||
** Audio
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
** Où est hébergé le site ?
|
||||
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,
|
||||
=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 se situent également en France.
|
||||
|
||||
@@ -23,7 +23,7 @@ Ces cookies ne sont pas et ne peuvent pas être utilisés pour vous
|
||||
traquer.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
sera sans doute plus rapide pour vous de chercher sur DuckDuckGo,
|
||||
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
|
||||
quelqu’un sur internet, ou même via des mails ou tout contenu web
|
||||
rendu à l’écran, comme pixels espions (des images extrêmement
|
||||
petites). Il est également possible de stocker des cookies Flash ou
|
||||
des objets locaux partagés.
|
||||
petites). Il est de plus possible de stocker des cookies Flash ou des
|
||||
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 ?
|
||||
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
|
||||
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
|
||||
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.
|
||||
@@ -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 ?
|
||||
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
|
||||
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.
|
||||
sur la page.
|
||||
|
||||
** J’ai d’autres questions
|
||||
Et je serai heureux d’y répondre par mail. Vous pouvez me contacter
|
||||
|
||||
@@ -20,7 +20,7 @@ Startup spécialisée dans le développement de chanteurs virtuels
|
||||
francophones utilisant de la synthèse vocale. Le produit le plus connu
|
||||
est la chanteuse virtuelle ALYS. Plus d’informations [[./vocal-synthesis.md][ici]].
|
||||
|
||||
- Co-fondateur
|
||||
- Co-fondateur, directeur technique
|
||||
- Programmation de voix de synthèse pour le chant
|
||||
- Recherches linguistiques
|
||||
- Support utilisateur
|
||||
@@ -38,32 +38,25 @@ LLCE. Études interrompues suite à la création de [[./resume.md#voxwave-2014-2
|
||||
|
||||
** Programmation Web
|
||||
*** Frontend
|
||||
- Utilisation régulière de Angular, Vue et Node.js
|
||||
- Bonnes connaissances en HTML5, CSS3 (y compris SASS, SCSS et LESS)
|
||||
et JavaScript
|
||||
- Connaissances en Python, Dart et TypeScript
|
||||
- Apprentissage de React et Next.js
|
||||
- Expérience professionnelle avec Angular et TypeScript
|
||||
- Expérience personnelle avec Vue (y compris Nuxt)
|
||||
|
||||
*** Backend
|
||||
- Utilisation régulière de Rust ([[https://actix.rs/][actix-web]] et [[https://rocket.rs/][Rocket]]) et Java Spring
|
||||
Boot
|
||||
- De l’expérience en développement backend avec Django (Python)
|
||||
- De l’expérience en communication avec des bases de données via
|
||||
Django et [[https://diesel.rs][Diesel]]. Connaissances de base avec EmacSQL.
|
||||
- Utilisation de MySQL et PostgreSQL.
|
||||
- Utilisation professionnelle de Java SpringBoot et SpringBatch
|
||||
- Utilisation professionnelle et personnelle de PostgreSQL
|
||||
- Utilisation personnelle de Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] et [[https://rocket.rs/][Rocket]])
|
||||
- Connaissances en développement backend avec Django (Python)
|
||||
- Utilisation personnelle de MySQL et SQLite
|
||||
|
||||
** Programmation Système
|
||||
- De l’expérience avec Rust, C et EmacsLisp
|
||||
- Connaissances en C++, Python, CommonLisp et les shells UNIX
|
||||
(bash, fish, Eshell)
|
||||
- Connaissances limitées en Prolog et Scheme
|
||||
- Utilisation personnelle fréquente de Rust, C, shells UNIX (bash, fish, Eshell) et EmacsLisp
|
||||
- Utilisation personnelle occasionnelle de C++, Python et CommonLisp
|
||||
|
||||
** Outils de développement
|
||||
*** IDEs et éditeurs de texte
|
||||
- Utilisateur avancé d’Emacs, y compris avec ses intégrations pour LSP
|
||||
et Git
|
||||
- Bonnes connaissances de Git (y compris avec son interface Magit pour
|
||||
Emacs), VS Code et Eclipse
|
||||
- Utilisation professionnelle de VS Code, Eclipse et Git
|
||||
- Utilisateur avancé personnelle d’Emacs, y compris avec ses
|
||||
intégrations pour LSP et Git
|
||||
- Connaissances basiques de Vim, CLion, PyCharm et WebStorm
|
||||
|
||||
*** CI/CD et déploiement sur le web
|
||||
@@ -73,14 +66,14 @@ LLCE. Études interrompues suite à la création de [[./resume.md#voxwave-2014-2
|
||||
|
||||
** Systèmes d’exploitation
|
||||
- Utilisation et administration de Linux (Arch Linux, Void Linux,
|
||||
Debian, Ubuntu, Alpine Linux)
|
||||
Debian, Ubuntu, Alpine Linux, NixOS)
|
||||
- Administration de serveurs web et serveurs de stockage (Arch Linux,
|
||||
Debian, Ubuntu, Alpine Linux)
|
||||
- Connaissances élémentaires de Guix System, NixOS et Windows de XP à
|
||||
10 (excepté Vista)
|
||||
Debian, Ubuntu, Alpine Linux, NixOS)
|
||||
- Connaissances élémentaires de Guix System et Windows de XP à 10
|
||||
(excepté Vista)
|
||||
|
||||
** Bureautique
|
||||
- Bonnes connaissances avec orgmode et LaTeX
|
||||
- Bonnes connaissances avec [[https://orgmode.org/][org mode]] et LaTeX
|
||||
- Connaissances avec Libre Office, Microsoft Office, WPS Office et OnlyOffice
|
||||
|
||||
** Audio
|
||||
|
||||
5090
package-lock.json
generated
Normal file
5090
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -3,28 +3,24 @@
|
||||
"version": "0.1.0",
|
||||
"description": "Static website of Phundrak",
|
||||
"main": "index.js",
|
||||
"repository": "https://labs.phundrak.com/phundrak/vuepress-www",
|
||||
"repository": "https://labs.phundrak.com/phundrak/phundrak.com",
|
||||
"author": "Lucien Cartier-Tilet <lucien@phundrak.com>",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"git-cliff": "^1.1.2",
|
||||
"vuepress": "2.0.0-beta.61"
|
||||
"@vuepress/bundler-vite": "2.0.0-rc.19",
|
||||
"@vuepress/plugin-slimsearch": "^2.0.0-rc.74",
|
||||
"@vuepress/plugin-umami-analytics": "^2.0.0-rc.74",
|
||||
"@vuepress/theme-default": "^2.0.0-rc.36",
|
||||
"sass-embedded": "^1.83.4",
|
||||
"vuepress": "2.0.0-rc.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"less": "^4.2.0",
|
||||
"nord": "^0.2.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vuepress dev content",
|
||||
"build": "vuepress build content"
|
||||
},
|
||||
"dependencies": {
|
||||
"less": "^4.1.3",
|
||||
"nord": "^0.2.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"vuepress-plugin-remove-html-extension": "^0.1.0"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
shell.nix
Normal file
6
shell.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
nodejs_22
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user