mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
270920111a
|
|||
d91feb8de4
|
|||
e68cb08a6f
|
|||
09d677bd37
|
|||
db1159f20c
|
|||
af5c845e4b
|
|||
3f66dfe46e
|
|||
d52a0c6f08
|
@ -32,7 +32,7 @@ The commit message guidelines adheres to [Conventional Commits](https://www.conv
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- [Node.js](https://nodejs.org/) >= 22.0.0
|
- [Node.js](https://nodejs.org/) >= 22.0.0
|
||||||
- [pnpm](https://pnpm.io/) >= 9.12.3 [(`corepack enable`)](https://nodejs.org/docs/latest-v22.x/api/corepack.html)
|
- [pnpm](https://pnpm.io/) >= 9.15.0 [(`corepack enable`)](https://nodejs.org/docs/latest-v22.x/api/corepack.html)
|
||||||
- [Docker](https://www.docker.com/)
|
- [Docker](https://www.docker.com/)
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
@ -13,7 +13,8 @@ const config: TestRunnerConfig = {
|
|||||||
async postVisit(page, context) {
|
async postVisit(page, context) {
|
||||||
const storyContext = await getStoryContext(page, context)
|
const storyContext = await getStoryContext(page, context)
|
||||||
|
|
||||||
if (storyContext.parameters?.a11y?.disable) {
|
const isA11yDisabled = storyContext.parameters?.a11y?.disable as boolean
|
||||||
|
if (isA11yDisabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/storybook",
|
"name": "@repo/storybook",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM node:22.11.0-slim AS node-pnpm
|
FROM node:22.13.1-slim AS node-pnpm
|
||||||
ENV PNPM_HOME="/pnpm"
|
ENV PNPM_HOME="/pnpm"
|
||||||
ENV PATH="$PNPM_HOME:$PATH"
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
@ -8,7 +8,7 @@ WORKDIR /usr/src/app
|
|||||||
|
|
||||||
FROM node-pnpm AS builder
|
FROM node-pnpm AS builder
|
||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
RUN pnpm install --global turbo@2.2.3
|
RUN pnpm install --global turbo@2.3.3
|
||||||
RUN turbo prune @repo/website --docker
|
RUN turbo prune @repo/website --docker
|
||||||
|
|
||||||
FROM node-pnpm AS installer
|
FROM node-pnpm AS installer
|
||||||
|
@ -9,6 +9,9 @@ import {
|
|||||||
getTranslations,
|
getTranslations,
|
||||||
setRequestLocale,
|
setRequestLocale,
|
||||||
} from "next-intl/server"
|
} from "next-intl/server"
|
||||||
|
import Script from "next/script"
|
||||||
|
|
||||||
|
const DOMAIN = "theoludwig.fr"
|
||||||
|
|
||||||
export const generateMetadata = async ({
|
export const generateMetadata = async ({
|
||||||
params,
|
params,
|
||||||
@ -18,7 +21,7 @@ export const generateMetadata = async ({
|
|||||||
const title = t("meta.title")
|
const title = t("meta.title")
|
||||||
const description = `${title} - ${t("meta.description")}`
|
const description = `${title} - ${t("meta.description")}`
|
||||||
const image = "/images/logo.webp"
|
const image = "/images/logo.webp"
|
||||||
const url = new URL("https://theoludwig.fr")
|
const url = new URL(`https://${DOMAIN}`)
|
||||||
const locales = LOCALES.join(", ")
|
const locales = LOCALES.join(", ")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -74,6 +77,12 @@ const LocaleLayout: React.FC<LocaleLayoutProps> = async (props) => {
|
|||||||
<NextIntlClientProvider messages={messages}>
|
<NextIntlClientProvider messages={messages}>
|
||||||
{children}
|
{children}
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
|
|
||||||
|
<Script
|
||||||
|
defer
|
||||||
|
data-domain={DOMAIN}
|
||||||
|
src="https://plausible.theoludwig.fr/js/script.js"
|
||||||
|
/>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
|
@ -9,10 +9,6 @@ const nextConfig = {
|
|||||||
unoptimized: true,
|
unoptimized: true,
|
||||||
},
|
},
|
||||||
compress: false,
|
compress: false,
|
||||||
|
|
||||||
// https://github.com/hashicorp/next-mdx-remote/issues/436#issuecomment-2066971842
|
|
||||||
transpilePackages: ["next-mdx-remote", "shiki"],
|
|
||||||
|
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/website",
|
"name": "@repo/website",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"imports": {
|
"imports": {
|
||||||
@ -19,6 +19,9 @@
|
|||||||
"@repo/utils": "workspace:*",
|
"@repo/utils": "workspace:*",
|
||||||
"@repo/i18n": "workspace:*",
|
"@repo/i18n": "workspace:*",
|
||||||
"@repo/ui": "workspace:*",
|
"@repo/ui": "workspace:*",
|
||||||
|
"@mdx-js/mdx": "catalog:",
|
||||||
|
"next-mdx-remote": "catalog:",
|
||||||
|
"shiki": "catalog:",
|
||||||
"next": "catalog:",
|
"next": "catalog:",
|
||||||
"next-intl": "catalog:",
|
"next-intl": "catalog:",
|
||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "repo",
|
"name": "repo",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
|
"packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.0.0",
|
"node": ">=22.0.0",
|
||||||
"pnpm": ">=9.12.3"
|
"pnpm": ">=9.15.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/blog",
|
"name": "@repo/blog",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -103,13 +103,14 @@ export const BlogPostContent: React.FC<BlogPostContentProps> = async (
|
|||||||
},
|
},
|
||||||
a: (props) => {
|
a: (props) => {
|
||||||
const { href = "", ...rest } = props
|
const { href = "", ...rest } = props
|
||||||
if (href.startsWith("#")) {
|
const hrefString = href as string
|
||||||
|
if (hrefString.startsWith("#")) {
|
||||||
return <a {...props} />
|
return <a {...props} />
|
||||||
}
|
}
|
||||||
if (href.startsWith("../posts/")) {
|
if (hrefString.startsWith("../posts/")) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={href
|
href={hrefString
|
||||||
.replace("../posts/", "/blog/")
|
.replace("../posts/", "/blog/")
|
||||||
.replace(".md", "")}
|
.replace(".md", "")}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
import typescriptESLint from "typescript-eslint"
|
||||||
import configConventions from "eslint-config-conventions"
|
import configConventions from "eslint-config-conventions"
|
||||||
import importX from "eslint-plugin-import-x"
|
import importX from "eslint-plugin-import-x"
|
||||||
import unicorn from "eslint-plugin-unicorn"
|
|
||||||
|
|
||||||
export default typescriptESLint.config(
|
export default typescriptESLint.config(
|
||||||
{
|
{
|
||||||
@ -20,7 +19,6 @@ export default typescriptESLint.config(
|
|||||||
name: "config-eslint",
|
name: "config-eslint",
|
||||||
plugins: {
|
plugins: {
|
||||||
"import-x": importX,
|
"import-x": importX,
|
||||||
unicorn,
|
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"import-x/extensions": [
|
"import-x/extensions": [
|
||||||
@ -33,8 +31,6 @@ export default typescriptESLint.config(
|
|||||||
jsx: "never",
|
jsx: "never",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"unicorn/explicit-length-check": "error",
|
|
||||||
"unicorn/consistent-destructuring": "off",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/eslint-config",
|
"name": "@repo/eslint-config",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/config-tailwind",
|
"name": "@repo/config-tailwind",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./tailwind.config.js",
|
"main": "./tailwind.config.js",
|
||||||
|
@ -155,10 +155,6 @@ code .line::before {
|
|||||||
word-break: normal;
|
word-break: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
code .line:last-child {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.katex .base {
|
.katex .base {
|
||||||
display: inline !important;
|
display: inline !important;
|
||||||
white-space: normal !important;
|
white-space: normal !important;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import typographyPlugin from "@tailwindcss/typography"
|
import typographyPlugin from "@tailwindcss/typography"
|
||||||
import { fontFamily } from "tailwindcss/defaultTheme"
|
|
||||||
|
|
||||||
/** @type {Omit<import('tailwindcss').Config, "content">} */
|
/** @type {Omit<import('tailwindcss').Config, "content">} */
|
||||||
const config = {
|
const config = {
|
||||||
@ -29,7 +28,7 @@ const config = {
|
|||||||
lightFlag: "0px 1px 10px rgba(0, 0, 0, 0.25)",
|
lightFlag: "0px 1px 10px rgba(0, 0, 0, 0.25)",
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ["'Montserrat'", ...fontFamily.sans],
|
sans: ["Montserrat", "sans-serif"],
|
||||||
},
|
},
|
||||||
typography: {
|
typography: {
|
||||||
DEFAULT: {
|
DEFAULT: {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/config-typescript",
|
"name": "@repo/config-typescript",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"files": [
|
"files": [
|
||||||
"tsconfig.json"
|
"tsconfig.json"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/i18n",
|
"name": "@repo/i18n",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/react-hooks",
|
"name": "@repo/react-hooks",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/ui",
|
"name": "@repo/ui",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/utils",
|
"name": "@repo/utils",
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -11,7 +11,7 @@ export const LOCALE_PREFIX = "never"
|
|||||||
|
|
||||||
export const THEMES = ["light", "dark"] as const
|
export const THEMES = ["light", "dark"] as const
|
||||||
export type Theme = (typeof THEMES)[number]
|
export type Theme = (typeof THEMES)[number]
|
||||||
export const THEME_DEFAULT = "light" as Theme
|
export const THEME_DEFAULT = "light" satisfies Theme
|
||||||
|
|
||||||
export const TIMEZONE = process.env["TZ"] ?? "UTC"
|
export const TIMEZONE = process.env["TZ"] ?? "UTC"
|
||||||
|
|
||||||
|
4541
pnpm-lock.yaml
generated
4541
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ packages:
|
|||||||
|
|
||||||
catalog:
|
catalog:
|
||||||
# Turborepo and Releases
|
# Turborepo and Releases
|
||||||
"turbo": "2.2.3"
|
"turbo": "2.3.3"
|
||||||
"@saithodev/semantic-release-backmerge": "4.0.1"
|
"@saithodev/semantic-release-backmerge": "4.0.1"
|
||||||
"@semantic-release/exec": "6.0.3"
|
"@semantic-release/exec": "6.0.3"
|
||||||
"@semantic-release/git": "10.0.1"
|
"@semantic-release/git": "10.0.1"
|
||||||
@ -15,90 +15,90 @@ catalog:
|
|||||||
"deepmerge": "4.3.1"
|
"deepmerge": "4.3.1"
|
||||||
|
|
||||||
# React.js/Next.js
|
# React.js/Next.js
|
||||||
"next": "15.0.3"
|
"next": "15.0.4"
|
||||||
"next-intl": "3.25.0"
|
"next-intl": "3.26.0"
|
||||||
"next-themes": "0.4.3"
|
"next-themes": "0.4.4"
|
||||||
"react": "18.3.1"
|
"react": "19.0.0"
|
||||||
"react-dom": "18.3.1"
|
"react-dom": "19.0.0"
|
||||||
"react-icons": "5.3.0"
|
"react-icons": "5.4.0"
|
||||||
"@types/react": "18.3.12"
|
"@types/react": "19.0.1"
|
||||||
"@types/react-dom": "18.3.1"
|
"@types/react-dom": "19.0.1"
|
||||||
|
|
||||||
# Blog
|
# Blog
|
||||||
"@giscus/react": "3.0.0"
|
"@giscus/react": "3.0.0"
|
||||||
"gray-matter": "4.0.3"
|
"gray-matter": "4.0.3"
|
||||||
"katex": "0.16.11"
|
"katex": "0.16.11"
|
||||||
"next-mdx-remote": "5.0.0"
|
"next-mdx-remote": "5.0.0"
|
||||||
"@mdx-js/mdx": "3.0.1"
|
"@mdx-js/mdx": "3.1.0"
|
||||||
"rehype-katex": "7.0.1"
|
"rehype-katex": "7.0.1"
|
||||||
"rehype-raw": "7.0.0"
|
"rehype-raw": "7.0.0"
|
||||||
"rehype-slug": "6.0.0"
|
"rehype-slug": "6.0.0"
|
||||||
"remark-gfm": "4.0.0"
|
"remark-gfm": "4.0.0"
|
||||||
"remark-math": "6.0.0"
|
"remark-math": "6.0.0"
|
||||||
"shiki": "1.12.0"
|
"shiki": "1.24.0"
|
||||||
"@shikijs/rehype": "1.12.0"
|
"@shikijs/rehype": "1.24.0"
|
||||||
|
|
||||||
# Markdown Lint
|
# Markdown Lint
|
||||||
"markdownlint-cli2": "0.14.0"
|
"markdownlint-cli2": "0.15.0"
|
||||||
"markdownlint": "0.35.0"
|
"markdownlint": "0.36.1"
|
||||||
"markdownlint-rule-relative-links": "3.0.0"
|
"markdownlint-rule-relative-links": "3.0.0"
|
||||||
|
|
||||||
# TypeScript
|
# TypeScript
|
||||||
"typescript": "5.6.3"
|
"typescript": "5.7.2"
|
||||||
"@total-typescript/ts-reset": "0.6.1"
|
"@total-typescript/ts-reset": "0.6.1"
|
||||||
"@types/node": "22.9.0"
|
"@types/node": "22.10.1"
|
||||||
|
|
||||||
# ESLint
|
# ESLint
|
||||||
"globals": "15.12.0"
|
"globals": "15.13.0"
|
||||||
"typescript-eslint": "8.13.0"
|
"typescript-eslint": "8.17.0"
|
||||||
"@eslint/eslintrc": "3.1.0"
|
"@eslint/eslintrc": "3.2.0"
|
||||||
"eslint": "9.14.0"
|
"eslint": "9.16.0"
|
||||||
"eslint-config-conventions": "17.0.0"
|
"eslint-config-conventions": "17.0.1"
|
||||||
"eslint-plugin-promise": "7.1.0"
|
"eslint-plugin-promise": "7.2.1"
|
||||||
"eslint-plugin-unicorn": "56.0.0"
|
"eslint-plugin-unicorn": "56.0.1"
|
||||||
"eslint-config-next": "15.0.3"
|
"eslint-config-next": "15.0.4"
|
||||||
"eslint-plugin-storybook": "0.11.0"
|
"eslint-plugin-storybook": "0.11.1"
|
||||||
"eslint-plugin-tailwindcss": "3.17.5"
|
"eslint-plugin-tailwindcss": "3.17.5"
|
||||||
"eslint-plugin-import-x": "4.4.0"
|
"eslint-plugin-import-x": "4.5.0"
|
||||||
|
|
||||||
# Prettier
|
# Prettier
|
||||||
"prettier": "3.3.3"
|
"prettier": "3.4.2"
|
||||||
"prettier-plugin-tailwindcss": "0.6.8"
|
"prettier-plugin-tailwindcss": "0.6.9"
|
||||||
"editorconfig-checker": "6.0.0"
|
"editorconfig-checker": "6.0.0"
|
||||||
|
|
||||||
# Storybook
|
# Storybook
|
||||||
"@chromatic-com/storybook": "3.2.2"
|
"@chromatic-com/storybook": "3.2.2"
|
||||||
"@storybook/addon-a11y": "8.4.2"
|
"@storybook/addon-a11y": "8.4.7"
|
||||||
"@storybook/addon-essentials": "8.4.2"
|
"@storybook/addon-essentials": "8.4.7"
|
||||||
"@storybook/addon-interactions": "8.4.2"
|
"@storybook/addon-interactions": "8.4.7"
|
||||||
"@storybook/addon-storysource": "8.4.2"
|
"@storybook/addon-storysource": "8.4.7"
|
||||||
"@storybook/addon-themes": "8.4.2"
|
"@storybook/addon-themes": "8.4.7"
|
||||||
"@storybook/blocks": "8.4.2"
|
"@storybook/blocks": "8.4.7"
|
||||||
"@storybook/nextjs": "8.4.2"
|
"@storybook/nextjs": "8.4.7"
|
||||||
"@storybook/react": "8.4.2"
|
"@storybook/react": "8.4.7"
|
||||||
"@storybook/test": "8.4.2"
|
"@storybook/test": "8.4.7"
|
||||||
"@storybook/test-runner": "0.19.1"
|
"@storybook/test-runner": "0.20.1"
|
||||||
"chromatic": "11.18.0"
|
"chromatic": "11.20.0"
|
||||||
"http-server": "14.1.1"
|
"http-server": "14.1.1"
|
||||||
"storybook": "8.4.2"
|
"storybook": "8.4.7"
|
||||||
"storybook-dark-mode": "4.0.2"
|
"storybook-dark-mode": "4.0.2"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
"playwright": "1.48.2"
|
"playwright": "1.49.0"
|
||||||
"@playwright/test": "1.48.2"
|
"@playwright/test": "1.49.0"
|
||||||
"axe-playwright": "2.0.3"
|
"axe-playwright": "2.0.3"
|
||||||
"start-server-and-test": "2.0.8"
|
"start-server-and-test": "2.0.8"
|
||||||
"@vitest/browser": "2.1.4"
|
"@vitest/browser": "2.1.8"
|
||||||
"@vitest/coverage-v8": "2.1.4"
|
"@vitest/coverage-v8": "2.1.8"
|
||||||
"@vitest/ui": "2.1.4"
|
"@vitest/ui": "2.1.8"
|
||||||
"vitest": "2.1.4"
|
"vitest": "2.1.8"
|
||||||
"@testing-library/react": "16.0.1"
|
"@testing-library/react": "16.1.0"
|
||||||
|
|
||||||
# CSS
|
# CSS
|
||||||
"postcss": "8.4.47"
|
"postcss": "8.4.49"
|
||||||
"tailwindcss": "3.4.14"
|
"tailwindcss": "3.4.16"
|
||||||
"@tailwindcss/typography": "0.5.15"
|
"@tailwindcss/typography": "0.5.15"
|
||||||
"tailwind-merge": "2.5.4"
|
"tailwind-merge": "2.5.5"
|
||||||
"clsx": "2.0.0"
|
"clsx": "2.1.1"
|
||||||
"cva": "1.0.0-beta.1"
|
"cva": "1.0.0-beta.2"
|
||||||
"@fontsource/montserrat": "5.1.0"
|
"@fontsource/montserrat": "5.1.0"
|
||||||
|
Reference in New Issue
Block a user