cleanup + better code blocks + redirects
This commit is contained in:
parent
703d1d7f08
commit
fa61a28160
@ -2,13 +2,13 @@
|
||||
export default new Map([
|
||||
["src/content/articles/en/after-effects-expressions.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Fen%2Fafter-effects-expressions.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/en/sci-hub-blocage.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Fen%2Fsci-hub-blocage.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/en/image-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Fen%2Fimage-full.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/en/the-day-I-jamd.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Fen%2Fthe-day-I-jamd.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/en/video-compression.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Fen%2Fvideo-compression.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/en/super-cookies.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Fen%2Fsuper-cookies.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/fr/sci-hub-blocage.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Ffr%2Fsci-hub-blocage.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/fr/buttons.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Ffr%2Fbuttons.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/fr/image-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Ffr%2Fimage-full.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/fr/super-cookies.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Ffr%2Fsuper-cookies.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/fr/sci-hub-blocage.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Ffr%2Fsci-hub-blocage.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/en/image-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Fen%2Fimage-full.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/fragments/en/super-cookies.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Ffragments%2Fen%2Fsuper-cookies.mdx&astroContentModuleFlag=true")],
|
||||
["src/content/articles/fr/the-day-I-jamd.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Farticles%2Ffr%2Fthe-day-I-jamd.mdx&astroContentModuleFlag=true")]]);
|
||||
|
206
.astro/content.d.ts
vendored
206
.astro/content.d.ts
vendored
@ -1,206 +0,0 @@
|
||||
declare module 'astro:content' {
|
||||
interface Render {
|
||||
'.mdx': Promise<{
|
||||
Content: import('astro').MarkdownInstance<{}>['Content'];
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
components: import('astro').MDXInstance<{}>['components'];
|
||||
}>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'astro:content' {
|
||||
export interface RenderResult {
|
||||
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
|
||||
headings: import('astro').MarkdownHeading[];
|
||||
remarkPluginFrontmatter: Record<string, any>;
|
||||
}
|
||||
interface Render {
|
||||
'.md': Promise<RenderResult>;
|
||||
}
|
||||
|
||||
export interface RenderedContent {
|
||||
html: string;
|
||||
metadata?: {
|
||||
imagePaths: Array<string>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'astro:content' {
|
||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
||||
|
||||
export type CollectionKey = keyof AnyEntryMap;
|
||||
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
||||
|
||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
||||
export type DataCollectionKey = keyof DataEntryMap;
|
||||
|
||||
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
||||
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
||||
ContentEntryMap[C]
|
||||
>['slug'];
|
||||
|
||||
/** @deprecated Use `getEntry` instead. */
|
||||
export function getEntryBySlug<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
// Note that this has to accept a regular string too, for SSR
|
||||
entrySlug: E,
|
||||
): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
|
||||
/** @deprecated Use `getEntry` instead. */
|
||||
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
|
||||
collection: C,
|
||||
entryId: E,
|
||||
): Promise<CollectionEntry<C>>;
|
||||
|
||||
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
|
||||
collection: C,
|
||||
filter?: (entry: CollectionEntry<C>) => entry is E,
|
||||
): Promise<E[]>;
|
||||
export function getCollection<C extends keyof AnyEntryMap>(
|
||||
collection: C,
|
||||
filter?: (entry: CollectionEntry<C>) => unknown,
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
|
||||
export function getEntry<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(entry: {
|
||||
collection: C;
|
||||
slug: E;
|
||||
}): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof DataEntryMap,
|
||||
E extends keyof DataEntryMap[C] | (string & {}),
|
||||
>(entry: {
|
||||
collection: C;
|
||||
id: E;
|
||||
}): E extends keyof DataEntryMap[C]
|
||||
? Promise<DataEntryMap[C][E]>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof ContentEntryMap,
|
||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
slug: E,
|
||||
): E extends ValidContentEntrySlug<C>
|
||||
? Promise<CollectionEntry<C>>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
export function getEntry<
|
||||
C extends keyof DataEntryMap,
|
||||
E extends keyof DataEntryMap[C] | (string & {}),
|
||||
>(
|
||||
collection: C,
|
||||
id: E,
|
||||
): E extends keyof DataEntryMap[C]
|
||||
? string extends keyof DataEntryMap[C]
|
||||
? Promise<DataEntryMap[C][E]> | undefined
|
||||
: Promise<DataEntryMap[C][E]>
|
||||
: Promise<CollectionEntry<C> | undefined>;
|
||||
|
||||
/** Resolve an array of entry references from the same collection */
|
||||
export function getEntries<C extends keyof ContentEntryMap>(
|
||||
entries: {
|
||||
collection: C;
|
||||
slug: ValidContentEntrySlug<C>;
|
||||
}[],
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
export function getEntries<C extends keyof DataEntryMap>(
|
||||
entries: {
|
||||
collection: C;
|
||||
id: keyof DataEntryMap[C];
|
||||
}[],
|
||||
): Promise<CollectionEntry<C>[]>;
|
||||
|
||||
export function render<C extends keyof AnyEntryMap>(
|
||||
entry: AnyEntryMap[C][string],
|
||||
): Promise<RenderResult>;
|
||||
|
||||
export function reference<C extends keyof AnyEntryMap>(
|
||||
collection: C,
|
||||
): import('astro/zod').ZodEffects<
|
||||
import('astro/zod').ZodString,
|
||||
C extends keyof ContentEntryMap
|
||||
? {
|
||||
collection: C;
|
||||
slug: ValidContentEntrySlug<C>;
|
||||
}
|
||||
: {
|
||||
collection: C;
|
||||
id: keyof DataEntryMap[C];
|
||||
}
|
||||
>;
|
||||
// Allow generic `string` to avoid excessive type errors in the config
|
||||
// if `dev` is not running to update as you edit.
|
||||
// Invalid collection names will be caught at build time.
|
||||
export function reference<C extends string>(
|
||||
collection: C,
|
||||
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
|
||||
|
||||
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
||||
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
|
||||
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
||||
>;
|
||||
|
||||
type ContentEntryMap = {
|
||||
|
||||
};
|
||||
|
||||
type DataEntryMap = {
|
||||
"HPsections": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "HPsections";
|
||||
data: InferEntrySchema<"HPsections">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
"articles": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "articles";
|
||||
data: InferEntrySchema<"articles">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
"fragments": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "fragments";
|
||||
data: InferEntrySchema<"fragments">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
"references": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "references";
|
||||
data: InferEntrySchema<"references">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
"veille": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
collection: "veille";
|
||||
data: InferEntrySchema<"veille">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
|
||||
};
|
||||
|
||||
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
||||
|
||||
export type ContentConfig = typeof import("../src/content.config.js");
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,30 +1,58 @@
|
||||
import { defineConfig } from 'astro/config'
|
||||
|
||||
import { transformerMetaHighlight } from '@shikijs/transformers'
|
||||
|
||||
// https://astro.build/config
|
||||
import mdx from '@astrojs/mdx'
|
||||
import sitemap from '@astrojs/sitemap'
|
||||
|
||||
// https://astro.build/config
|
||||
import { pluginLineNumbers } from '@expressive-code/plugin-line-numbers'
|
||||
import expressiveCode from 'astro-expressive-code'
|
||||
|
||||
export default defineConfig({
|
||||
site: 'https://www.nardu.in',
|
||||
build: {
|
||||
format: 'directory'
|
||||
},
|
||||
i18n: {
|
||||
locales: ['fr', 'en'],
|
||||
defaultLocale: 'fr'
|
||||
redirects: {
|
||||
'/en/': {
|
||||
status: 308,
|
||||
destination: '/articles/en-2025'
|
||||
},
|
||||
'/articles/en/': {
|
||||
status: 308,
|
||||
destination: '/articles/#en-articles'
|
||||
},
|
||||
'/articles/en/[...id]': {
|
||||
status: 308,
|
||||
destination: '/articles/en-[...id]'
|
||||
},
|
||||
'/snippets/en/': {
|
||||
status: 308,
|
||||
destination: '/fragments/#en-fragments'
|
||||
},
|
||||
'/snippets/en/[...id]': {
|
||||
status: 308,
|
||||
destination: '/fragments/en-[...id]'
|
||||
}
|
||||
},
|
||||
image: {
|
||||
domains: ['assets.nardu.in'],
|
||||
remotePatterns: [{ protocol: 'https' }]
|
||||
},
|
||||
integrations: [mdx(), sitemap()],
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
integrations: [
|
||||
expressiveCode({
|
||||
theme: 'one-dark-pro',
|
||||
transformers: [transformerMetaHighlight()]
|
||||
}
|
||||
}
|
||||
plugins: [pluginLineNumbers()],
|
||||
defaultProps: {
|
||||
// Disable line numbers by default
|
||||
showLineNumbers: false,
|
||||
// But enable line numbers for certain languages
|
||||
overridesByLang: {
|
||||
'css,html,js,ts,vue': {
|
||||
showLineNumbers: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
mdx(),
|
||||
sitemap()
|
||||
]
|
||||
})
|
||||
|
@ -14,7 +14,9 @@
|
||||
"@astrojs/rss": "4.0.10",
|
||||
"@astrojs/sitemap": "3.2.1",
|
||||
"@astrojs/ts-plugin": "^1.10.4",
|
||||
"@expressive-code/plugin-line-numbers": "^0.38.3",
|
||||
"astro": "5.1.1",
|
||||
"astro-expressive-code": "^0.38.3",
|
||||
"sharp": "^0.33.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
13
src/content/articles/en/2025.md
Normal file
13
src/content/articles/en/2025.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: Nico v3.0
|
||||
subtitle: Update 2025.
|
||||
lang: en
|
||||
slug: en-2023
|
||||
excerpt: So long i18n
|
||||
tags: ['Freelance']
|
||||
type: articles
|
||||
---
|
||||
|
||||
## This website no longer has an english version.
|
||||
|
||||
I have maintained an english version of my website for some years. But the
|
@ -13,7 +13,7 @@ updatedAt: '2022-12-27T12:08:00.000Z'
|
||||
|
||||
import AstroImage from '../../../components/AstroImage.astro'
|
||||
|
||||
The current sci-hub address is: <a href="https://sci-hub.se" rel="noreferer noopener">sci-hub.se</a>
|
||||
The current sci-hub address is: <a href="https://www.sci-hub.st/" rel="noreferer noopener">sci-hub.st</a>
|
||||
|
||||
## What is this about?
|
||||
|
||||
|
@ -12,7 +12,7 @@ updatedAt: '2022-12-27T12:08:00.000Z'
|
||||
|
||||
import AstroImage from '../../../components/AstroImage.astro'
|
||||
|
||||
L'adresse actuelle de sci-hub est : [sci-hub.se](https://sci-hub.se)
|
||||
L'adresse actuelle de sci-hub est : <a href="https://www.sci-hub.st/" rel="noreferer noopener">sci-hub.st</a>
|
||||
|
||||
## Résumé de la situation
|
||||
|
||||
|
@ -89,7 +89,7 @@ Limit TLS version to 1.2 and 1.3 (or just 1.3 as there is only a [5% compatibili
|
||||
|
||||
Use the [strict transport security](https://scotthelme.co.uk/hsts-the-missing-link-in-tls/) header.
|
||||
|
||||
```
|
||||
```http
|
||||
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
||||
```
|
||||
|
||||
@ -101,12 +101,12 @@ I've based my initial choices of ciphers on [this list](https://tls.imirhil.fr/c
|
||||
|
||||
I then asked [Aeris](https://twitter.com/aeris22), the creator of [tls.imirhil.fr](https://tls.imirhil.fr), about it and he advised me to use the following:
|
||||
|
||||
```
|
||||
```cypher
|
||||
ECDHE+AES:ECDHE+CHACHA20
|
||||
```
|
||||
|
||||
In order to achieve a perfect score, we can be a little more restrictive with:
|
||||
|
||||
```
|
||||
```cypher
|
||||
ECDHE+AES256:ECDHE+CHACHA20
|
||||
```
|
||||
|
@ -70,16 +70,16 @@ query {
|
||||
|
||||
#### Inside a page
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// index.vue
|
||||
<script>
|
||||
import homepageQuery from '~/graphql/queries/singles/homepage'
|
||||
|
||||
export default {
|
||||
async asyncData({ $graphql }) {
|
||||
const data = await $graphql.default.request(homepageQuery)
|
||||
return { data }
|
||||
},
|
||||
async asyncData({ $graphql }) {
|
||||
const data = await $graphql.default.request(homepageQuery)
|
||||
return { data }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@ -88,31 +88,29 @@ export default {
|
||||
|
||||
It is safer to wait until `fetch` has received a response before displaying anything. You can use `$fetchState` to be sure ([documentation](https://nuxtjs.org/docs/2.x/components-glossary/pages-fetch 'Documentation on the fetch hook (new tab)')).
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// Header.vue
|
||||
<template>
|
||||
<header v-if="!$fetchState.pending">
|
||||
…
|
||||
</header>
|
||||
<header v-if="!$fetchState.pending">…</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import headerQuery from '~/graphql/queries/singles/header'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
data: {},
|
||||
}
|
||||
},
|
||||
async fetch() {
|
||||
try {
|
||||
const data = await this.$graphql.default.request(headerQuery)
|
||||
this.data = data
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error, undefined, 2))
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: {}
|
||||
}
|
||||
},
|
||||
async fetch() {
|
||||
try {
|
||||
const data = await this.$graphql.default.request(headerQuery)
|
||||
this.data = data
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error, undefined, 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@ -121,20 +119,20 @@ export default {
|
||||
|
||||
To pass options to the request, for example for a multilingual version with [nuxt/i18n](https://i18n.nuxtjs.org/) and/or a url parameter in a dynamic page:
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// _slug.vue
|
||||
<script>
|
||||
import articleQuery from '~/graphql/queries/articles'
|
||||
|
||||
export default {
|
||||
async asyncData({ $graphql, app, params }) {
|
||||
const locale = app.i18n.localeProperties.iso
|
||||
const data = await $graphql.default.request(articleQuery, {
|
||||
code: locale,
|
||||
slug: params.slug,
|
||||
})
|
||||
return { data }
|
||||
},
|
||||
async asyncData({ $graphql, app, params }) {
|
||||
const locale = app.i18n.localeProperties.iso
|
||||
const data = await $graphql.default.request(articleQuery, {
|
||||
code: locale,
|
||||
slug: params.slug
|
||||
})
|
||||
return { data }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
@ -89,7 +89,7 @@ Limiter la version TLS à 1.2 et 1.3 (voire uniquement 1.3 vu [la différence de
|
||||
|
||||
Utiliser le header [strict transport security](https://scotthelme.co.uk/hsts-the-missing-link-in-tls/).
|
||||
|
||||
```
|
||||
```http
|
||||
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
||||
```
|
||||
|
||||
@ -101,12 +101,12 @@ J'avais basé ma première suite sur [cette liste](https://tls.imirhil.fr/cipher
|
||||
|
||||
J'ai ensuite demandé à [Aeris](https://twitter.com/aeris22), le créateur de [tls.imirhil.fr](https://tls.imirhil.fr), ses conseils sur cette suite. Il m'a recommandé d'utiliser :
|
||||
|
||||
```
|
||||
```cypher
|
||||
ECDHE+AES:ECDHE+CHACHA20
|
||||
```
|
||||
|
||||
Afin d'atteindre un score de 100/100, il est possible de restreindre un peu plus la suite comme ceci :
|
||||
|
||||
```
|
||||
```cypher
|
||||
ECDHE+AES256:ECDHE+CHACHA20
|
||||
```
|
||||
|
@ -27,6 +27,7 @@ On est parfois obligé d'utiliser des images dans des balises `img` plutôt que
|
||||
Considérons le html suivant :
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
<section class="container">
|
||||
<div class="hero">
|
||||
<img class="hero__image" src="hero.img" />
|
||||
@ -37,15 +38,15 @@ Considérons le html suivant :
|
||||
Et le style suivant :
|
||||
|
||||
```css
|
||||
/* style.css */
|
||||
.container {
|
||||
padding: 0 14px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 1040px;
|
||||
margin-inline: auto;
|
||||
max-inline-size: 1040px;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-inline-size: 100%;
|
||||
block-size: auto;
|
||||
}
|
||||
```
|
||||
|
||||
@ -60,10 +61,11 @@ img {
|
||||
Afin de faire prendre à l'image toute la largeur, on agit sur son conteneur :
|
||||
|
||||
```css
|
||||
/* style.css */
|
||||
.hero {
|
||||
margin-left: calc(50% - 50vw);
|
||||
margin-inline-start: calc(50% - 50vw);
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
inline-size: 100vw;
|
||||
}
|
||||
```
|
||||
|
||||
@ -77,12 +79,15 @@ Afin de faire prendre à l'image toute la largeur, on agit sur son conteneur&nbs
|
||||
|
||||
On peut alors réduire la hauteur du conteneur pour obtenir une bannière plutôt que l'image entière et faire correspondre la hauteur de l'image à la hauteur du conteneur :
|
||||
|
||||
```css
|
||||
```css title='style.css' ins={5, 7-9}
|
||||
.hero {
|
||||
height: 200px;
|
||||
margin-inline-start: calc(50% - 50vw);
|
||||
position: relative;
|
||||
inline-size: 100vw;
|
||||
block-size: 200px;
|
||||
}
|
||||
.hero__image {
|
||||
height: 100%;
|
||||
block-size: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
@ -94,9 +99,10 @@ On peut alors réduire la hauteur du conteneur pour obtenir une bannière plutô
|
||||
|
||||
Il faut ensuite forcer l'image à prendre toute la largeur du conteneur :
|
||||
|
||||
```css
|
||||
```css title='style.css' ins={3}
|
||||
.hero__image {
|
||||
width: 100%;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
@ -112,8 +118,10 @@ Pas top…
|
||||
|
||||
**ENFIN** le code magique pour redonner son ratio à l'image sans la déformer :
|
||||
|
||||
```css
|
||||
```css title='style.css' ins={4,5}
|
||||
.hero__image {
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center; /* à positionner comme on veut */
|
||||
}
|
||||
@ -125,22 +133,23 @@ Pas top…
|
||||
height='568'
|
||||
/>
|
||||
|
||||
Cette technique s'apparente à l'utilisation d'une image de background mais en dur 😁
|
||||
Cette technique s'apparente à l'utilisation d'une image de background.
|
||||
|
||||
## TL;DR
|
||||
|
||||
Le code complet :
|
||||
|
||||
```css
|
||||
/* style.css */
|
||||
.hero {
|
||||
margin-left: calc(50% - 50vw);
|
||||
margin-inline-start: calc(50% - 50vw);
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 200px;
|
||||
inline-size: 100vw;
|
||||
block-size: 200px;
|
||||
}
|
||||
.hero__image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
-o-object-position: center;
|
||||
|
@ -70,16 +70,16 @@ query {
|
||||
|
||||
#### Dans une page
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// index.vue
|
||||
<script>
|
||||
import homepageQuery from '~/graphql/queries/singles/homepage'
|
||||
|
||||
export default {
|
||||
async asyncData({ $graphql }) {
|
||||
const data = await $graphql.default.request(homepageQuery)
|
||||
return { data }
|
||||
},
|
||||
async asyncData({ $graphql }) {
|
||||
const data = await $graphql.default.request(homepageQuery)
|
||||
return { data }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@ -88,31 +88,29 @@ export default {
|
||||
|
||||
Il est plus prudent d'attendre que `fetch` ait reçu une réponse avant d'afficher quoi que ce soit. On peut utiliser `$fetchState` afin d'être tranquille ([documentation](https://fr.nuxtjs.org/docs/2.x/components-glossary/pages-fetch 'Documentation sur la méthode fetch (nouvel onglet)')).
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// Header.vue
|
||||
<template>
|
||||
<header v-if="!$fetchState.pending">
|
||||
…
|
||||
</header>
|
||||
<header v-if="!$fetchState.pending">…</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import headerQuery from '~/graphql/queries/singles/header'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
data: {},
|
||||
}
|
||||
},
|
||||
async fetch() {
|
||||
try {
|
||||
const data = await this.$graphql.default.request(headerQuery)
|
||||
this.data = data
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error, undefined, 2))
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: {}
|
||||
}
|
||||
},
|
||||
async fetch() {
|
||||
try {
|
||||
const data = await this.$graphql.default.request(headerQuery)
|
||||
this.data = data
|
||||
} catch (error) {
|
||||
console.error(JSON.stringify(error, undefined, 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@ -121,20 +119,20 @@ export default {
|
||||
|
||||
Pour passer des options à la requête, par exemple pour une version multilingue avec [nuxt/i18n](https://i18n.nuxtjs.org/ 'Documentation de nuxt i18n (nouvel onglet)') et/ou un paramètre d'url dans le cadre d'une page dynamique :
|
||||
|
||||
```javascript
|
||||
```vue
|
||||
// _slug.vue
|
||||
<script>
|
||||
import articleQuery from '~/graphql/queries/articles'
|
||||
|
||||
export default {
|
||||
async asyncData({ $graphql, app, params }) {
|
||||
const locale = app.i18n.localeProperties.iso
|
||||
const data = await $graphql.default.request(articleQuery, {
|
||||
code: locale,
|
||||
slug: params.slug,
|
||||
})
|
||||
return { data }
|
||||
},
|
||||
async asyncData({ $graphql, app, params }) {
|
||||
const locale = app.i18n.localeProperties.iso
|
||||
const data = await $graphql.default.request(articleQuery, {
|
||||
code: locale,
|
||||
slug: params.slug
|
||||
})
|
||||
return { data }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
@ -45,7 +45,7 @@ J'ai personnellement choisi de faire différemment. J'ai décidé d'utiliser un
|
||||
|
||||
### Le code
|
||||
|
||||
```css {1,4-6}
|
||||
```css {5,16} title="style.css"
|
||||
a {
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
import type { ArticleEntry } from 'src/content.config'
|
||||
import EditorialContent from '../../components/EditorialContent.astro'
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
// 1. Generate a new path for every collection entry
|
||||
export async function getStaticPaths() {
|
||||
const articles = await getCollection('articles')
|
||||
const articles: ArticleEntry[] = await getCollection('articles')
|
||||
return articles.map((article) => ({
|
||||
params: { id: article.data.slug },
|
||||
props: { article }
|
||||
|
@ -34,7 +34,7 @@ const pageTitle = 'Articles'
|
||||
<ListCards list={frArticles} routeName='articles' />
|
||||
</section>
|
||||
<section class='flow' lang='en'>
|
||||
<h3>In english</h3>
|
||||
<h3 id='en-articles'>In english</h3>
|
||||
<ListCards list={enArticles} routeName='articles' />
|
||||
</section>
|
||||
</section>
|
||||
|
@ -1,12 +1,13 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content'
|
||||
import EditorialContent from '../../components/EditorialContent.astro'
|
||||
|
||||
import type { FragmentEntry } from 'src/content.config'
|
||||
import EditorialContent from '../../components/EditorialContent.astro'
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro'
|
||||
|
||||
// 1. Generate a new path for every collection entry
|
||||
export async function getStaticPaths() {
|
||||
const fragments = await getCollection('fragments')
|
||||
const fragments: FragmentEntry[] = await getCollection('fragments')
|
||||
return fragments.map((fragment) => ({
|
||||
params: { id: fragment.data.slug },
|
||||
props: { fragment }
|
||||
|
@ -34,7 +34,7 @@ const pageTitle = 'Fragments'
|
||||
<ListCards list={frFragments} routeName='fragments' />
|
||||
</section>
|
||||
<section class='flow' lang='en'>
|
||||
<h3>In english</h3>
|
||||
<h3 id='en-fragments'>In english</h3>
|
||||
<ListCards list={enFragments} routeName='fragments' />
|
||||
</section>
|
||||
</section>
|
||||
|
@ -140,7 +140,6 @@ const allReferences = await getCollection('references')
|
||||
}
|
||||
.intro__subtitle {
|
||||
margin: var(--space-s-m) 0;
|
||||
font-family: 'wotfard';
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
color: var(--color-dark-blue);
|
||||
|
@ -30,7 +30,7 @@ EXCEPTIONS
|
||||
/*
|
||||
A flipped version where the sidebar is on the right
|
||||
*/
|
||||
.sidebar[data-direction="rtl"] {
|
||||
.sidebar[data-direction='rtl'] {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
|
@ -1,129 +1,131 @@
|
||||
.btn {
|
||||
padding: 12px 26px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s ease;
|
||||
padding: 12px 26px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
.btn-icon {
|
||||
background-color: hotpink;
|
||||
background-color: hotpink;
|
||||
}
|
||||
.btn-icon::before {
|
||||
content: url('~assets/svg/arrow-right-white.svg');
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate(40px, -50%);
|
||||
transition: transform ease 0.3s;
|
||||
content: url('~assets/svg/arrow-right-white.svg');
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate(40px, -50%);
|
||||
transition: transform ease 0.3s;
|
||||
}
|
||||
.btn-icon:hover,
|
||||
.btn-icon:focus {
|
||||
background-color: darkorchid;
|
||||
background-color: darkorchid;
|
||||
}
|
||||
.btn-icon:hover::before,
|
||||
.btn-icon:focus::before {
|
||||
transform: translate(-10px, -50%);
|
||||
transform: translate(-10px, -50%);
|
||||
}
|
||||
.btn-icon > span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.3s ease;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.btn-icon:hover > span,
|
||||
.btn-icon:focus > span {
|
||||
transform: translateX(-10px);
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
|
||||
.btn-rideau {
|
||||
border: 2px solid var(--dark);
|
||||
color: var(--dark);
|
||||
background-color: transparent;
|
||||
transition: color 0.3s ease, border-color 0.3s ease;
|
||||
border: 2px solid var(--dark);
|
||||
color: var(--dark);
|
||||
background-color: transparent;
|
||||
transition:
|
||||
color 0.3s ease,
|
||||
border-color 0.3s ease;
|
||||
}
|
||||
.btn-rideau:hover {
|
||||
color: white;
|
||||
border-color: darkorchid;
|
||||
color: white;
|
||||
border-color: darkorchid;
|
||||
}
|
||||
.btn-rideau::before {
|
||||
background: hotpink;
|
||||
background: hotpink;
|
||||
}
|
||||
.btn-rideau::after {
|
||||
background: darkorchid;
|
||||
background: darkorchid;
|
||||
}
|
||||
.btn-rideau::before,
|
||||
.btn-rideau::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
transition: transform 0.3s;
|
||||
transition-timing-function: ease;
|
||||
transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1);
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
transition: transform 0.3s;
|
||||
transition-timing-function: ease;
|
||||
transition-timing-function: cubic-bezier(0.75, 0, 0.125, 1);
|
||||
}
|
||||
.btn-rideau:hover::before,
|
||||
.btn-rideau:hover::after,
|
||||
.btn-rideau:focus::before,
|
||||
.btn-rideau:focus::after {
|
||||
transform: translateY(100%);
|
||||
transform: translateY(100%);
|
||||
}
|
||||
.btn-rideau:hover::after,
|
||||
.btn-rideau:focus::after {
|
||||
transition-delay: 0.175s;
|
||||
transition-delay: 0.175s;
|
||||
}
|
||||
|
||||
.btn-gradient {
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
background-position: 0% 50%;
|
||||
animation: GradientReverse 0.5s ease 1 normal forwards;
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
background-position: 0% 50%;
|
||||
animation: GradientReverse 0.5s ease 1 normal forwards;
|
||||
}
|
||||
.btn-gradient:hover,
|
||||
.btn-gradient:focus {
|
||||
animation: Gradient 0.5s ease 1 normal forwards;
|
||||
animation: Gradient 0.5s ease 1 normal forwards;
|
||||
}
|
||||
@keyframes Gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
@keyframes GradientReverse {
|
||||
0% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
0% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-scale {
|
||||
overflow: visible;
|
||||
color: #10113a;
|
||||
background-color: transparent;
|
||||
overflow: visible;
|
||||
color: #10113a;
|
||||
background-color: transparent;
|
||||
}
|
||||
.btn-scale::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border: 2px solid #10113a;
|
||||
border-radius: 2px;
|
||||
transition: transform 0.3s ease;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border: 2px solid #10113a;
|
||||
border-radius: 2px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.btn-scale:hover::after,
|
||||
.btn-scale:focus::after {
|
||||
transform: scale(1.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "wotfard";
|
||||
src: url("../../fonts/wotfard/wotfard-medium-webfont.woff2") format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "wotfard";
|
||||
src: url("../../fonts/wotfard/wotfard-semibold-webfont.woff2") format("woff2");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "wotfard";
|
||||
src: url("../../fonts/wotfard/wotfard-regular-webfont.woff2") format("woff2");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/*
|
||||
* reduces Cumulative Layout Shift
|
||||
* https://www.24joursdeweb.fr/2021/performance-web-lintegrateur-ce-heros/
|
||||
*/
|
||||
@font-face {
|
||||
font-family: "ArialReplace";
|
||||
src: local("Arial");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 96%;
|
||||
letter-spacing: 1px;
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
body {
|
||||
font-family: var(--font-primary);
|
||||
font-size: var(--size-0);
|
||||
line-height: 1.5;
|
||||
line-height: 1.4;
|
||||
color: var(--color-dark);
|
||||
background-color: var(--color-light-white);
|
||||
accent-color: var(--color-brique);
|
||||
@ -204,46 +204,8 @@ blockquote code {
|
||||
|
||||
/* code highlight */
|
||||
|
||||
.astro-code,
|
||||
code {
|
||||
font-size: var(--size--1);
|
||||
font-family: var(--font-code);
|
||||
}
|
||||
.astro-code {
|
||||
position: relative;
|
||||
border-radius: var(--radius-small);
|
||||
padding-block: var(--space-xs);
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
-moz-tab-size: 2;
|
||||
-o-tab-size: 2;
|
||||
tab-size: 2;
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
|
||||
code {
|
||||
padding-inline: var(--space-s);
|
||||
white-space: pre-wrap;
|
||||
display: block;
|
||||
inline-size: fit-content;
|
||||
min-inline-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
&.highlighted::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
inline-size: 100%;
|
||||
block-size: 1lh;
|
||||
inset-inline-start: 0;
|
||||
background-color: hsla(0, 0%, 80%, 0.1);
|
||||
}
|
||||
background-color: var(--color-light-grey);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* RESET */
|
||||
|
||||
:root {
|
||||
--font-tnum: "tnum" on;
|
||||
--font-tnum: 'tnum' on;
|
||||
}
|
||||
|
||||
* {
|
||||
@ -29,7 +29,7 @@
|
||||
}
|
||||
@supports (font-variant-numeric: tabular-nums) {
|
||||
html {
|
||||
--font-tnum: "____";
|
||||
--font-tnum: '____';
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ body {
|
||||
|
||||
/* Remove built-in form typography styles */
|
||||
:where(input, button, textarea, select),
|
||||
:where(input[type="file"])::-webkit-file-upload-button {
|
||||
:where(input[type='file'])::-webkit-file-upload-button {
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
font-size: inherit;
|
||||
@ -113,7 +113,7 @@ body {
|
||||
}
|
||||
|
||||
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
|
||||
:where(ul, ol)[role="list"] {
|
||||
:where(ul, ol)[role='list'] {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@ -124,24 +124,24 @@ a:not([class]) {
|
||||
|
||||
/* Make it clear that interactive elements are interactive */
|
||||
:where(
|
||||
a[href],
|
||||
area,
|
||||
button,
|
||||
input,
|
||||
label[for],
|
||||
select,
|
||||
summary,
|
||||
textarea,
|
||||
[tabindex]:not([tabindex*="-"])
|
||||
) {
|
||||
a[href],
|
||||
area,
|
||||
button,
|
||||
input,
|
||||
label[for],
|
||||
select,
|
||||
summary,
|
||||
textarea,
|
||||
[tabindex]:not([tabindex*='-'])
|
||||
) {
|
||||
cursor: pointer;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
:where(input[type="file"]) {
|
||||
:where(input[type='file']) {
|
||||
cursor: auto;
|
||||
}
|
||||
:where(input[type="file"])::-webkit-file-upload-button,
|
||||
:where(input[type="file"])::file-selector-button {
|
||||
:where(input[type='file'])::-webkit-file-upload-button,
|
||||
:where(input[type='file'])::file-selector-button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -160,14 +160,14 @@ a:not([class]) {
|
||||
|
||||
/* Make sure users can't select button text */
|
||||
:where(
|
||||
button,
|
||||
button[type],
|
||||
input[type="button"],
|
||||
input[type="submit"],
|
||||
input[type="reset"]
|
||||
),
|
||||
:where(input[type="file"])::-webkit-file-upload-button,
|
||||
:where(input[type="file"])::file-selector-button {
|
||||
button,
|
||||
button[type],
|
||||
input[type='button'],
|
||||
input[type='submit'],
|
||||
input[type='reset']
|
||||
),
|
||||
:where(input[type='file'])::-webkit-file-upload-button,
|
||||
:where(input[type='file'])::file-selector-button {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
@ -178,9 +178,9 @@ a:not([class]) {
|
||||
:where(
|
||||
button,
|
||||
button[type],
|
||||
input[type="button"],
|
||||
input[type="submit"],
|
||||
input[type="reset"]
|
||||
input[type='button'],
|
||||
input[type='submit'],
|
||||
input[type='reset']
|
||||
)[disabled] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -51,10 +51,10 @@
|
||||
--space-l-3xl: clamp(2.25rem, calc(-0.08rem + 11.67vw), 7.5rem);
|
||||
|
||||
/* fonts */
|
||||
--font-primary: "wotfard", "ArialReplace", sans-serif;
|
||||
--font-secondary: "recoleta", Palatino, serif;
|
||||
--font-code: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||
--font-tnum: "tnum" on;
|
||||
--font-primary: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||
Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
--font-code: monospace;
|
||||
--font-tnum: 'tnum' on;
|
||||
|
||||
/* colors */
|
||||
--color-dark: hsl(239, 57%, 15%);
|
||||
|
@ -1,18 +1,10 @@
|
||||
/* @import "open-props/style"; */
|
||||
/* @import "open-props/normalize"; */
|
||||
@import './global/reset.css';
|
||||
@import './global/variables.css';
|
||||
@import './global/global-styles.css';
|
||||
|
||||
@import "./global/reset.css";
|
||||
@import "./global/fonts.css";
|
||||
@import "./global/variables.css";
|
||||
@import "./global/global-styles.css";
|
||||
@import './compositions/grid.css';
|
||||
@import './compositions/sidebar.css';
|
||||
|
||||
@import "./compositions/grid.css";
|
||||
@import "./compositions/sidebar.css";
|
||||
|
||||
@import "./utilities/flow.css";
|
||||
@import "./utilities/region.css";
|
||||
@import "./utilities/wrapper.css";
|
||||
|
||||
/* @import-glob './blocks/*.css'; */
|
||||
/* @import-glob './compositions/*.css'; */
|
||||
/* @import-glob './utilities/*.css'; */
|
||||
@import './utilities/flow.css';
|
||||
@import './utilities/region.css';
|
||||
@import './utilities/wrapper.css';
|
||||
|
@ -1,71 +0,0 @@
|
||||
.waves {
|
||||
background: transparent;
|
||||
block-size: 4px;
|
||||
position: relative;
|
||||
}
|
||||
.waves::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-repeat: repeat;
|
||||
block-size: 10px;
|
||||
background-size: 20px 20px;
|
||||
background-image: radial-gradient(
|
||||
circle at 10px -5px,
|
||||
transparent 12px,
|
||||
var(--waves-color, var(--color-white)) 13px
|
||||
);
|
||||
}
|
||||
.waves::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-repeat: repeat;
|
||||
block-size: 15px;
|
||||
background-size: 40px 20px;
|
||||
background-image: radial-gradient(
|
||||
circle at 10px 15px,
|
||||
var(--waves-color, var(--color-white)) 12px,
|
||||
transparent 13px
|
||||
);
|
||||
}
|
||||
|
||||
/* LARGE */
|
||||
.waves-container {
|
||||
block-size: 30px;
|
||||
position: relative;
|
||||
}
|
||||
.waves--large {
|
||||
position: absolute;
|
||||
block-size: 30px;
|
||||
inline-size: 100%;
|
||||
background: var(--waves-color, var(--color-light));
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.waves--large::before,
|
||||
.waves--large::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
border-radius: 100% 50%;
|
||||
}
|
||||
|
||||
.waves--large::before {
|
||||
inline-size: 55%;
|
||||
block-size: 100%;
|
||||
background-color: var(--waves-color, var(--color-light));
|
||||
left: -1.5%;
|
||||
top: 40%;
|
||||
}
|
||||
.waves--large::after {
|
||||
inline-size: 55%;
|
||||
block-size: 109%;
|
||||
background-color: var(--waves-bg-color, var(--color-white));
|
||||
right: -1.5%;
|
||||
top: 60%;
|
||||
}
|
@ -32,6 +32,7 @@
|
||||
grid-column: full;
|
||||
}
|
||||
/* set full width color to full grid */
|
||||
/* prettier-ignore */
|
||||
.wrapper.full-width-color {
|
||||
/* https://codepen.io/t_afif/pen/oNEaqQX */
|
||||
border-image: conic-gradient(var(--color-full-width, var(--color-light)) 0 0)
|
||||
|
271
src/styles/vendor/one-dark-pro.css
vendored
271
src/styles/vendor/one-dark-pro.css
vendored
@ -1,271 +0,0 @@
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"],
|
||||
:not(pre) > code {
|
||||
color: #abb2bf;
|
||||
background: none;
|
||||
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||
font-size: var(--size--1);
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 2;
|
||||
-o-tab-size: 2;
|
||||
tab-size: 2;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: var(--space-2xs-xs) var(--space-xs-s);
|
||||
margin: var(--space-2xs-xs) 0;
|
||||
overflow: auto;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #282c34;
|
||||
}
|
||||
:not(pre) > code[class*="language-"],
|
||||
:not(pre) > code {
|
||||
padding: 0.2em;
|
||||
white-space: normal;
|
||||
color: var(--color-dark);
|
||||
border-radius: 0.3em;
|
||||
background-color: var(--color-light-grey);
|
||||
}
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
background: rgba(148, 170, 209, 0.2);
|
||||
}
|
||||
|
||||
/* General styling */
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata,
|
||||
.token.punctuation {
|
||||
color: #abb2bf;
|
||||
}
|
||||
|
||||
.token.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.token.keyword,
|
||||
.token.regex,
|
||||
.token.important {
|
||||
color: #c678dd;
|
||||
}
|
||||
.token.property,
|
||||
.token.attr-name,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #e06c75;
|
||||
}
|
||||
|
||||
.token.unit {
|
||||
color: #2f02d1;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.selector,
|
||||
.token.tag,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string,
|
||||
.token.variable {
|
||||
color: #ce004b;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.pseudo-element,
|
||||
.token.pseudo-class,
|
||||
.token.attr-value,
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #abb2bf;
|
||||
}
|
||||
|
||||
.token.atrule {
|
||||
color: #c678dd;
|
||||
}
|
||||
|
||||
.token.string {
|
||||
color: #10113a;
|
||||
}
|
||||
|
||||
/* Specific styling */
|
||||
.language-html .token.doctype-tag {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-html .token.name {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-html .token.punctuation {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-html .token.tag .token.tag {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-html .token.tag .token.attr-name {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-html .token.tag .token.attr-value {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-html .token.tag .token.attr-value .token.punctuation {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-html .token.tag .token.attr-value .token.punctuation.attr-equals {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-html .token.comment {
|
||||
color: #7f848e;
|
||||
font-style: italic;
|
||||
}
|
||||
code[class*="language-css"],
|
||||
pre[class*="language-css"] {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-css .token.operator,
|
||||
.language-css .token.punctuation,
|
||||
.language-css .token.property,
|
||||
.language-css .token.operator,
|
||||
.language-css .token.combinator {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-css .token.attr-name,
|
||||
.language-css .token.color,
|
||||
.language-css .token.number,
|
||||
.language-css .token.class {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-css .token.attr-value,
|
||||
.language-css .token.string {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-css .token.selector,
|
||||
.language-css .token.unit {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-css .token.property.prefix,
|
||||
.language-css .token.pseudo-element,
|
||||
.language-css .token.pseudo-class {
|
||||
color: #56b6c2;
|
||||
}
|
||||
.language-css .token.atrule {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-css .token.atrule .token.rule {
|
||||
color: #c678dd;
|
||||
}
|
||||
.language-css .token.comment {
|
||||
color: #7f848e;
|
||||
font-style: italic;
|
||||
}
|
||||
.language-css .token.keyword {
|
||||
color: #56b6c2;
|
||||
}
|
||||
code[class*="language-javascript"],
|
||||
pre[class*="language-javascript"] {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-javascript {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-javascript .token.punctuation {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-javascript .token.comment {
|
||||
color: #7f848e;
|
||||
font-style: italic;
|
||||
}
|
||||
.language-javascript .token.keyword.this,
|
||||
.language-javascript .token.dom.variable,
|
||||
.language-javascript .token.class-name {
|
||||
color: #e5c07b;
|
||||
}
|
||||
.language-javascript .token.null,
|
||||
.language-javascript .token.boolean,
|
||||
.language-javascript .token.number {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-javascript .token.property-access,
|
||||
.language-javascript .token.imports,
|
||||
.language-javascript .token.parameter {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-javascript .token.parameter {
|
||||
font-style: italic;
|
||||
}
|
||||
.language-javascript .token.keyword {
|
||||
color: #c678dd;
|
||||
}
|
||||
.language-javascript .token.function,
|
||||
.language-javascript .token.property-access.function.method {
|
||||
color: #61afef;
|
||||
}
|
||||
.language-javascript .token.regex-source,
|
||||
.language-javascript .token.operator {
|
||||
color: #56b6c2;
|
||||
}
|
||||
.language-javascript .token.regex-delimiter,
|
||||
.language-javascript .token.string {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-json .token.punctuation,
|
||||
.language-json .token.operator {
|
||||
color: #abb2bf;
|
||||
}
|
||||
.language-json .token.string {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-json .token.boolean,
|
||||
.language-json .token.number,
|
||||
.language-json .token.null.keyword {
|
||||
color: #d19a66;
|
||||
}
|
||||
.language-json .token.property {
|
||||
color: #e06c75;
|
||||
}
|
||||
.language-bash .token.string,
|
||||
.language-shell .token.string {
|
||||
color: #98c379;
|
||||
}
|
||||
.language-bash .token.shebang.important,
|
||||
.language-bash .token.comment,
|
||||
.language-shell .token.shebang.important,
|
||||
.language-shell .token.comment {
|
||||
color: #7f848e;
|
||||
font-style: italic;
|
||||
}
|
||||
.language-bash .token.builtin.class-name,
|
||||
.language-bash .token.entity,
|
||||
.language-shell .token.builtin.class-name,
|
||||
.language-shell .token.entity {
|
||||
color: #56b6c2;
|
||||
}
|
||||
.language-bash .token.keyword,
|
||||
.language-shell .token.keyword {
|
||||
color: #c678dd;
|
||||
}
|
||||
.language-bash .token.variable,
|
||||
.language-shell .token.variable {
|
||||
color: #e06c75;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import { defaultLang, ui } from '../i18n/ui'
|
||||
|
||||
export function getLangFromUrl(url: URL) {
|
||||
const [, lang] = url.pathname.split('/')
|
||||
if (lang in ui) return lang as keyof typeof ui
|
||||
return defaultLang
|
||||
}
|
||||
|
||||
type NestedKeyOf<T> = {
|
||||
[K in keyof T]: T[K] extends object
|
||||
? `${K & string}.${NestedKeyOf<T[K]> & string}`
|
||||
: K & string
|
||||
}[keyof T]
|
||||
|
||||
export function useTranslations(lang: keyof typeof ui) {
|
||||
return function t(key: NestedKeyOf<(typeof ui)[typeof defaultLang]>) {
|
||||
const keys = key.split('.')
|
||||
let value = ui[lang]
|
||||
let fallback = ui[defaultLang]
|
||||
|
||||
for (const k of keys) {
|
||||
value = value?.[k]
|
||||
fallback = fallback?.[k]
|
||||
}
|
||||
|
||||
return value || fallback
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user