Compare commits

...

55 commits

Author SHA1 Message Date
Miroslav Šedivý
afa89836d2 increase version. 2023-01-24 18:18:53 +01:00
Miroslav Šedivý
d25b53ab33 datepicker add year increase / decrease, #44. 2023-01-24 18:18:36 +01:00
Miroslav Šedivý
f17219d054 add #sort=reverse, #44. 2023-01-24 18:02:48 +01:00
Miroslav Šedivý
1583120679 multiarch builds. 2023-01-12 22:21:09 +01:00
Miroslav Šedivý
5651c47b1d fix url escape. 2022-01-15 20:07:35 +01:00
Miroslav Šedivý
6f5e59f140 check image create errors. 2022-01-06 17:23:43 +01:00
Miroslav Šedivý
5e1a72f22e HTML escape config vars. 2022-01-06 16:36:47 +01:00
Miroslav Šedivý
08cd9e7cf8 bug fix. 2022-01-06 15:10:50 +01:00
Vincent Stans
2ad4e86ec8
Create nl.ini (#36)
Dutch Translation
2021-12-16 15:07:02 +01:00
Miroslav Šedivý
911b0be5ac fixes #35. 2021-11-20 19:36:00 +01:00
vkhurana
7d834a6d03
add config options for footer (#34) 2021-11-17 09:54:47 +01:00
Lucien Cartier-Tilet
902066ed81
Fix typos in French translation (#33) 2021-11-10 23:12:42 +01:00
Miroslav Šedivý
75788116ec Revert "add funding."
This reverts commit 57153f383c.
2021-11-10 23:04:13 +01:00
Miroslav Šedivý
2ff91c0908 bump minor version. 2021-11-06 00:10:22 +01:00
Miroslav Šedivý
57153f383c add funding. 2021-11-06 00:10:00 +01:00
Miroslav Šedivý
45955a4730 fix canocat for postgres, #32. 2021-11-01 17:06:51 +01:00
Miroslav Šedivý
1a72664f73
Merge pull request #31 from m1k1o/postgres
Add postgres support
2021-10-29 23:33:55 +02:00
Miroslav Šedivý
7231835bf5 bump version. 2021-10-29 23:28:12 +02:00
Miroslav Šedivý
d13d6ab98e update readme. 2021-10-29 23:26:44 +02:00
Miroslav Šedivý
b41c4a57fc revert debug in config. 2021-10-29 23:21:43 +02:00
Miroslav Šedivý
845b9f724a fix postgres timezone. 2021-10-29 23:13:52 +02:00
Miroslav Šedivý
f0dbd5e426 set postgres datetime. 2021-10-29 22:58:54 +02:00
Miroslav Šedivý
3652faf8ab add postgres support. 2021-10-29 21:56:50 +02:00
Miroslav Šedivý
8ad8b5ca6f add postgres schema. 2021-10-29 21:47:31 +02:00
Miroslav Šedivý
3dee0f4028 add 🇷🇺 to readme. 2021-10-29 20:44:58 +02:00
Miroslav Šedivý
8073f2ce44
Merge pull request #30 from ozzyst/f/add_ru_lang
Add support of Russian language
2021-10-28 15:33:21 +02:00
Stanislav Losev
0396958944 Add support of Russian language 2021-10-28 16:13:05 +03:00
Miroslav Šedivý
dabfd02776 dockerfile remove deprecated maintainer. 2021-08-09 17:59:08 +02:00
Miroslav Šedivý
59858cabfe do not use root mysql account. 2021-08-09 17:57:20 +02:00
Miroslav Šedivý
477912bdbf add exif, fixes #20. 2021-08-09 17:53:58 +02:00
Miroslav Šedivý
9f5393fac5 theme01 remove textarea border. 2021-07-23 15:51:01 +02:00
Miroslav Šedivý
1ae667ed5e add link to github repo. 2021-07-23 15:49:40 +02:00
Miroslav Šedivý
763bca162a remove unused code. 2021-07-23 15:40:43 +02:00
Miroslav Šedivý
b43ca9a94e use github actions. 2021-06-13 14:44:59 +02:00
Miroslav Šedivý
386707c104 fix CONCAT() for SQLite #24. 2021-06-13 12:45:52 +02:00
Miroslav Šedivý
86b3840278
Merge pull request #22 from Nixo-77/master
Implode bug fix
2021-02-21 19:07:40 +01:00
Nixo-77
d5ecdf330c
Implode bug fix 2021-02-21 19:03:33 +01:00
Miroslav Šedivý
734822aa8a
update version to v1.3 2020-11-06 10:05:37 +01:00
Miroslav Šedivý
b54509ba51
check for null in language 2020-11-06 09:58:32 +01:00
m1k1o
07d5869a1a fallback if dictionary does not exist 2020-10-08 23:19:13 +02:00
m1k1o
6f6640ae15 fix es lang syntax error 2020-10-08 23:19:03 +02:00
Miroslav Šedivý
4f9ec2cb82
Merge pull request #21 from ManuLinares/patch-2
Created es.ini (Spanish translation)
2020-10-08 17:54:58 +02:00
m1k1o
795308a949 Spanish to readme 2020-10-08 17:54:15 +02:00
ManuLinares
59633724c2
Create es.ini
Spanish translation
2020-10-08 00:46:21 -03:00
Miroslav Šedivý
022bc27612
Merge pull request #19 from hajro92/master
Translated to Bosnian
2020-10-03 19:41:26 +02:00
hajro92
5ae966bfa5 Translated to Bosnian 2020-10-03 19:21:01 +02:00
Miroslav Šedivý
bf9ba1ad34
Update lang.class.php 2020-08-24 21:50:00 +02:00
Miroslav Šedivý
1b43034c0e
added CZ to readme 2020-08-24 21:39:44 +02:00
Miroslav Šedivý
53cfef9655
Merge pull request #18 from djfinch/master
Added CZ translation and fixed typo in sk.ini
2020-08-24 21:37:47 +02:00
djfinch
d8b745cbbd Added Czech translation 2020-08-24 21:21:52 +02:00
djfinch
26ad4902a0 Fix typo in SK lang. 2020-08-24 21:00:34 +02:00
m1k1o
1048548f3e bump highlight.js to 10.1.2 2020-08-22 11:14:02 +02:00
m1k1o
cdc56c3c0c fix JBBCode class 2020-08-22 11:13:21 +02:00
m1k1o
00d109ca82 add access control to readme #17 2020-07-05 19:56:41 +02:00
m1k1o
5d300a80ad visitors as friends in envs #17 2020-07-05 19:41:45 +02:00
29 changed files with 801 additions and 114 deletions

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
github: [ m1k1o ]

58
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: "CI for builds"
on:
push:
branches:
- master
tags:
- 'v*'
env:
IMAGE_NAME: m1k1o/blog
jobs:
build:
runs-on: ubuntu-latest
#
# do not run on forks
#
if: github.repository_owner == 'm1k1o'
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
-
name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
-
name: Extract metadata (tags, labels) for Docker
uses: docker/metadata-action@v3
id: meta
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
name: Log in to the Container registry
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v2
with:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true

View file

@ -1,9 +1,7 @@
FROM php:7.4-apache
MAINTAINER Miroslav Sedivy
RUN set -eux; apt-get update; \
apt-get install -y --no-install-recommends \
apt-get install -y --no-install-recommends libpq-dev \
#
# install curl
libcurl4-openssl-dev \
@ -20,7 +18,7 @@ RUN set -eux; apt-get update; \
--with-jpeg --with-webp --with-xpm --with-freetype; \
#
# install extensions
docker-php-ext-install curl gd pdo pdo_mysql; \
docker-php-ext-install curl gd pdo pdo_mysql pdo_pgsql exif; \
#
# set up environment
a2enmod rewrite;

150
README.md
View file

@ -53,32 +53,85 @@ docker run -d \
m1k1o/blog:latest
```
Or in docker-compose format:
```yml
version: "3"
services:
blog:
image: m1k1o/blog:latest
restart: unless-stopped
environment:
TZ: Europe/Vienna
BLOG_TITLE: Blog
BLOG_NAME: Max Musermann
BLOG_NICK: username
BLOG_PASS: password
BLOG_LANG: en
ports:
- 80:80
volumes:
- ./data:/var/www/html/data
```
Or for docker-compose format, see [docker-compose.yml](docker-compose.yml).
## Install standalone app using `docker-compose` with mysql
## Install standalone app using `docker-compose` with external database
You need to install [docker-compose](https://docs.docker.com/compose/install/).
### Step 1: Download and run `docker-compose.yml`.
### MySQL
```yaml
version: "3"
services:
webserver:
image: m1k1o/blog:latest
container_name: blog_apache
environment:
TZ: Europe/Vienna
BLOG_DB_CONNECTION: mysql
BLOG_MYSQL_HOST: mariadb
BLOG_MYSQL_PORT: 3306
BLOG_MYSQL_USER: blog
BLOG_MYSQL_PASS: blog # use secure password
BLOG_DB_NAME: blog
restart: unless-stopped
ports:
- ${HTTP_PORT-80}:80
volumes:
- ${DATA-./data}:/var/www/html/data
mariadb:
image: mariadb:10.1
container_name: blog_mariadb
environment:
MYSQL_USER: blog
MYSQL_PASSWORD: blog # use secure password
MYSQL_DATABASE: blog
MYSQL_ROOT_PASSWORD: root # use secure password
restart: unless-stopped
volumes:
- mariadb:/var/lib/mysql
- ./app/db/mysql:/docker-entrypoint-initdb.d:ro
volumes:
mariadb:
```
### Postgres
```yaml
version: "3"
services:
webserver:
image: m1k1o/blog:latest
container_name: blog_apache
environment:
TZ: Europe/Vienna
BLOG_DB_CONNECTION: postgres
BLOG_POSTGRES_HOST: postgres
BLOG_POSTGRES_PORT: 5432
BLOG_POSTGRES_USER: blog
BLOG_POSTGRES_PASS: blog # use secure password
BLOG_DB_NAME: blog
restart: unless-stopped
ports:
- ${HTTP_PORT-80}:80
volumes:
- ${DATA-./data}:/var/www/html/data
postgres:
image: postgres:14
container_name: blog_postgres
environment:
POSTGRES_USER: blog
POSTGRES_PASSWORD: blog # use secure password
POSTGRES_DB: blog
restart: unless-stopped
volumes:
- postgres:/var/lib/postgresql/data
- ./app/db/postgres:/docker-entrypoint-initdb.d:ro
volumes:
postgres:
```
### Step 1: Run `docker-compose.yml`.
Select one of configurations above and save it to `docker-compose.yml`. Then run:
```sh
wget https://raw.githubusercontent.com/m1k1o/blog/master/docker-compose.yml
docker-compose up -d
```
@ -155,13 +208,56 @@ To check if your server is set up correctly, turn on a debug mode (in config add
* Upload images using CTRL + V *(paste it into textarea)*.
* Highlight code in post using `[code]..your code..[/code]`.
* Highlight your goal using `[goal]Text of your goal.[/goal]`.
* Use tags in posts (allowed characters `A-Za-z0-9-_` terminated by space or EOL): `#song`
* Sort posts by hashtags: `http://blog/#tag=songs`
* Sort posts by location in url using: `http://blog/#loc=Vienna`.
* Use tags in posts (allowed characters `A-Za-z0-9-_` terminated by space or EOL): `#song`.
* Sort posts in reverse order (oldest first): `http://blog/#sort=reverse`.
* Filter posts by hashtags: `http://blog/#tag=songs`.
* Filter posts by location in url using: `http://blog/#loc=Vienna`.
* Display posts from chosen date using (format YYYY-MM-DD or YYY-MM): `http://blog/#from=2017-06`.
* Display posts to chosen date using (format YYYY-MM-DD or YYY-MM): `http://blog/#to=2017-06`.
* Combine parameters in url using `&`, e.g. show posts between dates: `http://blog/#from=2017-06&to=2017-08`.
## Access control
This blog is using Mandatory Access Control (MAC), with 3 types of access levels:
* **Private** posts are visible only to your single account specified in `nick` and `pass`.
* You can specify group of your **friends** and share posts only for them.
* **Public** posts are visible to everyone, without login.
In `docker-compose.yml` file, specify your credentials and friends like this:
```yml
version: "3"
services:
blog:
image: m1k1o/blog:latest
restart: unless-stopped
environment:
TZ: Europe/Vienna
BLOG_NICK: admin_username
BLOG_PASS: admin_password
BLOG_FRIENDS: |
jane:mysecretpass
thomas:anotherpass
ports:
- 80:80
volumes:
- ./data:/var/www/html/data
```
You can specify your credentials and friends in your `config.ini` file e.g.:
```ini
[admin]
force_login = true
nick = admin_username
pass = admin_password
[friends]
friends[jane] = mysecretpass
friends[thomas] = anotherpass
```
## Localisation
Timezone can be set in config or, for docker users, `TZ` environment variable is supported. List of timezones can be found [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
@ -172,3 +268,7 @@ Feel free to create new PR and add a new language. Specify language in config or
* de - 🇩🇪 German
* sk - 🇸🇰 Slovak
* fr - 🇫🇷 French (thanks @Phundrak)
* cz - 🇨🇿 Czech (thanks @djfinch)
* bs - 🇧🇦 Bosnian (thanks @hajro92)
* es - 🇪🇸 Spanish (thanks @ManuLinares)
* ru - 🇷🇺 Russian (thanks @ozzyst)

View file

@ -66,6 +66,11 @@ class Config
$value = false;
}
// Associative arrays in environment variables
if($key === 'visitor' || $key === 'friends'){
$value = self::parse_env_assoc($value);
}
self::$_settings[$key] = $value;
}
}
@ -92,6 +97,22 @@ class Config
return $value;
}
// Parse associative array from string in format key:value
private static function parse_env_assoc($data){
if(!preg_match_all("/([^\s]+):([^\s]+)/s", $data, $matches)){
return [];
}
list($_, $keys, $values) = $matches;
$array = [];
foreach ($values as $key => $value) {
$array[$keys[$key]] = $value;
}
return $array;
}
}
class ConfigException extends Exception {}

View file

@ -24,12 +24,27 @@ class DB
return Config::get_safe('db_connection', 'sqlite');
}
// CONCAT() does not exist in SQLite, using || instead
// for postgres, ERROR: could not determine data type of parameter $1
public final static function concat(){
$values = func_get_args();
if(DB::connection() === 'sqlite' || DB::connection() === 'postgres') {
return implode(" || ", $values);
} else {
return 'CONCAT('.implode(", ", $values).')';
}
}
// Initialise PDO object
private final function __construct(){
switch(DB::connection()) {
case 'mysql':
$this->mysql_connect();
break;
case 'postgres':
$this->postgres_connect();
break;
case 'sqlite':
$this->sqlite_connect();
break;
@ -81,6 +96,48 @@ class DB
}
}
private final function postgres_connect(){
$host = Config::get_safe('postgres_host', false);
$port = Config::get_safe('postgres_port', false);
$socket = Config::get_safe('postgres_socket', false);
if($socket === false && $host === false){
throw new DBException("Postgres host or socket must be defined.");
}
// Try to connect
try {
$this->_PDO = new \PDO(
// Server
'pgsql:'.
($socket !== false
? 'unix_socket='.$socket
: 'host='.$host.($port !== false ? ';port='.$port : '')
).
// DB
';dbname='.Config::get('db_name').
// Charset
';options=\'--client_encoding=UTF8\'',
// Username
Config::get('postgres_user'),
// Password
Config::get_safe('postgres_pass', ''),
// Set attributes
[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false
]
);
$this->_PDO->exec(
// Set timezone
'SET TIME ZONE "'.date('e').'";'
);
} catch (PDOException $e) {
throw new DBException($e->getMessage());
}
}
private final function sqlite_connect(){
$sqlite_db = PROJECT_PATH.Config::get_safe('sqlite_db', "data/sqlite.db");
@ -154,6 +211,11 @@ class DB
$sql = $params[0];
unset($params[0]);
// Replace backticks with " for postgres
if(DB::connection() === 'postgres') {
$sql = str_replace("`", '"', $sql);
}
// Debug mode
if(Config::get_safe('debug', false)){
echo "<!-- ".$sql." + ".json_encode($params)." -->\n";

View file

@ -0,0 +1,26 @@
CREATE TABLE images (
"id" serial PRIMARY KEY,
"name" varchar(255) NOT NULL,
"path" varchar(255) DEFAULT NULL,
"thumb" varchar(255) DEFAULT NULL,
"type" varchar(10) NOT NULL,
"md5" char(32) NOT NULL,
"datetime" timestamp NOT NULL,
"status" int NOT NULL
);
CREATE TYPE privacy_t as enum('private','friends','public');
CREATE TABLE posts (
"id" serial PRIMARY KEY,
"text" text NOT NULL,
"plain_text" text NOT NULL,
"feeling" varchar(255) NOT NULL,
"persons" varchar(255) NOT NULL,
"location" varchar(255) NOT NULL,
"content" varchar(1000) NOT NULL,
"content_type" varchar(255) NOT NULL,
"privacy" privacy_t NOT NULL,
"datetime" timestamp NOT NULL,
"status" int NOT NULL
);

View file

@ -110,15 +110,16 @@ class Image
}
$old_image = $imgcreatefrom($source_path);
if ($old_image === false) return false;
$new_image = imagecreatetruecolor($new_w, $new_h);
imagecopyresampled($new_image, $old_image, 0, 0, 0, 0, $new_w, $new_h, $source_w, $source_h);
$new_image = self::fix_orientation($source_path, $new_image);
$old_image = self::fix_orientation($source_path, $old_image);
$imgt($new_image, $thumb_path);
$imgt($old_image, $source_path);
return true;
return $imgt($new_image, $thumb_path)
&& $imgt($old_image, $source_path);
}
public static function upload(){

View file

@ -15,7 +15,7 @@ class Lang
}
public static function get($key){
if(!array_key_exists($key, self::$_dictionary)){
if(is_null(self::$_dictionary) || !array_key_exists($key, self::$_dictionary)){
return $key;
}
@ -25,4 +25,4 @@ class Lang
function __($key){
return Lang::get($key);
}
}

67
app/lang/bs.ini Normal file
View file

@ -0,0 +1,67 @@
; index.html
Show More = "Prikaži još"
Login = "Prijava"
Logout = "Odjava"
Nick = "Nadimak"
Password = "Šifra"
Cancel = "Zatvori"
Post = "Objavi"
Edit Post = "Izmijeni Objavu"
Change Date = "Promijeni Datum"
Hide from Timeline = "Sakrij sa Vremenske Linije"
Show on Timeline = "Prikaži na Vremenskoj Liniji"
Delete Post = "Izbriši objavu"
Drag photos here = "Privuci fotografije ovdje"
Drop photos here = "Privuci fotografije ovdje"
What's on your mind? = "Šta vam je na umu?"
Feeling = "Osjećaj"
How are you feeling? = "Kako se osjećate?"
With = "Sa"
Who are you with? = "S kim ste?"
At = "Gdje"
Where are you? = "Gdje se nalazite?"
Save = "Sačuvaj"
January = "Januar"
February = "Februar"
March = "Mart"
April = "April"
May = "Maj"
June = "Juni"
July = "Juli"
August = "Avgust"
September = "Septembar"
October = "Oktobar"
November = "Novembar"
December = "Decembar"
Time: = "Vrijeme:"
Hour: = "Sati:"
Minute: = "Minute:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Ova će objava biti izbrisana i nećete je više moći pronaći. Takođe možete izmijeniti ovu objavu ako želite izvršiti izmjene."
with = "sa"
here: = "ovdje:"
Public = "Javno"
Friends = "Prijatelji"
Only me = "Samo ja"
Show hidden content = "Prikaži skriveni sadržaj"
Show all posts = "Prikaži sve objave"
; user.class.php
You are already logged in. = "Već ste prijavljeni."
The nick or password is incorrect. = "Nadimak ili šifra su pogrešni."
You can't log out. There is no account. = "Ne možete se odjaviti. Račun ne postoji."
You are not even logged in. = "Niste čak ni prijavljeni."
; post.class.php
You need to be logged in to perform this action. = "Morate biti priavljeni da biste izvršili ovu radnju."
No data. = "Nema podataka."

67
app/lang/cz.ini Normal file
View file

@ -0,0 +1,67 @@
; index.html
Show More = "Zobrazit více"
Login = "Přihlásit se"
Logout = "Odhlásit se"
Nick = "Přihlašovací jméno"
Password = "Heslo"
Cancel = "Zrušit"
Post = "Nový příspěvek"
Edit Post = "Upravit příspěvek"
Change Date = "Změnit datum"
Hide from Timeline = "Skrýt na časové ose"
Show on Timeline = "Zobrazit na časové ose"
Delete Post = "Odstranit příspěvek"
Drag photos here = "Sem přesuňte fotografie"
Drop photos here = "Zde vložte fotografie"
What's on your mind? = "Na co myslíš?"
Feeling = "Pocit"
How are you feeling? = "Jak se cítíš?"
With = "Spolu s"
Who are you with? = "S kým jsi?"
At = "Místo"
Where are you? = "Kde jsi?"
Save = "Uložit"
January = "Leden"
February = "Únor"
March = "Březen"
April = "Duben"
May = "Květen"
June = "Červen"
July = "Červenec"
August = "Srpen"
September = "Září"
October = "Říjen"
November = "Listopad"
December = "Prosinec"
Time: = "Čas:"
Hour: = "Hodina:"
Minute: = "Minuta:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Tento příspěvek bude odstraněn a už ho nebude možné najít. Pokud chcete něco změnit, můžete tento příspěvek také upravit."
with = "s"
here: = "zde:"
Public = "Veřejné"
Friends = "Přátelé"
Only me = "Jen já"
Show hidden content = "Zobrazit skrytý obsah"
Show all posts = "Zobrazit všechny příspěvky"
; user.class.php
You are already logged in. = "Už jsi přihlášený."
The nick or password is incorrect. = "Přihlašovací jméno nebo heslo je nesprávné."
You can't log out. There is no account. = "Nemůžeš se odhlásit. Neexistuje žádný účet."
You are not even logged in. = "Nejsi ani přihlášený."
; post.class.php
You need to be logged in to perform this action. = "Na provedení této akce musíš být přihlášený."
No data. = "Žádná data."

67
app/lang/es.ini Normal file
View file

@ -0,0 +1,67 @@
; index.html
Show More = "Mostrar más"
Login = "Iniciar sesión"
Logout = "Cerrar sesión"
Nick = "Apodo"
Password = "Contraseña"
Cancel = "Cancelar"
Post = "Publicar"
Edit Post = "Editar publicación"
Change Date = "Cambiar fecha"
Hide from Timeline = "Ocultar de la línea de tiempo"
Show on Timeline = "Mostrar en la línea de tiempo"
Delete Post = "Eliminar publicación"
Drag photos here = "Arrastra aquí las fotos"
Drop photos here = "Suelta aquí las fotos"
What's on your mind? = "¿Qué estas pensando?"
Feeling = "Sintiendo"
How are you feeling? = "¿Como te sientes?"
With = "Con"
Who are you with? = "¿Con quién estás?"
At = "En"
Where are you? = "¿Dónde estás?"
Save = "Guardar"
January = "Enero"
February = "Febrero"
March = "Marzo"
April = "Abril"
May = "Mayo"
June = "Junio"
July = "Julio"
August = "Agosto"
September = "Septiembre"
October = "Octubre"
November = "Noviembre"
December = "Diciembre"
Time: = "Hora:"
Hour: = "Hora:"
Minute: = "Minuto:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Esta publicación se eliminará y ya no podrá ser encontrada. También puedes editar esta publicación si solo deseas cambiar algo."
with = "con"
here: = "aqui:"
Public = "Público"
Friends = "Amigos"
Only me = "Solo yo"
Show hidden content = "Mostrar contenido oculto"
Show all posts = "Mostrar todas las publicaciones"
; user.class.php
You are already logged in. = "Ya has iniciado sesión."
The nick or password is incorrect. = "El apodo o la contraseña son incorrectos."
You can't log out. There is no account. = "No puede cerrar sesión. No hay cuenta."
You are not even logged in. = "Ni siquiera estás conectado."
; post.class.php
You need to be logged in to perform this action. = "Debe haber iniciado una sesión para realizar esta acción."
No data. = "Sin datos."

View file

@ -40,9 +40,9 @@ October = "Octobre"
November = "Novembre"
December = "Décembre"
Time: = "Heure:"
Hour: = "Heure:"
Minute: = "Minutes:"
Time: = "Heure :"
Hour: = "Heure :"
Minute: = "Minutes :"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Cette publication sera supprimée et vous ne pourrez plus la retrouver. Vous pouvez aussi la modifier si vous souhaitez simplement changer quelque chose."
@ -57,11 +57,11 @@ Show hidden content = "Montrer le contenu caché"
Show all posts = "Montrer toutes les publications"
; user.class.php
You are already logged in. = "Vous êtes déjà connectés."
You are already logged in. = "Vous êtes déjà connecté."
The nick or password is incorrect. = "Votre pseudo ou mot de passe est incorrect."
You can't log out. There is no account. = "Vous ne pouvez pas vous déconnecter, les comptes sont désactivés."
You are not even logged in. = "Vous nêtes même pas connectés."
You are not even logged in. = "Vous nêtes pas connecté."
; post.class.php
You need to be logged in to perform this action. = "Vous devez être connectés pour pouvoir faire ça."
You need to be logged in to perform this action. = "Vous devez être connecté pour pouvoir faire ça."
No data. = "Aucune données."

67
app/lang/nl.ini Normal file
View file

@ -0,0 +1,67 @@
; index.html
Show More = "Verder Lezen"
Login = "Aanmelden"
Logout = "Afmelden"
Nick = "Gebruiker"
Password = "Wachtwoord"
Cancel = "Annuleren"
Post = "Bericht"
Edit Post = "Wijzig Bericht"
Change Date = "Wijzig Datum"
Hide from Timeline = "Verbergen van Tijdlijn"
Show on Timeline = "Laten zien op Tijdlijn"
Delete Post = "Verwijder Bericht"
Drag photos here = "Sleep foto's hier"
Drop photos here = "Gooi foto's hier"
What's on your mind? = "Waar ben je mee bezig?"
Feeling = "Gevoel"
How are you feeling? = "Hoe voel je je?"
With = "Met"
Who are you with? = "Met wie ben je?"
At = "Bij"
Where are you? = "Waar ben je?"
Save = "Opslaan"
January = "Januari"
February = "Februari"
March = "Maart"
April = "April"
May = "Mei"
June = "Juni"
July = "Juli"
August = "Augustus"
September = "September"
October = "Oktober"
November = "November"
December = "December"
Time: = "Tijd:"
Hour: = "Uur:"
Minute: = "Minuten:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Dit bericht word verwijderd en kan niet meer worden gevonden. Je kan ook het bericht wijzigen als je dat liever wilt."
with = "met"
here: = "Bij:"
Public = "Openbaar"
Friends = "Vrienden"
Only me = "Alleen ik"
Show hidden content = "Laat verborgen berichten zien"
Show all posts = "Alle berichten zien"
; user.class.php
You are already logged in. = "Je bent al ingelogt."
The nick or password is incorrect. = "De gebruiken of het Wachtwoord is onjuist."
You can't log out. There is no account. = "Je kan niet Afmelden. Er is geen Account."
You are not even logged in. = "Je ben niet eens ingelogt."
; post.class.php
You need to be logged in to perform this action. = "Je moet ingelogged zijn om deze actie uit te voeren."
No data. = "Geen data."

67
app/lang/ru.ini Normal file
View file

@ -0,0 +1,67 @@
; index.html
Show More = "Показать больше"
Login = "Войти"
Logout = "Выйти"
Nick = "Логин"
Password = "Пароль"
Cancel = "Отмена"
Post = "Пост"
Edit Post = "Редактировать пост"
Change Date = "Изменить дату"
Hide from Timeline = "Скрыть из ленты"
Show on Timeline = "Показать в ленте"
Delete Post = "Удалить пост"
Drag photos here = "Перетащите сюда фото"
Drop photos here = "Оставь фото здесь"
What's on your mind? = "О чем ты думаешь?"
Feeling = "Ощущения"
How are you feeling? = "Как ты себя чувствуешь?"
With = "В компании"
Who are you with? = "С кем ты?"
At = "Локация"
Where are you? = "Где ты?"
Save = "Сохранить"
January = "Январь"
February = "Февраль"
March = "Март"
April = "Апрель"
May = "Май"
June = "Июнь"
July = "Июль"
August = "Август"
September = "Сентябрь"
October = "Октябрь"
November = "Ноябрь"
December = "Декабрь"
Time: = "Время:"
Hour: = аc:"
Minute: = "Минута:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Этот пост будет удален, и вы больше не сможете его найти. Вы также можете отредактировать этот пост, если просто хотите что-то изменить"
with = "с"
here: = "здесь:"
Public = "Публичный"
Friends = "Друзья"
Only me = "Только я"
Show hidden content = "Показать скрытый контент"
Show all posts = "Показать все посты"
; user.class.php
You are already logged in. = "Вы уже залогинены."
The nick or password is incorrect. = "Логин или пароль неверный."
You can't log out. There is no account. = "Вы не можете выйти. Вы не залогинены."
You are not even logged in. = "Вы не авторизовались."
; post.class.php
You need to be logged in to perform this action. = "Вы должны быть залогинены, чтобы выполнить это действие."
No data. = "Нет данных."

View file

@ -41,7 +41,7 @@ November = "November"
December = "December"
Time: = "Čas:"
Hour: = "Hodnia:"
Hour: = "Hodina:"
Minute: = "Minúta:"
This post will be deleted and you'll no longer be able to find it. You can also edit this post if you just want to change something. = "Tento príspevok bude odstránený a už ho nebudete môcť nájsť. Tento príspevok môžete tiež upraviť, ak chcete niečo zmeniť."

View file

@ -29,7 +29,8 @@ class Post
public function asHtml(\JBBCode\ElementNode $el){
$content = $this->getContent($el);
return '<code class="'.$el->getAttribute().'">'.htmlentities($content).'</code>';
$class = $el->getAttribute()['code'];
return '<code class="'.$class.'">'.htmlentities($content).'</code>';
}
});
}
@ -203,6 +204,8 @@ class Post
if (DB::connection() === 'sqlite') {
$datetime = "strftime('%Y %m %d %H %M', `posts`.`datetime`)";
} else if (DB::connection() === 'postgres') {
$datetime = "to_char(datetime,'YYYY MM DD HH24 MI')";
} else {
$datetime = "DATE_FORMAT(`datetime`,'%Y %c %e %k %i')";
}
@ -424,10 +427,14 @@ class Post
if (DB::connection() === 'sqlite') {
$datetime = "strftime('%d %m %Y %H:%M', `posts`.`datetime`)";
} else if (DB::connection() === 'postgres') {
$datetime = "to_char(posts.datetime,'DD Mon YYYY HH24:MI')";
} else {
$datetime = "DATE_FORMAT(`posts`.`datetime`,'%d %b %Y %H:%i')";
}
$like_match = "LIKE ".DB::concat("'%'", "?", "'%'");
return DB::get_instance()->query("
SELECT
`id`, `text`, `feeling`, `persons`, `location`, `privacy`, `content_type`, `content`,
@ -438,11 +445,11 @@ class Post
($from ? "`posts`.`datetime` > ? AND " : "").
($to ? "`posts`.`datetime` < ? AND " : "").
($id ? "`id` = ? AND " : "").
($tag ? "`plain_text` LIKE CONCAT('%', ?, '%') AND " : "").
($loc ? "`location` LIKE CONCAT('%', ?, '%') AND " : "").
($person ? "`persons` LIKE CONCAT('%', ?, '%') AND " : "").
($tag ? "`plain_text` $like_match AND " : "").
($loc ? "`location` $like_match AND " : "").
($person ? "`persons` $like_match AND " : "").
"`status` <> 5
ORDER BY `posts`.`datetime` DESC
ORDER BY `posts`.`datetime` ".(@$r["sort"] == 'reverse' ? "ASC" : "DESC")."
LIMIT ? OFFSET ?
", $from, $to, $id, $tag, $loc, $person, $r["limit"], $r["offset"]
)->all();

View file

@ -35,7 +35,11 @@ class user
return ["logged_in" => true, "is_visitor" => false];
}
$visitors = Config::get_safe("visitor", []);
// Legacy: Visitors and Friends.
$visitors = array_merge(
Config::get_safe("friends", []),
Config::get_safe("visitor", [])
);
if(!empty($visitors) && isset($visitors[$nick]) && $visitors[$nick] === $pass){
$_SESSION[User::SESSION_NAME] = 'visitor';
return ["logged_in" => false, "is_visitor" => true];

View file

@ -17,10 +17,10 @@ if(Config::get_safe('debug', false)){
error_reporting(E_ALL);
// Check extensions
$required = ['curl', 'PDO', 'pdo_mysql', 'gd'];
$required = ['curl', 'PDO', 'pdo_mysql', 'gd', 'exif'];
$loaded = get_loaded_extensions();
if($missing = array_diff($required, $loaded)){
die("Missing extensions, please install: ".impode(", ", $missing));
die("Missing extensions, please install: ".implode(", ", $missing));
}
}

View file

@ -11,6 +11,15 @@ db_connection = sqlite
;mysql_pass = root
;db_name = blog
;[database]
;db_connection = postgres
;postgres_socket = /tmp/postgres.sock
;postgres_host = localhost
;postgres_port = 5432
;postgres_user = root
;postgres_pass = root
;db_name = blog
[profile]
title = Blog
name = Max Musermann
@ -30,6 +39,7 @@ theme = theme02
;styles[] = static/styles/custom1.css
;styles[] = static/styles/custom2.css
;scripts = static/styles/scripts.css
;footer = "Edit this if you really want to remove my backlink :("
[bbcode]
;bbtags[quote] = "<quote>{param}</quote>"
@ -39,9 +49,9 @@ force_login = true
nick = demo
pass = demo
[visitors]
;visitor[user] = pass
;visitor[user] = pass
[friends]
;friends[user] = pass
;friends[user] = pass
[directories]
images_path = data/i/
@ -62,7 +72,6 @@ logs_path = data/logs/
[system]
;timezone = Europe/Vienna
system_name = blog
version = 1.253
version = 1.42
debug = false
logs = false
logs = false

View file

@ -1,31 +1,17 @@
version: "3"
services:
webserver:
blog:
image: m1k1o/blog:latest
container_name: blog_apache
environment:
TZ: Europe/Vienna
BLOG_DB_CONNECTION: mysql
BLOG_MYSQL_HOST: mariadb
BLOG_MYSQL_PORT: 3306
BLOG_MYSQL_USER: root
BLOG_MYSQL_PASS: root
BLOG_DB_NAME: blog
restart: unless-stopped
environment:
TZ: Europe/Vienna
BLOG_TITLE: Blog
BLOG_NAME: Max Musermann
BLOG_NICK: username
BLOG_PASS: password
BLOG_LANG: en
ports:
- ${HTTP_PORT-80}:80
volumes:
- ${DATA-./data}:/var/www/html/data
mariadb:
image: mariadb:10.1
container_name: blog_mariadb
environment:
MYSQL_DATABASE: blog
MYSQL_ROOT_PASSWORD: root
restart: unless-stopped
- 80:80
volumes:
- mariadb:/var/lib/mysql
- ./app/db/mysql:/docker-entrypoint-initdb.d:ro
volumes:
mariadb:
- ./data:/var/www/html/data

View file

@ -10,6 +10,10 @@ if(empty($_SESSION['token'])){
}
}
function escape($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
//$.ajaxSetup({headers:{'Csrf-Token':'token'}});
Log::put("visitors");
@ -40,6 +44,7 @@ if(!empty($styles)){
}
$styles = array_unique($styles);
$styles = array_map('escape', $styles);
$styles_html = '<link href="'.implode('" rel="stylesheet" type="text/css"/>'.PHP_EOL.'<link href="', $styles).'" rel="stylesheet" type="text/css"/>'.PHP_EOL;
}
@ -47,32 +52,39 @@ if(!empty($styles)){
$scripts = Config::get_safe("scripts", []);
$scripts_html = '';
if(!empty($scripts)){
if(!is_array($styles)){
$styles = [$styles];
if(!is_array($scripts)){
$scripts = [$scripts];
}
$scripts = array_unique($scripts);
$scripts = array_map('escape', $scripts);
$scripts_html = '<script src="'.implode('" type="text/javascript"></script>'.PHP_EOL.'<script src="', $scripts).'" type="text/javascript"></script>'.PHP_EOL;
}
// Use version suffix in URLs to prevent cache
$versionSuffix = '';
if (Config::get_safe("version", false)) {
$versionSuffix = '?v='.rawurlencode(Config::get("version"));
}
?><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo Config::get("title"); ?></title>
<title><?php echo escape(Config::get("title")); ?></title>
<meta name="robots" content="noindex, nofollow">
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link href="static/styles/main.css?v=<?php echo Config::get("version"); ?>" rel="stylesheet" type="text/css" />
<link href="static/styles/<?php echo Config::get_safe("theme", "theme01"); ?>.css?v=<?php echo Config::get("version"); ?>" rel="stylesheet" type="text/css" />
<link href="static/styles/main.css<?php echo $versionSuffix?>" rel="stylesheet" type="text/css" />
<link href="static/styles/<?php echo rawurlencode(Config::get_safe("theme", "theme01")); ?>.css<?php echo $versionSuffix?>" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans&amp;subset=all" rel="stylesheet">
<link href="static/styles/lightbox.css" rel="stylesheet" type="text/css" />
<?php echo Config::get("highlight") ? '<link href="static/styles/highlight.css" rel="stylesheet" type="text/css" />' : ''; ?>
<?php echo Config::get_safe("highlight", false) ? '<link href="static/styles/highlight-monokai-sublime.css" rel="stylesheet" type="text/css" />'.PHP_EOL : ''; ?>
<?php echo $styles_html; ?>
</head>
@ -103,7 +115,6 @@ if(!empty($scripts)){
</div>
<div class="modal-footer">
<div class="buttons">
<!--<div class="left"><a>Register</a> - <a>Forgot Password</a></div>-->
<a class="button gray close"><?php echo __("Cancel"); ?></a>
<button type="button" class="button blue do_login"><?php echo __("Login"); ?></button>
</div>
@ -170,7 +181,7 @@ if(!empty($scripts)){
<div class="modal-body drop_space">
<div class="e_drag"><span><?php echo __("Drag photos here"); ?></span></div>
<div class="e_drop"><span><?php echo __("Drop photos here"); ?></span></div>
<img src="<?php echo Config::get("pic_small"); ?>" width="40" height="40" class="e_profile">
<img src="<?php echo escape(Config::get("pic_small")); ?>" width="40" height="40" class="e_profile">
<!--<div class="e_text" contenteditable="true"></div>-->
<div class="t_area">
<textarea class="e_text" placeholder="<?php echo __("What's on your mind?"); ?>"></textarea>
@ -282,10 +293,10 @@ if(!empty($scripts)){
<a class="button"><?php echo __("Show hidden content"); ?></a>
</div>
<div class="b_header">
<img src="<?php echo Config::get("pic_small"); ?>" width="40" height="40" class="b_profile">
<img src="<?php echo escape(Config::get("pic_small")); ?>" width="40" height="40" class="b_profile">
<div class="b_desc">
<div class="b_sharer">
<span class="b_name"><?php echo Config::get("name"); ?></span><span class="b_options"> - </span><span class="b_feeling"></span><span class="b_with"> <?php echo __("with"); ?> </span><span class="b_persons"></span><span class="b_here"> <?php echo __("here:"); ?> </span><span class="b_location"></span>
<span class="b_name"><?php echo escape(Config::get("name")); ?></span><span class="b_options"> - </span><span class="b_feeling"></span><span class="b_with"> <?php echo __("with"); ?> </span><span class="b_persons"></span><span class="b_here"> <?php echo __("here:"); ?> </span><span class="b_location"></span>
</div>
<i class="privacy_icon"></i>
<a class="b_date"></a>
@ -305,18 +316,18 @@ if(!empty($scripts)){
</div>
<div class="bluebar">
<h1><?php echo Config::get("title"); ?></h1>
<h1><?php echo escape(Config::get("title")); ?></h1>
</div>
<div class="headbar">
<div class="cover">
<?php echo $header; ?>
<div class="overlay"></div>
<?php echo (Config::get_safe("cover", false) ? '<img src="'.Config::get("cover").'">' : (empty($header) ? '<div style="padding-bottom: 37%;"></div>' : '')); ?>
<?php echo (Config::get_safe("cover", false) ? '<img src="'.escape(Config::get("cover")).'">' : (empty($header) ? '<div style="padding-bottom: 37%;"></div>' : '')); ?>
<div class="profile">
<img src="<?php echo Config::get("pic_big"); ?>">
<img src="<?php echo escape(Config::get("pic_big")); ?>">
</div>
<div class="name"><?php echo Config::get("name"); ?></div>
<div class="name"><?php echo escape(Config::get("name")); ?></div>
</div>
<div id="headline"></div>
</div>
@ -330,16 +341,18 @@ if(!empty($scripts)){
<div id="eof_feed">
<img src="static/images/zpEYXu5Wdu6.png">
<p><?php echo Config::get("version"); ?> &copy; 2016-2020 <br>Miroslav Šedivý</p>
<p><?php echo escape(Config::get("version")); ?> &copy; 2016-2022<br>
<?php echo Config::get_safe("footer", false) ? escape(Config::get_safe("footer")) : '<a href="https://github.com/m1k1o/blog" class="link" title="m1k1o/blog github repository" target="_blank">m1k1o/blog</a>'; ?>
</p>
</div>
<script src="static/scripts/jquery.min.js"></script>
<script>$["\x61\x6A\x61\x78\x53\x65\x74\x75\x70"]({"\x68\x65\x61\x64\x65\x72\x73":{"\x43\x73\x72\x66-\x54\x6F\x6B\x65\x6E":"<?php echo $_SESSION['token'];?>"}});</script>
<script src="static/scripts/lightbox.js"></script>
<script src="static/scripts/datepick.js?v=<?php echo Config::get("version"); ?>"></script>
<script src="static/scripts/datepick.js<?php echo $versionSuffix?>"></script>
<script src="static/scripts/autosize.js"></script>
<?php echo Config::get("highlight") ? '<script src="static/scripts/highlight.js"></script><script>hljs.initHighlightingOnLoad();</script>' : ''; ?>
<script src="static/scripts/app.js?v=<?php echo Config::get("version"); ?>"></script>
<?php echo Config::get_safe("highlight", false) ? '<script src="static/scripts/highlight-10.1.2.min.js"></script><script>hljs.initHighlightingOnLoad();</script>'.PHP_EOL : ''; ?>
<script src="static/scripts/app.js<?php echo $versionSuffix?>"></script>
<?php echo $scripts_html; ?>
</body>

View file

@ -13,6 +13,7 @@ var posts = {
limit: 5, // Limit posts per load
offset: 0, // Current offset
sort: "default", // Default is from newest to oldest posts (use reverse for oldest to newest)
filter: {
from: null, // Show posts from specified date
@ -34,6 +35,10 @@ var posts = {
// Update ID hash
location.hash.replace(/([a-z]+)\=([^\&]+)/g, function(_, key, value){
if (key == "sort") {
posts.sort = decodeURIComponent(value);
return;
}
posts.filter[key] = decodeURIComponent(value);
$(".more_posts").show();
});
@ -72,6 +77,7 @@ var posts = {
action: "load",
limit: posts.limit,
offset: posts.offset,
sort: posts.sort,
filter: posts.filter
},
success: function(posts_data){

View file

@ -51,9 +51,11 @@ var datepick = function(container) {
var thead = $(
'<thead>' +
'<tr>' +
'<th><button type="button" class="button blue prev_y" title="Previous Year">&lt;&lt;</button></th>' +
'<th><button type="button" class="button blue prev" title="Previous Month">&lt;</button></th>' +
'<th class="month-pick" colspan="5" title="Select Month">'+this.months[this.m]+' '+this.y+'</th>' +
'<th class="month-pick" colspan="3" title="Select Month">'+this.months[this.m]+' '+this.y+'</th>' +
'<th><button type="button" class="button blue next" title="Next Month">&gt;</button></th>' +
'<th><button type="button" class="button blue next_y" title="Next Year">&gt;&gt;</button></th>' +
'</tr>' +
'<tr>' +
'<th>Mo</th>' +
@ -68,12 +70,22 @@ var datepick = function(container) {
);
var x = this;
$(thead).find(".prev_y").click(function(){
x.dec_y();
x.load_table();
$(thead).find(".month-pick").text(x.months[x.m]+' '+x.y);
});
$(thead).find(".prev").click(function(){
x.dec_m();
x.load_table();
$(thead).find(".month-pick").text(x.months[x.m]+' '+x.y);
});
$(thead).find(".next_y").click(function(){
x.inc_y();
x.load_table();
$(thead).find(".month-pick").text(x.months[x.m]+' '+x.y);
});
$(thead).find(".next").click(function(){
x.inc_m();
x.load_table();

44
static/scripts/highlight-10.1.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -114,6 +114,10 @@ body {
text-transform: uppercase;
}
#eof_feed .link {
color: #90949c;
}
.show_more {
height: 40px;
line-height: 40px;
@ -126,7 +130,6 @@ body {
background: linear-gradient(to bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 75%,rgba(255,255,255,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff',GradientType=0 );
cursor: pointer;
vertical-align: bottom;
}
.b_post {
@ -587,11 +590,6 @@ body {
margin: 8px;
}
.modal-footer .buttons .left {
display: inline-block;
float: left;
}
.modal-footer:before,
.modal-footer:after {
content: " ";
@ -779,6 +777,8 @@ body {
min-height: 88px;
max-width: 100%;
min-width: 100%;
background: transparent;
border: 0;
}
.options {
@ -1055,7 +1055,8 @@ code {
text-align: center;
}
.datepicker table {
display: inline-block;
width: 100%;
margin: 5px 0;
}
.datepicker th,
@ -1063,6 +1064,9 @@ code {
width: 12.5%;
}
.datepicker th {
padding: 5px 0;
}
.datepicker td {
color: #999;
padding: 5px;

View file

@ -181,6 +181,10 @@ body {
text-transform: uppercase;
}
#eof_feed .link {
color: var(--secondary-text);
}
.show_more {
height: 40px;
line-height: 40px;
@ -192,7 +196,6 @@ body {
background: -webkit-linear-gradient(top, transparent 0%,var(--primary-background) 75%,var(--primary-background) 100%);
background: linear-gradient(to bottom, transparent 0%,var(--primary-background) 75%,var(--primary-background) 100%);
cursor: pointer;
vertical-align: bottom;
}
.b_post {
@ -714,11 +717,6 @@ body {
margin-right: 0;
}
.modal-footer .buttons .left {
display: inline-block;
float: left;
}
.modal-footer:before,
.modal-footer:after {
content: " ";
@ -1175,7 +1173,8 @@ code {
text-align: center;
}
.datepicker table {
display: inline-block;
width: 100%;
margin: 5px 0;
}
.datepicker th,
@ -1183,6 +1182,9 @@ code {
width: 12.5%;
}
.datepicker th {
padding: 5px 0;
}
.datepicker td {
color: var(--datepicker-inactive-month);
padding: 5px;