FEAT: Lots of work on the blogs!
Syntax highlighting looks really good so far! Rendering of the markdowns works when a valid URL is provided, need to work on routing some more.
This commit is contained in:
parent
9acb11f6e2
commit
022bd1bcf7
2859
package-lock.json
generated
Normal file
2859
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -34,5 +34,14 @@
|
|||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"typescript-eslint": "^8.20.0",
|
"typescript-eslint": "^8.20.0",
|
||||||
"vite": "^6.0.0"
|
"vite": "^6.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^22.13.5",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"fs": "^0.0.1-security",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
|
"marked": "^15.0.7",
|
||||||
|
"marked-highlight": "^2.2.1",
|
||||||
|
"path": "^0.12.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/app.css
78
src/app.css
@ -1 +1,79 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
|
||||||
|
/* This is very painful. There must be a better way. */
|
||||||
|
@layer base {
|
||||||
|
pre {
|
||||||
|
background-color: #191724;
|
||||||
|
/* background-color: red; */
|
||||||
|
/* Or any color you want */
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
margin-inline: 2%;
|
||||||
|
/* Adjust padding as needed */
|
||||||
|
border-radius: 10px;
|
||||||
|
/* Optional: Add rounded corners */
|
||||||
|
overflow-x: auto;
|
||||||
|
/* Handle horizontal overflow if code is wider */
|
||||||
|
white-space: pre-wrap;
|
||||||
|
/* Allows code to wrap within the pre element*/
|
||||||
|
}
|
||||||
|
|
||||||
|
code.hljs {
|
||||||
|
color: #e0def4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #f6c177;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-punctuation,
|
||||||
|
.hljs-operator {
|
||||||
|
color: #908caa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment {
|
||||||
|
color: #6e6a86;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword {
|
||||||
|
color: #31748f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-params,
|
||||||
|
.hljs-method,
|
||||||
|
.hljs-methods,
|
||||||
|
.hljs-regexp,
|
||||||
|
code.language-python .hljs-meta {
|
||||||
|
color: #c4a7e7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-attr {
|
||||||
|
color: #e0def4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language_ {
|
||||||
|
color: #eb6f92;
|
||||||
|
}
|
||||||
|
|
||||||
|
.function_,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-title,
|
||||||
|
code.language-python .hljs-built_in,
|
||||||
|
code.language-go .hljs-built_in {
|
||||||
|
color: #ebbcba;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-property,
|
||||||
|
.class_,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-selector-class,
|
||||||
|
code.language-ts .hljs-built_in {
|
||||||
|
color: #9ccfd8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
415
src/blog/postOne.md
Normal file
415
src/blog/postOne.md
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
# This is a blog post
|
||||||
|
|
||||||
|
This is a blog post about something. It's really interesting. I hope you enjoy it.
|
||||||
|
|
||||||
|
My favorite color is red.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// JavaScript
|
||||||
|
|
||||||
|
// Function with parameters and return value
|
||||||
|
function greet(name, greeting = "Hello") {
|
||||||
|
return `${greeting}, ${name}!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow function
|
||||||
|
const multiply = (a, b) => a * b;
|
||||||
|
|
||||||
|
// Object literal
|
||||||
|
const person = {
|
||||||
|
name: "Alice",
|
||||||
|
age: 30,
|
||||||
|
greet: function() {
|
||||||
|
console.log(`My name is ${this.name}.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Array methods
|
||||||
|
const numbers = [1, 2, 3, 4, 5];
|
||||||
|
const doubled = numbers.map(num => num * 2);
|
||||||
|
|
||||||
|
// Promises and async/await
|
||||||
|
async function fetchData() {
|
||||||
|
const response = await fetch('https://example.com/data');
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class definition
|
||||||
|
class Dog {
|
||||||
|
constructor(name, breed) {
|
||||||
|
this.name = name;
|
||||||
|
this.breed = breed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bark() {
|
||||||
|
console.log("Woof!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments: single-line and multi-line
|
||||||
|
// This is a single-line comment.
|
||||||
|
/*
|
||||||
|
This is a
|
||||||
|
multi-line comment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Regular expressions
|
||||||
|
const regex = /^[a-zA-Z]+$/;
|
||||||
|
|
||||||
|
// Destructuring
|
||||||
|
const { name, age } = person;
|
||||||
|
|
||||||
|
// Template literals
|
||||||
|
const message = `Name: ${name}, Age: ${age}`;
|
||||||
|
|
||||||
|
|
||||||
|
// TypeScript (If your highlighter supports it)
|
||||||
|
// interface Person {
|
||||||
|
// name: string;
|
||||||
|
// age: number;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function greet(person: Person): string {
|
||||||
|
// return `Hello, ${person.name}!`;
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello world</h1>
|
||||||
|
</body>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```css
|
||||||
|
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
|
||||||
|
/* This is very painful. There must be a better way. */
|
||||||
|
@layer base {
|
||||||
|
pre {
|
||||||
|
background-color: #191724;
|
||||||
|
/* background-color: red; */
|
||||||
|
/* Or any color you want */
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
margin-inline: 2%;
|
||||||
|
/* Adjust padding as needed */
|
||||||
|
border-radius: 10px;
|
||||||
|
/* Optional: Add rounded corners */
|
||||||
|
overflow-x: auto;
|
||||||
|
/* Handle horizontal overflow if code is wider */
|
||||||
|
white-space: pre-wrap;
|
||||||
|
/* Allows code to wrap within the pre element*/
|
||||||
|
}
|
||||||
|
|
||||||
|
code.hljs {
|
||||||
|
color: #e0def4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #f6c177;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-punctuation,
|
||||||
|
.hljs-operator {
|
||||||
|
color: #908caa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment {
|
||||||
|
color: #6e6a86;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword {
|
||||||
|
color: #31748f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-params {
|
||||||
|
color: #c4a7e7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-attr {
|
||||||
|
color: #e0def4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language_ {
|
||||||
|
color: #eb6f92;
|
||||||
|
}
|
||||||
|
|
||||||
|
.function_,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-title,
|
||||||
|
code.language-python .hljs-built_in,
|
||||||
|
code.language-go .hljs-built_in {
|
||||||
|
color: #ebbcba;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-property,
|
||||||
|
.class_,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
code.language-ts .hljs-built_in {
|
||||||
|
color: #9ccfd8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```rs
|
||||||
|
fn main() {
|
||||||
|
// A simple function to add two numbers
|
||||||
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
// A struct representing a point in 2D space
|
||||||
|
struct Point {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
// Method to calculate the distance from the origin
|
||||||
|
fn distance_from_origin(&self) -> f64 {
|
||||||
|
(self.x * self.x + self.y * self.y).sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage
|
||||||
|
let num1 = 10;
|
||||||
|
let num2 = 20;
|
||||||
|
let sum = add(num1, num2);
|
||||||
|
println!("The sum of {} and {} is {}", num1, num2, sum);
|
||||||
|
|
||||||
|
let point = Point { x: 3.0, y: 4.0 };
|
||||||
|
let distance = point.distance_from_origin();
|
||||||
|
println!("The distance of the point from the origin is {}", distance);
|
||||||
|
|
||||||
|
// Demonstrating a for loop
|
||||||
|
for i in 0..5 {
|
||||||
|
println!("Value of i: {}", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example of a vector
|
||||||
|
let mut my_vector = vec![1, 2, 3];
|
||||||
|
my_vector.push(4);
|
||||||
|
println!("My vector: {:?}", my_vector);
|
||||||
|
|
||||||
|
// Using a Result to handle potential errors
|
||||||
|
fn divide(a: i32, b: i32) -> Result<i32, String> {
|
||||||
|
if b == 0 {
|
||||||
|
Err("Cannot divide by zero".to_string())
|
||||||
|
} else {
|
||||||
|
Ok(a / b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = divide(10, 2);
|
||||||
|
match result {
|
||||||
|
Ok(value) => println!("Result of division: {}", value),
|
||||||
|
Err(error) => println!("Error: {}", error),
|
||||||
|
}
|
||||||
|
|
||||||
|
let result2 = divide(10, 0);
|
||||||
|
match result2 {
|
||||||
|
Ok(value) => println!("Result of division: {}", value),
|
||||||
|
Err(error) => println!("Error: {}", error),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example of a closure
|
||||||
|
let square = |x: i32| -> i32 { x * x };
|
||||||
|
println!("Square of 5: {}", square(5));
|
||||||
|
|
||||||
|
// String manipulation
|
||||||
|
let my_string = "Hello, world!".to_string();
|
||||||
|
let greeting = format!("Greeting: {}", my_string);
|
||||||
|
println!("{}", greeting);
|
||||||
|
|
||||||
|
// Option example
|
||||||
|
let optional_value: Option<i32> = Some(42);
|
||||||
|
match optional_value {
|
||||||
|
Some(value) => println!("Optional value: {}", value),
|
||||||
|
None => println!("No value present"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Python
|
||||||
|
|
||||||
|
# Function definition
|
||||||
|
def greet(name, greeting="Hello"):
|
||||||
|
return f"{greeting}, {name}!"
|
||||||
|
|
||||||
|
# List comprehension
|
||||||
|
numbers = [1, 2, 3, 4, 5]
|
||||||
|
doubled = [num * 2 for num in numbers]
|
||||||
|
|
||||||
|
# Dictionary
|
||||||
|
person = {
|
||||||
|
"name": "Alice",
|
||||||
|
"age": 30,
|
||||||
|
"greet": lambda self: print(f"My name is {self['name']}."),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Class definition
|
||||||
|
class Dog:
|
||||||
|
def __init__(self, name, breed):
|
||||||
|
self.name = name
|
||||||
|
self.breed = breed
|
||||||
|
|
||||||
|
def bark(self):
|
||||||
|
print("Woof!")
|
||||||
|
|
||||||
|
# Comments: single-line and multi-line
|
||||||
|
# This is a single-line comment.
|
||||||
|
"""
|
||||||
|
This is a
|
||||||
|
multi-line comment.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Try-except block
|
||||||
|
try:
|
||||||
|
result = 10 / 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
print("Cannot divide by zero.")
|
||||||
|
|
||||||
|
# For loop
|
||||||
|
for i in range(5):
|
||||||
|
print(f"Value of i: {i}")
|
||||||
|
|
||||||
|
# While loop
|
||||||
|
count = 0
|
||||||
|
while count < 3:
|
||||||
|
print(f"Count: {count}")
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
# String formatting
|
||||||
|
message = "Name: {}, Age: {}".format(person["name"], person["age"])
|
||||||
|
|
||||||
|
# f-strings (formatted string literals)
|
||||||
|
message2 = f"Name: {person['name']}, Age: {person['age']}"
|
||||||
|
|
||||||
|
# List slicing
|
||||||
|
my_list = [10, 20, 30, 40, 50]
|
||||||
|
slice_of_list = my_list[1:4]
|
||||||
|
|
||||||
|
# Tuple unpacking
|
||||||
|
coordinates = (10, 20)
|
||||||
|
x, y = coordinates
|
||||||
|
|
||||||
|
# Decorators
|
||||||
|
def my_decorator(func):
|
||||||
|
def wrapper():
|
||||||
|
print("Something is happening before the function is called.")
|
||||||
|
func()
|
||||||
|
print("Something is happening after the function is called.")
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@my_decorator
|
||||||
|
def say_hello():
|
||||||
|
print("Hello!")
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Java
|
||||||
|
|
||||||
|
// Class definition
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
// Main method
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// Variables and data types
|
||||||
|
int age = 30;
|
||||||
|
String name = "Alice";
|
||||||
|
double height = 5.8;
|
||||||
|
boolean isStudent = true;
|
||||||
|
|
||||||
|
// Conditional statement
|
||||||
|
if (age >= 18) {
|
||||||
|
System.out.println("Adult");
|
||||||
|
} else {
|
||||||
|
System.out.println("Minor");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loops
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
System.out.println("Value of i: " + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// While loop
|
||||||
|
int count = 0;
|
||||||
|
while (count < 3) {
|
||||||
|
System.out.println("Count: " + count);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
int[] numbers = {1, 2, 3, 4, 5};
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
greet(name);
|
||||||
|
|
||||||
|
// Object creation
|
||||||
|
Person person = new Person(name, age);
|
||||||
|
person.greet();
|
||||||
|
|
||||||
|
// Try-catch block
|
||||||
|
try {
|
||||||
|
int result = 10 / 0;
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
System.out.println("Cannot divide by zero.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments: single-line and multi-line
|
||||||
|
// This is a single-line comment.
|
||||||
|
/*
|
||||||
|
This is a
|
||||||
|
multi-line comment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// String concatenation
|
||||||
|
String message = "Hello, " + name + "!";
|
||||||
|
System.out.println(message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method definition
|
||||||
|
public static void greet(String name) {
|
||||||
|
System.out.println("Hello, " + name + "!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class definition
|
||||||
|
class Person {
|
||||||
|
String name;
|
||||||
|
int age;
|
||||||
|
|
||||||
|
public Person(String name, int age) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void greet() {
|
||||||
|
System.out.println("My name is " + this.name + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -1,7 +1,3 @@
|
|||||||
<script>
|
|
||||||
console.log('navbar.svelte');
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav class="flex border-b-1 border-gray-700 py-6">
|
<nav class="flex border-b-1 border-gray-700 py-6">
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<h3 class="ml-4 px-2 text-2xl font-[600] text-gray-200">Hayden Hargreaves</h3>
|
<h3 class="ml-4 px-2 text-2xl font-[600] text-gray-200">Hayden Hargreaves</h3>
|
||||||
@ -15,6 +11,9 @@
|
|||||||
<a href="/about" class="transition-all duration-150 hover:text-blue-300">
|
<a href="/about" class="transition-all duration-150 hover:text-blue-300">
|
||||||
<p class="px-3">About</p>
|
<p class="px-3">About</p>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/blog" class="transition-all duration-150 hover:text-blue-300">
|
||||||
|
<p class="px-3">Blog</p>
|
||||||
|
</a>
|
||||||
<a href="https://github.com/Azpect3120" target="_blank" class="">
|
<a href="https://github.com/Azpect3120" target="_blank" class="">
|
||||||
<svg viewBox="0 0 98 96" xmlns="http://www.w3.org/2000/svg" class="mx-4 h-auto w-6">
|
<svg viewBox="0 0 98 96" xmlns="http://www.w3.org/2000/svg" class="mx-4 h-auto w-6">
|
||||||
><path
|
><path
|
||||||
|
|||||||
48
src/routes/blog/[title]/+page.server.ts
Normal file
48
src/routes/blog/[title]/+page.server.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import type { RequestEvent } from '@sveltejs/kit';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { Marked } from 'marked';
|
||||||
|
import { markedHighlight } from "marked-highlight";
|
||||||
|
import hljs from 'highlight.js';
|
||||||
|
|
||||||
|
// Root of the project
|
||||||
|
const cwd = process.cwd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the blog post from the file system when the page is requested.
|
||||||
|
* @param {RequestEvent} event
|
||||||
|
*/
|
||||||
|
export const load = async ({ url }: RequestEvent) => {
|
||||||
|
// Create the path
|
||||||
|
// ./src/[url].md
|
||||||
|
const blogPath = cwd.concat("/src", url.pathname, ".md");
|
||||||
|
|
||||||
|
// Read the file and get the data
|
||||||
|
const data = readFileSync(blogPath, 'utf-8');
|
||||||
|
|
||||||
|
// marked.use({
|
||||||
|
// gfm: true,
|
||||||
|
// breaks: true,
|
||||||
|
//
|
||||||
|
// });
|
||||||
|
const marked = new Marked(
|
||||||
|
markedHighlight({
|
||||||
|
emptyLangClass: 'hljs',
|
||||||
|
langPrefix: 'hljs language-',
|
||||||
|
highlight(code, lang, info) {
|
||||||
|
console.log("INFO: ", code);
|
||||||
|
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||||
|
return hljs.highlight(code, { language }).value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert the markdown to HTML
|
||||||
|
const html = marked.parse(data);
|
||||||
|
console.log(html);
|
||||||
|
|
||||||
|
return {
|
||||||
|
post: {
|
||||||
|
content: html,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
25
src/routes/blog/[title]/+page.svelte
Normal file
25
src/routes/blog/[title]/+page.svelte
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { PageProps } from './$types';
|
||||||
|
// import hljs from 'highlight.js';
|
||||||
|
|
||||||
|
let { data }: PageProps = $props();
|
||||||
|
// Run highlight.js after the component is rendered (onMount or after each update)
|
||||||
|
// import { onMount } from 'svelte';
|
||||||
|
//
|
||||||
|
// onMount(() => {
|
||||||
|
// // console.log("onMount called");
|
||||||
|
// highlightAllCodeBlocks();
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// function highlightAllCodeBlocks() {
|
||||||
|
// // console.log("highlightAllCodeBlocks called");
|
||||||
|
// const codeBlocks = document.querySelectorAll('pre code');
|
||||||
|
// codeBlocks.forEach((block) => {
|
||||||
|
// hljs.highlightElement(block);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="prose">
|
||||||
|
{@html data.post.content}
|
||||||
|
</div>
|
||||||
Loading…
x
Reference in New Issue
Block a user