Compare commits
No commits in common. "master" and "2.2" have entirely different histories.
459 changed files with 13114 additions and 37921 deletions
5
.gitattributes
vendored
5
.gitattributes
vendored
|
@ -1,5 +0,0 @@
|
||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
# Shell scripts require LF
|
|
||||||
*.sh text eol=lf
|
|
108
.github/workflows/build-containers.yml
vendored
108
.github/workflows/build-containers.yml
vendored
|
@ -1,108 +0,0 @@
|
||||||
name: Build Docker containers
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
jobs:
|
|
||||||
build-client:
|
|
||||||
name: Build and push client/ Docker container
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Determine metadata
|
|
||||||
run: |
|
|
||||||
CLOSEST_VER="$(git describe --tags --abbrev=0 $GITHUB_SHA)"
|
|
||||||
CLOSEST_MAJOR_VER="$(echo ${CLOSEST_VER} | cut -d'.' -f1)"
|
|
||||||
CLOSEST_MINOR_VER="$(echo ${CLOSEST_VER} | cut -d'.' -f2)"
|
|
||||||
SHORT_COMMIT=$(echo $GITHUB_SHA | cut -c1-8)
|
|
||||||
BUILD_INFO="v${CLOSEST_VER}-${SHORT_COMMIT}"
|
|
||||||
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
||||||
|
|
||||||
echo "major_tag=${CLOSEST_MAJOR_VER}" >> $GITHUB_ENV
|
|
||||||
echo "minor_tag=${CLOSEST_MAJOR_VER}.${CLOSEST_MINOR_VER}" >> $GITHUB_ENV
|
|
||||||
echo "build_info=${BUILD_INFO}" >> $GITHUB_ENV
|
|
||||||
echo "build_date=${BUILD_DATE}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo "Build Info: ${BUILD_INFO}"
|
|
||||||
echo "Build Date: ${BUILD_DATE}"
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
|
|
||||||
- name: Build container
|
|
||||||
run: >
|
|
||||||
docker buildx build --push
|
|
||||||
--platform linux/amd64,linux/arm/v7,linux/arm64/v8
|
|
||||||
--build-arg BUILD_INFO=${{ env.build_info }}
|
|
||||||
--build-arg BUILD_DATE=${{ env.build_date }}
|
|
||||||
--build-arg SOURCE_COMMIT=$GITHUB_SHA
|
|
||||||
--build-arg DOCKER_REPO=szurubooru/client
|
|
||||||
-t "szurubooru/client:latest"
|
|
||||||
-t "szurubooru/client:${{ env.major_tag }}"
|
|
||||||
-t "szurubooru/client:${{ env.minor_tag }}"
|
|
||||||
./client
|
|
||||||
|
|
||||||
build-server:
|
|
||||||
name: Build and push server/ Docker container
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Determine metadata
|
|
||||||
run: |
|
|
||||||
CLOSEST_VER="$(git describe --tags --abbrev=0 $GITHUB_SHA)"
|
|
||||||
CLOSEST_MAJOR_VER="$(echo ${CLOSEST_VER} | cut -d'.' -f1)"
|
|
||||||
CLOSEST_MINOR_VER="$(echo ${CLOSEST_VER} | cut -d'.' -f2)"
|
|
||||||
SHORT_COMMIT=$(echo $GITHUB_SHA | cut -c1-8)
|
|
||||||
BUILD_INFO="v${CLOSEST_VER}-${SHORT_COMMIT}"
|
|
||||||
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
||||||
|
|
||||||
echo "major_tag=${CLOSEST_MAJOR_VER}" >> $GITHUB_ENV
|
|
||||||
echo "minor_tag=${CLOSEST_MAJOR_VER}.${CLOSEST_MINOR_VER}" >> $GITHUB_ENV
|
|
||||||
echo "build_info=${BUILD_INFO}" >> $GITHUB_ENV
|
|
||||||
echo "build_date=${BUILD_DATE}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
echo "Build Info: ${BUILD_INFO}"
|
|
||||||
echo "Build Date: ${BUILD_DATE}"
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
|
|
||||||
- name: Build container
|
|
||||||
run: >
|
|
||||||
docker buildx build --push
|
|
||||||
--platform linux/amd64,linux/arm/v7,linux/arm64/v8
|
|
||||||
--build-arg BUILD_DATE=${{ env.build_date }}
|
|
||||||
--build-arg SOURCE_COMMIT=$GITHUB_SHA
|
|
||||||
--build-arg DOCKER_REPO=szurubooru/server
|
|
||||||
-t "szurubooru/server:latest"
|
|
||||||
-t "szurubooru/server:${{ env.major_tag }}"
|
|
||||||
-t "szurubooru/server:${{ env.minor_tag }}"
|
|
||||||
./server
|
|
28
.github/workflows/run-unit-tests.yml
vendored
28
.github/workflows/run-unit-tests.yml
vendored
|
@ -1,28 +0,0 @@
|
||||||
name: Run unit tests
|
|
||||||
on: [push, pull_request]
|
|
||||||
jobs:
|
|
||||||
test-server:
|
|
||||||
name: Run pytest for server/
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
|
|
||||||
- name: Build test container
|
|
||||||
run: >
|
|
||||||
docker buildx build --load
|
|
||||||
--platform linux/amd64 --target testing
|
|
||||||
-t test_container
|
|
||||||
./server
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: >
|
|
||||||
docker run --rm -t test_container
|
|
||||||
--color=no
|
|
||||||
--cov-report=term-missing:skip-covered
|
|
||||||
--cov=szurubooru
|
|
||||||
szurubooru/
|
|
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,18 +1,4 @@
|
||||||
# User-specific configuration
|
|
||||||
config.yaml
|
config.yaml
|
||||||
.env
|
|
||||||
|
|
||||||
# Client Development Artifacts
|
|
||||||
*/*_modules/
|
*/*_modules/
|
||||||
client/public
|
|
||||||
|
|
||||||
# Server Development Artifacts
|
|
||||||
.coverage
|
.coverage
|
||||||
.cache
|
.cache
|
||||||
server/**/lib/
|
|
||||||
server/**/bin/
|
|
||||||
server/**/pyvenv.cfg
|
|
||||||
__pycache__/
|
|
||||||
|
|
||||||
data/
|
|
||||||
sql/
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
repos:
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
||||||
rev: v4.4.0
|
|
||||||
hooks:
|
|
||||||
- id: trailing-whitespace
|
|
||||||
- id: end-of-file-fixer
|
|
||||||
- id: check-yaml
|
|
||||||
- id: mixed-line-ending
|
|
||||||
|
|
||||||
|
|
||||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
|
||||||
rev: v1.4.2
|
|
||||||
hooks:
|
|
||||||
- id: remove-tabs
|
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
|
||||||
rev: '23.1.0'
|
|
||||||
hooks:
|
|
||||||
- id: black
|
|
||||||
files: 'server/'
|
|
||||||
types: [python]
|
|
||||||
language_version: python3.9
|
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/isort
|
|
||||||
rev: '5.12.0'
|
|
||||||
hooks:
|
|
||||||
- id: isort
|
|
||||||
files: 'server/'
|
|
||||||
types: [python]
|
|
||||||
exclude: server/szurubooru/migrations/env.py
|
|
||||||
additional_dependencies:
|
|
||||||
- toml
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
|
||||||
rev: v2.7.1
|
|
||||||
hooks:
|
|
||||||
- id: prettier
|
|
||||||
files: client/js/
|
|
||||||
exclude: client/js/.gitignore
|
|
||||||
args: ['--config', 'client/.prettierrc.yml']
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
|
||||||
rev: v8.33.0
|
|
||||||
hooks:
|
|
||||||
- id: eslint
|
|
||||||
files: client/js/
|
|
||||||
args: ['--fix']
|
|
||||||
additional_dependencies:
|
|
||||||
- eslint-config-prettier
|
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
|
||||||
rev: '6.0.0'
|
|
||||||
hooks:
|
|
||||||
- id: flake8
|
|
||||||
files: server/szurubooru/
|
|
||||||
additional_dependencies:
|
|
||||||
- flake8-print
|
|
||||||
args: ['--config=server/.flake8']
|
|
||||||
|
|
||||||
fail_fast: true
|
|
||||||
exclude: LICENSE.md
|
|
File diff suppressed because it is too large
Load diff
187
INSTALL.md
Normal file
187
INSTALL.md
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
This guide assumes Arch Linux. Although exact instructions for other
|
||||||
|
distributions are different, the steps stay roughly the same.
|
||||||
|
|
||||||
|
### Installing hard dependencies
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:~$ sudo pacman -S postgresql
|
||||||
|
user@host:~$ sudo pacman -S python
|
||||||
|
user@host:~$ sudo pacman -S python-pip
|
||||||
|
user@host:~$ sudo pacman -S ffmpeg
|
||||||
|
user@host:~$ sudo pacman -S npm
|
||||||
|
user@host:~$ sudo pacman -S elasticsearch
|
||||||
|
user@host:~$ sudo pip install virtualenv
|
||||||
|
user@host:~$ python --version
|
||||||
|
Python 3.5.1
|
||||||
|
```
|
||||||
|
|
||||||
|
The reason `ffmpeg` is used over, say, `ImageMagick` or even `PIL` is because of
|
||||||
|
Flash and video posts.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Setting up a database
|
||||||
|
|
||||||
|
First, basic `postgres` configuration:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:~$ sudo -i -u postgres initdb --locale en_US.UTF-8 -E UTF8 -D /var/lib/postgres/data
|
||||||
|
user@host:~$ sudo systemctl start postgresql
|
||||||
|
user@host:~$ sudo systemctl enable postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
Then creating a database:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:~$ sudo -i -u postgres createuser --interactive
|
||||||
|
Enter name of role to add: szuru
|
||||||
|
Shall the new role be a superuser? (y/n) n
|
||||||
|
Shall the new role be allowed to create databases? (y/n) n
|
||||||
|
Shall the new role be allowed to create more new roles? (y/n) n
|
||||||
|
user@host:~$ sudo -i -u postgres createdb szuru
|
||||||
|
user@host:~$ sudo -i -u postgres psql -c "ALTER USER szuru PASSWORD 'dog';"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Setting up elasticsearch
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:~$ sudo systemctl start elasticsearch
|
||||||
|
user@host:~$ sudo systemctl enable elasticsearch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preparing environment
|
||||||
|
|
||||||
|
Getting `szurubooru`:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:~$ git clone https://github.com/rr-/szurubooru.git szuru
|
||||||
|
user@host:~$ cd szuru
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing frontend dependencies:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:szuru$ cd client
|
||||||
|
user@host:szuru/client$ npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
`npm` sandboxes dependencies by default, i.e. installs them to
|
||||||
|
`./node_modules`. This is good, because it avoids polluting the system with the
|
||||||
|
project's dependencies. To make Python work the same way, we'll use
|
||||||
|
`virtualenv`. Installing backend dependencies with `virtualenv` looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:szuru/client$ cd ../server
|
||||||
|
user@host:szuru/server$ virtualenv python_modules # consistent with node_modules
|
||||||
|
user@host:szuru/server$ source python_modules/bin/activate # enters the sandbox
|
||||||
|
(python_modules) user@host:szuru/server$ pip install -r requirements.txt # installs the dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Preparing `szurubooru` for first run
|
||||||
|
|
||||||
|
1. Configure things:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:szuru$ cp config.yaml.dist config.yaml
|
||||||
|
user@host:szuru$ vim config.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Pay extra attention to these fields:
|
||||||
|
|
||||||
|
- base URL,
|
||||||
|
- API URL,
|
||||||
|
- data directory,
|
||||||
|
- data URL,
|
||||||
|
- database,
|
||||||
|
- the `smtp` section.
|
||||||
|
|
||||||
|
2. Compile the frontend:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:szuru$ cd client
|
||||||
|
user@host:szuru/client$ npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Upgrade the database:
|
||||||
|
|
||||||
|
```console
|
||||||
|
user@host:szuru/client$ cd ../server
|
||||||
|
user@host:szuru/server$ source python_modules/bin/activate
|
||||||
|
(python_modules) user@host:szuru/server$ alembic upgrade head
|
||||||
|
```
|
||||||
|
|
||||||
|
`alembic` should have been installed during installation of `szurubooru`'s
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
4. Run the tests:
|
||||||
|
|
||||||
|
```console
|
||||||
|
(python_modules) user@host:szuru/server$ ./test
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to rebuild the frontend after each change to configuration.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Wiring `szurubooru` to the web server
|
||||||
|
|
||||||
|
`szurubooru` is divided into two parts: public static files, and the API. It
|
||||||
|
tries not to impose any networking configurations on the user, so it is the
|
||||||
|
user's responsibility to wire these to their web server.
|
||||||
|
|
||||||
|
Below are described the methods to integrate the API into a web server:
|
||||||
|
|
||||||
|
1. Run API locally with `waitress`, and bind it with a reverse proxy. In this
|
||||||
|
approach, the user needs to (from within `virtualenv`) install `waitress`
|
||||||
|
with `pip install waitress` and then start `szurubooru` with `./host-waitress`
|
||||||
|
from within the `server/` directory (see `--help` for details). Then the
|
||||||
|
user needs to add a virtual host that delegates the API requests to the
|
||||||
|
local API server, and the browser requests to the `client/public/`
|
||||||
|
directory.
|
||||||
|
2. Alternatively, Apache users can use `mod_wsgi`.
|
||||||
|
3. Alternatively, users can use other WSGI frontends such as `gunicorn` or
|
||||||
|
`uwsgi`, but they'll need to write wrapper scripts themselves.
|
||||||
|
|
||||||
|
Note that the API URL in the virtual host configuration needs to be the same as
|
||||||
|
the one in the `config.yaml`, so that client knows how to access the backend!
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
**nginx configuration** - wiring API `http://great.dude/api/` to
|
||||||
|
`localhost:6666` to avoid fiddling with CORS:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name great.dude;
|
||||||
|
merge_slashes off; # to support post tags such as ///
|
||||||
|
|
||||||
|
location ~ ^/api$ {
|
||||||
|
return 302 /api/;
|
||||||
|
}
|
||||||
|
location ~ ^/api/(.*)$ {
|
||||||
|
proxy_pass http://127.0.0.1:6666/$1$is_args$args;
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
root /home/rr-/src/maintained/szurubooru/client/public;
|
||||||
|
try_files $uri /index.htm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**`config.yaml`**:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
api_url: 'http://big.dude/api/'
|
||||||
|
base_url: 'http://big.dude/'
|
||||||
|
data_url: 'http://big.dude/data/'
|
||||||
|
data_dir: '/home/rr-/src/maintained/szurubooru/client/public/data'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the backend is started with `host-waitress` from within `virtualenv` and
|
||||||
|
`./server/` directory.
|
20
README.md
20
README.md
|
@ -3,16 +3,14 @@
|
||||||
Szurubooru is an image board engine inspired by services such as Danbooru,
|
Szurubooru is an image board engine inspired by services such as Danbooru,
|
||||||
Gelbooru and Moebooru dedicated for small and medium communities. Its name [has
|
Gelbooru and Moebooru dedicated for small and medium communities. Its name [has
|
||||||
its roots in Polish language and has onomatopeic meaning of scraping or
|
its roots in Polish language and has onomatopeic meaning of scraping or
|
||||||
scrubbing](https://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*.
|
scrubbing](http://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations
|
- Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations
|
||||||
- Ability to retrieve web video content using [yt-dlp](https://github.com/yt-dlp/yt-dlp)
|
|
||||||
- Post comments
|
- Post comments
|
||||||
- Post notes / annotations, including arbitrary polygons
|
- Post notes / annotations, including arbitrary polygons
|
||||||
- Rich JSON REST API ([see documentation](doc/API.md))
|
- Rich JSON REST API ([see documentation](https://github.com/rr-/szurubooru/blob/master/API.md))
|
||||||
- Token based authentication for clients
|
|
||||||
- Rich search system
|
- Rich search system
|
||||||
- Rich privilege system
|
- Rich privilege system
|
||||||
- Autocomplete in search and while editing tags
|
- Autocomplete in search and while editing tags
|
||||||
|
@ -20,20 +18,20 @@ scrubbing](https://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*.
|
||||||
- Tag suggestions
|
- Tag suggestions
|
||||||
- Tag implications (adding a tag automatically adds another)
|
- Tag implications (adding a tag automatically adds another)
|
||||||
- Tag aliases
|
- Tag aliases
|
||||||
- Pools and pool categories
|
|
||||||
- Duplicate detection
|
- Duplicate detection
|
||||||
- Post rating and favoriting; comment rating
|
- Post rating and favoriting; comment rating
|
||||||
- Polished UI
|
- Polished UI
|
||||||
- Browser configurable endless paging
|
- Browser configurable endless paging
|
||||||
- Browser configurable backdrop grid for transparent images
|
- Browser configurable backdrop grid for transparent images
|
||||||
|
|
||||||
## Installation
|
## Requirements
|
||||||
|
|
||||||
It is recommended that you use Docker for deployment.
|
- Python 3.5
|
||||||
[See installation instructions.](doc/INSTALL.md)
|
- Postgres
|
||||||
|
- FFmpeg
|
||||||
|
- node.js
|
||||||
|
|
||||||
More installation resources, as well as related projects can be found on the
|
[See installation instructions.](https://github.com/rr-/szurubooru/blob/master/INSTALL.md)
|
||||||
[GitHub project Wiki](https://github.com/rr-/szurubooru/wiki)
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
|
@ -47,4 +45,4 @@ Post view:
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[GPLv3](LICENSE.md).
|
[GPLv3](https://github.com/rr-/szurubooru/blob/master/LICENSE.md).
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{ "presets": ["env"] }
|
{ "presets": ["es2015"] }
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
node_modules/*
|
|
||||||
Dockerfile
|
|
||||||
.dockerignore
|
|
||||||
**/.gitignore
|
|
|
@ -1,12 +0,0 @@
|
||||||
env:
|
|
||||||
browser: true
|
|
||||||
commonjs: true
|
|
||||||
es6: true
|
|
||||||
extends: 'prettier'
|
|
||||||
globals:
|
|
||||||
Atomics: readonly
|
|
||||||
SharedArrayBuffer: readonly
|
|
||||||
ignorePatterns:
|
|
||||||
- build.js
|
|
||||||
parserOptions:
|
|
||||||
ecmaVersion: 11
|
|
|
@ -1,4 +0,0 @@
|
||||||
parser: babel
|
|
||||||
printWidth: 79
|
|
||||||
tabWidth: 4
|
|
||||||
quoteProps: consistent
|
|
|
@ -1,44 +0,0 @@
|
||||||
FROM --platform=$BUILDPLATFORM node:lts as builder
|
|
||||||
WORKDIR /opt/app
|
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
COPY . ./
|
|
||||||
|
|
||||||
ARG BUILD_INFO="docker-latest"
|
|
||||||
ARG CLIENT_BUILD_ARGS=""
|
|
||||||
RUN BASE_URL="__BASEURL__" node build.js --gzip ${CLIENT_BUILD_ARGS}
|
|
||||||
|
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM scratch as approot
|
|
||||||
|
|
||||||
COPY docker-start.sh /
|
|
||||||
|
|
||||||
WORKDIR /etc/nginx
|
|
||||||
COPY nginx.conf.docker ./nginx.conf
|
|
||||||
|
|
||||||
WORKDIR /var/www
|
|
||||||
COPY --from=builder /opt/app/public/ .
|
|
||||||
|
|
||||||
|
|
||||||
FROM nginx:alpine as release
|
|
||||||
|
|
||||||
RUN apk --no-cache add dumb-init
|
|
||||||
COPY --from=approot / /
|
|
||||||
|
|
||||||
CMD ["/docker-start.sh"]
|
|
||||||
VOLUME ["/data"]
|
|
||||||
|
|
||||||
ARG DOCKER_REPO
|
|
||||||
ARG BUILD_DATE
|
|
||||||
ARG SOURCE_COMMIT
|
|
||||||
LABEL \
|
|
||||||
maintainer="" \
|
|
||||||
org.opencontainers.image.title="${DOCKER_REPO}" \
|
|
||||||
org.opencontainers.image.url="https://github.com/rr-/szurubooru" \
|
|
||||||
org.opencontainers.image.documentation="https://github.com/rr-/szurubooru/blob/${SOURCE_COMMIT}/doc/INSTALL.md" \
|
|
||||||
org.opencontainers.image.created="${BUILD_DATE}" \
|
|
||||||
org.opencontainers.image.source="https://github.com/rr-/szurubooru" \
|
|
||||||
org.opencontainers.image.revision="${SOURCE_COMMIT}" \
|
|
||||||
org.opencontainers.image.licenses="GPL-3.0"
|
|
565
client/build.js
Executable file → Normal file
565
client/build.js
Executable file → Normal file
|
@ -1,424 +1,227 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// -------------------------------------------------
|
|
||||||
|
|
||||||
const webapp_icons = [
|
|
||||||
{ name: 'android-chrome-192x192.png', size: 192 },
|
|
||||||
{ name: 'android-chrome-512x512.png', size: 512 },
|
|
||||||
{ name: 'apple-touch-icon.png', size: 180 },
|
|
||||||
{ name: 'mstile-150x150.png', size: 150 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const webapp_splash_screens = [
|
|
||||||
{ w: 640, h: 1136, center: 320 },
|
|
||||||
{ w: 750, h: 1294, center: 375 },
|
|
||||||
{ w: 1125, h: 2436, center: 565 },
|
|
||||||
{ w: 1242, h: 2148, center: 625 },
|
|
||||||
{ w: 1536, h: 2048, center: 770 },
|
|
||||||
{ w: 1668, h: 2224, center: 820 },
|
|
||||||
{ w: 2048, h: 2732, center: 1024 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const external_js = [
|
|
||||||
'dompurify',
|
|
||||||
'js-cookie',
|
|
||||||
'marked',
|
|
||||||
'mousetrap',
|
|
||||||
'nprogress',
|
|
||||||
'superagent',
|
|
||||||
'underscore',
|
|
||||||
];
|
|
||||||
|
|
||||||
const app_manifest = {
|
|
||||||
name: 'szurubooru',
|
|
||||||
icons: [
|
|
||||||
{
|
|
||||||
src: baseUrl() + 'img/android-chrome-192x192.png',
|
|
||||||
type: 'image/png',
|
|
||||||
sizes: '192x192'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: baseUrl() + 'img/android-chrome-512x512.png',
|
|
||||||
type: 'image/png',
|
|
||||||
sizes: '512x512'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
start_url: baseUrl(),
|
|
||||||
theme_color: '#24aadd',
|
|
||||||
background_color: '#ffffff',
|
|
||||||
display: 'standalone'
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------
|
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const execSync = require('child_process').execSync;
|
const execSync = require('child_process').execSync;
|
||||||
const browserify = require('browserify');
|
const camelcase = require('camelcase');
|
||||||
const chokidar = require('chokidar');
|
|
||||||
const WebSocket = require('ws');
|
function convertKeysToCamelCase(input) {
|
||||||
var PrettyError = require('pretty-error');
|
let result = {};
|
||||||
var pe = new PrettyError();
|
Object.keys(input).map((key, _) => {
|
||||||
|
const value = input[key];
|
||||||
|
if (value !== null && value.constructor == Object) {
|
||||||
|
result[camelcase(key)] = convertKeysToCamelCase(value);
|
||||||
|
} else {
|
||||||
|
result[camelcase(key)] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function readTextFile(path) {
|
function readTextFile(path) {
|
||||||
return fs.readFileSync(path, 'utf-8');
|
return fs.readFileSync(path, 'utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
function gzipFile(file) {
|
function writeFile(path, content) {
|
||||||
file = path.normalize(file);
|
return fs.writeFileSync(path, content);
|
||||||
execSync('gzip -6 -k ' + file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function baseUrl() {
|
function getVersion() {
|
||||||
return process.env.BASE_URL ? process.env.BASE_URL : '/';
|
return execSync('git describe --always --dirty --long --tags')
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------
|
function getConfig() {
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const merge = require('merge');
|
||||||
|
const camelcaseKeys = require('camelcase-keys');
|
||||||
|
|
||||||
function bundleHtml() {
|
function parseConfigFile(path) {
|
||||||
|
let result = yaml.load(readTextFile(path, 'utf-8'));
|
||||||
|
return convertKeysToCamelCase(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = parseConfigFile('../config.yaml.dist');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const localConfig = parseConfigFile('../config.yaml');
|
||||||
|
config = merge.recursive(config, localConfig);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Local config does not exist, ignoring');
|
||||||
|
}
|
||||||
|
|
||||||
|
config.canSendMails = !!config.smtp.host;
|
||||||
|
delete config.secret;
|
||||||
|
delete config.smtp;
|
||||||
|
delete config.database;
|
||||||
|
config.meta = {
|
||||||
|
version: getVersion(),
|
||||||
|
buildDate: new Date().toUTCString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyFile(source, target) {
|
||||||
|
fs.createReadStream(source).pipe(fs.createWriteStream(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
function minifyJs(path) {
|
||||||
|
return require('uglify-js').minify(path, {compress: {unused: false}}).code;
|
||||||
|
}
|
||||||
|
|
||||||
|
function minifyCss(css) {
|
||||||
|
return require('csso').minify(css);
|
||||||
|
}
|
||||||
|
|
||||||
|
function minifyHtml(html) {
|
||||||
|
return require('html-minifier').minify(html, {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
conservativeCollapse: true,
|
||||||
|
}).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bundleHtml(config) {
|
||||||
const underscore = require('underscore');
|
const underscore = require('underscore');
|
||||||
const babelify = require('babelify');
|
const babelify = require('babelify');
|
||||||
|
const baseHtml = readTextFile('./html/index.htm', 'utf-8');
|
||||||
|
const finalHtml = baseHtml
|
||||||
|
.replace(
|
||||||
|
/(<title>)(.*)(<\/title>)/,
|
||||||
|
util.format('$1%s$3', config.name));
|
||||||
|
writeFile('./public/index.htm', minifyHtml(finalHtml));
|
||||||
|
|
||||||
function minifyHtml(html) {
|
glob('./html/**/*.tpl', {}, (er, files) => {
|
||||||
return require('html-minifier').minify(html, {
|
let compiledTemplateJs = '\'use strict\'\n';
|
||||||
removeComments: true,
|
compiledTemplateJs += 'let _ = require(\'underscore\');';
|
||||||
collapseWhitespace: true,
|
compiledTemplateJs += 'let templates = {};';
|
||||||
conservativeCollapse: true,
|
for (const file of files) {
|
||||||
}).trim();
|
const name = path.basename(file, '.tpl').replace(/_/g, '-');
|
||||||
}
|
const placeholders = [];
|
||||||
|
let templateText = readTextFile(file, 'utf-8');
|
||||||
|
templateText = templateText.replace(
|
||||||
|
/<%.*?%>/ig,
|
||||||
|
(match) => {
|
||||||
|
const ret = '%%%TEMPLATE' + placeholders.length;
|
||||||
|
placeholders.push(match);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
templateText = minifyHtml(templateText);
|
||||||
|
templateText = templateText.replace(
|
||||||
|
/%%%TEMPLATE(\d+)/g,
|
||||||
|
(match, number) => { return placeholders[number]; });
|
||||||
|
|
||||||
const baseHtml = readTextFile('./html/index.htm')
|
const functionText = underscore.template(
|
||||||
.replace('<!-- Base HTML Placeholder -->', `<base href="${baseUrl()}"/>`);
|
templateText, {variable: 'ctx'}).source;
|
||||||
fs.writeFileSync('./public/index.htm', minifyHtml(baseHtml));
|
compiledTemplateJs += `templates['${name}'] = ${functionText};`;
|
||||||
|
}
|
||||||
let compiledTemplateJs = [
|
compiledTemplateJs += 'module.exports = templates;';
|
||||||
`'use strict';`,
|
writeFile('./js/.templates.autogen.js', compiledTemplateJs);
|
||||||
`let _ = require('underscore');`,
|
console.info('Bundled HTML');
|
||||||
`let templates = {};`
|
});
|
||||||
];
|
|
||||||
|
|
||||||
for (const file of glob.sync('./html/**/*.tpl')) {
|
|
||||||
const name = path.basename(file, '.tpl').replace(/_/g, '-');
|
|
||||||
const placeholders = [];
|
|
||||||
let templateText = readTextFile(file);
|
|
||||||
templateText = templateText.replace(
|
|
||||||
/<%.*?%>/ig,
|
|
||||||
(match) => {
|
|
||||||
const ret = '%%%TEMPLATE' + placeholders.length;
|
|
||||||
placeholders.push(match);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
templateText = minifyHtml(templateText);
|
|
||||||
templateText = templateText.replace(
|
|
||||||
/%%%TEMPLATE(\d+)/g,
|
|
||||||
(match, number) => { return placeholders[number]; });
|
|
||||||
|
|
||||||
const functionText = underscore.template(
|
|
||||||
templateText, { variable: 'ctx' }).source;
|
|
||||||
|
|
||||||
compiledTemplateJs.push(`templates['${name}'] = ${functionText};`);
|
|
||||||
}
|
|
||||||
compiledTemplateJs.push('module.exports = templates;');
|
|
||||||
|
|
||||||
fs.writeFileSync('./js/.templates.autogen.js', compiledTemplateJs.join('\n'));
|
|
||||||
console.info('Bundled HTML');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleCss() {
|
function bundleCss() {
|
||||||
const stylus = require('stylus');
|
const stylus = require('stylus');
|
||||||
|
glob('./css/**/*.styl', {}, (er, files) => {
|
||||||
function minifyCss(css) {
|
let css = '';
|
||||||
return require('csso').minify(css).css;
|
for (const file of files) {
|
||||||
}
|
css += stylus.render(
|
||||||
|
readTextFile(file), {filename: file});
|
||||||
let css = '';
|
|
||||||
for (const file of glob.sync('./css/**/*.styl')) {
|
|
||||||
css += stylus.render(readTextFile(file), { filename: file });
|
|
||||||
}
|
|
||||||
fs.writeFileSync('./public/css/app.min.css', minifyCss(css));
|
|
||||||
if (process.argv.includes('--gzip')) {
|
|
||||||
gzipFile('./public/css/app.min.css');
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.copyFileSync(
|
|
||||||
'./node_modules/font-awesome/css/font-awesome.min.css',
|
|
||||||
'./public/css/vendor.min.css');
|
|
||||||
if (process.argv.includes('--gzip')) {
|
|
||||||
gzipFile('./public/css/vendor.min.css');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.info('Bundled CSS');
|
|
||||||
}
|
|
||||||
|
|
||||||
function minifyJs(path) {
|
|
||||||
return require('terser').minify(
|
|
||||||
fs.readFileSync(path, 'utf-8'), { compress: { unused: false } }).code;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeJsBundle(b, path, compress, callback) {
|
|
||||||
let outputFile = fs.createWriteStream(path);
|
|
||||||
b.bundle().on('error', (e) => console.error(pe.render(e))).pipe(outputFile);
|
|
||||||
outputFile.on('finish', () => {
|
|
||||||
if (compress) {
|
|
||||||
fs.writeFileSync(path, minifyJs(path));
|
|
||||||
}
|
}
|
||||||
callback();
|
writeFile('./public/css/app.min.css', minifyCss(css));
|
||||||
|
|
||||||
|
copyFile(
|
||||||
|
'./node_modules/font-awesome/css/font-awesome.min.css',
|
||||||
|
'./public/css/vendor.min.css');
|
||||||
|
|
||||||
|
console.info('Bundled CSS');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleVendorJs(compress) {
|
function bundleJs(config) {
|
||||||
let b = browserify();
|
const browserify = require('browserify');
|
||||||
for (let lib of external_js) {
|
const external = [
|
||||||
b.require(lib);
|
'underscore',
|
||||||
}
|
'superagent',
|
||||||
if (!process.argv.includes('--no-transpile')) {
|
'mousetrap',
|
||||||
b.add(require.resolve('babel-polyfill'));
|
'js-cookie',
|
||||||
}
|
'nprogress',
|
||||||
const file = './public/js/vendor.min.js';
|
];
|
||||||
writeJsBundle(b, file, compress, () => {
|
|
||||||
if (process.argv.includes('--gzip')) {
|
|
||||||
gzipFile(file);
|
|
||||||
}
|
|
||||||
console.info('Bundled vendor JS');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function bundleAppJs(b, compress, callback) {
|
function writeJsBundle(b, path, message, compress) {
|
||||||
const file = './public/js/app.min.js';
|
let outputFile = fs.createWriteStream(path);
|
||||||
writeJsBundle(b, file, compress, () => {
|
b.bundle().pipe(outputFile);
|
||||||
if (process.argv.includes('--gzip')) {
|
outputFile.on('finish', function() {
|
||||||
gzipFile(file);
|
if (compress) {
|
||||||
}
|
writeFile(path, minifyJs(path));
|
||||||
console.info('Bundled app JS');
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function bundleJs() {
|
|
||||||
if (!process.argv.includes('--no-vendor-js')) {
|
|
||||||
bundleVendorJs(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.argv.includes('--no-app-js')) {
|
|
||||||
let watchify = require('watchify');
|
|
||||||
let b = browserify({ debug: process.argv.includes('--debug') });
|
|
||||||
if (!process.argv.includes('--no-transpile')) {
|
|
||||||
b = b.transform('babelify');
|
|
||||||
}
|
|
||||||
b = b.external(external_js).add(glob.sync('./js/**/*.js'));
|
|
||||||
const compress = !process.argv.includes('--debug');
|
|
||||||
bundleAppJs(b, compress, () => { });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const environment = process.argv.includes('--watch') ? "development" : "production";
|
|
||||||
|
|
||||||
function bundleConfig() {
|
|
||||||
function getVersion() {
|
|
||||||
let build_info = process.env.BUILD_INFO;
|
|
||||||
if (!build_info) {
|
|
||||||
try {
|
|
||||||
build_info = execSync('git describe --always --dirty --long --tags').toString();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Cannot find build version');
|
|
||||||
build_info = 'unknown';
|
|
||||||
}
|
}
|
||||||
}
|
console.info(message);
|
||||||
return build_info.trim();
|
});
|
||||||
}
|
}
|
||||||
const config = {
|
|
||||||
meta: {
|
|
||||||
version: getVersion(),
|
|
||||||
buildDate: new Date().toUTCString()
|
|
||||||
},
|
|
||||||
environment: environment
|
|
||||||
};
|
|
||||||
|
|
||||||
fs.writeFileSync('./js/.config.autogen.json', JSON.stringify(config));
|
glob('./js/**/*.js', {}, (er, files) => {
|
||||||
console.info('Generated config file');
|
if (!process.argv.includes('--no-vendor-js')) {
|
||||||
|
let b = browserify();
|
||||||
|
for (let lib of external) {
|
||||||
|
b.require(lib);
|
||||||
|
}
|
||||||
|
if (config.transpile) {
|
||||||
|
b.add(require.resolve('babel-polyfill'));
|
||||||
|
}
|
||||||
|
writeJsBundle(
|
||||||
|
b, './public/js/vendor.min.js', 'Bundled vendor JS', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.argv.includes('--no-app-js')) {
|
||||||
|
let outputFile = fs.createWriteStream('./public/js/app.min.js');
|
||||||
|
let b = browserify({debug: config.debug});
|
||||||
|
if (config.transpile) {
|
||||||
|
b = b.transform('babelify');
|
||||||
|
}
|
||||||
|
writeJsBundle(
|
||||||
|
b.external(external).add(files),
|
||||||
|
'./public/js/app.min.js',
|
||||||
|
'Bundled app JS',
|
||||||
|
!config.debug);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bundleConfig(config) {
|
||||||
|
writeFile(
|
||||||
|
'./js/.config.autogen.json', JSON.stringify(config));
|
||||||
|
glob('./node_modules/font-awesome/fonts/*.*', {}, (er, files) => {
|
||||||
|
for (let file of files) {
|
||||||
|
if (fs.lstatSync(file).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
copyFile(file, path.join('./public/fonts/', path.basename(file)));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleBinaryAssets() {
|
function bundleBinaryAssets() {
|
||||||
fs.copyFileSync('./img/favicon.png', './public/img/favicon.png');
|
glob('./img/*.png', {}, (er, files) => {
|
||||||
console.info('Copied images');
|
for (let file of files) {
|
||||||
|
copyFile(file, path.join('./public/img/', path.basename(file)));
|
||||||
fs.copyFileSync('./fonts/open_sans.woff2', './public/fonts/open_sans.woff2')
|
|
||||||
for (let file of glob.sync('./node_modules/font-awesome/fonts/*.*')) {
|
|
||||||
if (fs.lstatSync(file).isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
fs.copyFileSync(file, path.join('./public/fonts/', path.basename(file)));
|
});
|
||||||
}
|
|
||||||
if (process.argv.includes('--gzip')) {
|
|
||||||
for (let file of glob.sync('./public/fonts/*.*')) {
|
|
||||||
if (file.endsWith('woff2')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
gzipFile(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.info('Copied fonts')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleWebAppFiles() {
|
const config = getConfig();
|
||||||
const Jimp = require('jimp');
|
bundleConfig(config);
|
||||||
|
bundleBinaryAssets();
|
||||||
fs.writeFileSync('./public/manifest.json', JSON.stringify(app_manifest));
|
if (!process.argv.includes('--no-html')) {
|
||||||
console.info('Generated app manifest');
|
bundleHtml(config);
|
||||||
|
|
||||||
Promise.all(webapp_icons.map(icon => {
|
|
||||||
return Jimp.read('./img/app.png')
|
|
||||||
.then(file => {
|
|
||||||
file.resize(icon.size, Jimp.AUTO, Jimp.RESIZE_BEZIER)
|
|
||||||
.write(path.join('./public/img/', icon.name));
|
|
||||||
});
|
|
||||||
}))
|
|
||||||
.then(() => {
|
|
||||||
console.info('Generated webapp icons');
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(webapp_splash_screens.map(dim => {
|
|
||||||
return Jimp.read('./img/splash.png')
|
|
||||||
.then(file => {
|
|
||||||
file.resize(dim.center, Jimp.AUTO, Jimp.RESIZE_BEZIER)
|
|
||||||
.background(0xFFFFFFFF)
|
|
||||||
.contain(dim.w, dim.center,
|
|
||||||
Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
|
|
||||||
.contain(dim.w, dim.h,
|
|
||||||
Jimp.HORIZONTAL_ALIGN_CENTER | Jimp.VERTICAL_ALIGN_MIDDLE)
|
|
||||||
.write(path.join('./public/img/',
|
|
||||||
'apple-touch-startup-image-' + dim.w + 'x' + dim.h + '.png'));
|
|
||||||
});
|
|
||||||
}))
|
|
||||||
.then(() => {
|
|
||||||
console.info('Generated splash screens');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (!process.argv.includes('--no-css')) {
|
||||||
function makeOutputDirs() {
|
|
||||||
const dirs = [
|
|
||||||
'./public',
|
|
||||||
'./public/css',
|
|
||||||
'./public/fonts',
|
|
||||||
'./public/img',
|
|
||||||
'./public/js'
|
|
||||||
];
|
|
||||||
for (let dir of dirs) {
|
|
||||||
if (!fs.existsSync(dir)) {
|
|
||||||
fs.mkdirSync(dir, 0o755);
|
|
||||||
console.info('Created directory: ' + dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function watch() {
|
|
||||||
let wss = new WebSocket.Server({ port: 8080 });
|
|
||||||
const liveReload = !process.argv.includes('--no-live-reload');
|
|
||||||
|
|
||||||
function emitReload() {
|
|
||||||
if (liveReload) {
|
|
||||||
console.log("Requesting live reload.")
|
|
||||||
wss.clients.forEach((client) => {
|
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
|
||||||
client.send("reload");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
chokidar.watch('./fonts/**/*').on('change', () => {
|
|
||||||
try {
|
|
||||||
bundleBinaryAssets();
|
|
||||||
emitReload();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(pe.render(e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
chokidar.watch('./img/**/*').on('change', () => {
|
|
||||||
try {
|
|
||||||
bundleWebAppFiles();
|
|
||||||
emitReload();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(pe.render(e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
chokidar.watch('./html/**/*.tpl').on('change', () => {
|
|
||||||
try {
|
|
||||||
bundleHtml();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(pe.render(e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
chokidar.watch('./css/**/*.styl').on('change', () => {
|
|
||||||
try {
|
|
||||||
bundleCss()
|
|
||||||
emitReload();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(pe.render(e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bundleBinaryAssets();
|
|
||||||
bundleWebAppFiles();
|
|
||||||
bundleCss();
|
bundleCss();
|
||||||
bundleHtml();
|
|
||||||
|
|
||||||
bundleVendorJs(true);
|
|
||||||
|
|
||||||
let watchify = require('watchify');
|
|
||||||
let b = browserify({
|
|
||||||
debug: process.argv.includes('--debug'),
|
|
||||||
entries: ['js/main.js'],
|
|
||||||
cache: {},
|
|
||||||
packageCache: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
b.plugin(watchify);
|
|
||||||
|
|
||||||
if (!process.argv.includes('--no-transpile')) {
|
|
||||||
b = b.transform('babelify');
|
|
||||||
}
|
|
||||||
b = b.external(external_js).add(glob.sync('./js/**/*.js'));
|
|
||||||
const compress = false;
|
|
||||||
|
|
||||||
function bundle(id) {
|
|
||||||
console.info("Rebundling app JS...");
|
|
||||||
let start = new Date();
|
|
||||||
bundleAppJs(b, compress, () => {
|
|
||||||
let end = new Date() - start;
|
|
||||||
console.info('Rebundled in %ds.', end / 1000)
|
|
||||||
emitReload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
b.on('update', bundle);
|
|
||||||
bundle();
|
|
||||||
}
|
}
|
||||||
|
if (!process.argv.includes('--no-js')) {
|
||||||
// -------------------------------------------------
|
bundleJs(config);
|
||||||
|
|
||||||
console.log("Building for '" + environment + "' environment.");
|
|
||||||
makeOutputDirs();
|
|
||||||
bundleConfig();
|
|
||||||
if (process.argv.includes('--watch')) {
|
|
||||||
watch();
|
|
||||||
} else {
|
|
||||||
if (!process.argv.includes('--no-binary-assets')) {
|
|
||||||
bundleBinaryAssets();
|
|
||||||
}
|
|
||||||
if (!process.argv.includes('--no-web-app-files')) {
|
|
||||||
bundleWebAppFiles();
|
|
||||||
}
|
|
||||||
if (!process.argv.includes('--no-html')) {
|
|
||||||
bundleHtml();
|
|
||||||
}
|
|
||||||
if (!process.argv.includes('--no-css')) {
|
|
||||||
bundleCss();
|
|
||||||
}
|
|
||||||
if (!process.argv.includes('--no-js')) {
|
|
||||||
bundleJs();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
$main-color = #24AADD
|
$main-color = #24AADD
|
||||||
$window-color = white
|
$window-color = white
|
||||||
$window-color-darktheme = #1a1a1a
|
|
||||||
$top-navigation-color = #F5F5F5
|
$top-navigation-color = #F5F5F5
|
||||||
$top-navigation-color-darktheme = #333333
|
|
||||||
$text-color = #111
|
$text-color = #111
|
||||||
$text-color-darktheme = #e6e6e6
|
|
||||||
$inactive-link-color = #888
|
$inactive-link-color = #888
|
||||||
$inactive-link-color-darktheme = #cccccc
|
|
||||||
$line-color = #DDD
|
$line-color = #DDD
|
||||||
|
$inactive-tab-text-color = $inactive-link-color
|
||||||
|
$active-tab-text-color = $text-color
|
||||||
$active-tab-background-color = rgba(0, 0, 0, 0.06)
|
$active-tab-background-color = rgba(0, 0, 0, 0.06)
|
||||||
$focused-tab-background-color = rgba(0, 0, 0, 0.03)
|
$focused-tab-background-color = rgba(0, 0, 0, 0.03)
|
||||||
$active-tab-background-color-darktheme = rgba(255, 255, 255, 0.06)
|
|
||||||
$focused-tab-background-color-darktheme = rgba(255, 255, 255, 0.03)
|
|
||||||
$message-info-border-color = #BDF
|
$message-info-border-color = #BDF
|
||||||
$message-info-background-color = #E3EFF9
|
$message-info-background-color = #E3EFF9
|
||||||
$message-error-border-color = #FCC
|
$message-error-border-color = #FCC
|
||||||
|
@ -25,7 +21,6 @@ $input-good-background-color = #F5FFF5
|
||||||
$input-enabled-background-color = #FAFAFA
|
$input-enabled-background-color = #FAFAFA
|
||||||
$input-enabled-border-color = #EEE
|
$input-enabled-border-color = #EEE
|
||||||
$input-enabled-text-color = $text-color
|
$input-enabled-text-color = $text-color
|
||||||
$input-enabled-text-color-darktheme = $text-color-darktheme
|
|
||||||
$input-disabled-background-color = #FAFAFA
|
$input-disabled-background-color = #FAFAFA
|
||||||
$input-disabled-border-color = #EEE
|
$input-disabled-border-color = #EEE
|
||||||
$input-disabled-text-color = #888
|
$input-disabled-text-color = #888
|
||||||
|
@ -40,6 +35,7 @@ $new-tag-background-color = #DFC
|
||||||
$new-tag-text-color = black
|
$new-tag-text-color = black
|
||||||
$implied-tag-background-color = #FFC
|
$implied-tag-background-color = #FFC
|
||||||
$implied-tag-text-color = black
|
$implied-tag-text-color = black
|
||||||
|
$tag-suggestions-background-color = $window-color
|
||||||
$tag-suggestions-header-color = #EEE
|
$tag-suggestions-header-color = #EEE
|
||||||
$tag-suggestions-border-color = #AAA
|
$tag-suggestions-border-color = #AAA
|
||||||
$duplicate-tag-background-color = #FDC
|
$duplicate-tag-background-color = #FDC
|
||||||
|
@ -59,6 +55,3 @@ $hovered-first-note-point-color = red
|
||||||
$safety-safe = #88D488
|
$safety-safe = #88D488
|
||||||
$safety-sketchy = #F3D75F
|
$safety-sketchy = #F3D75F
|
||||||
$safety-unsafe = #F3985F
|
$safety-unsafe = #F3985F
|
||||||
$scrollbar-thumb-color = $main-color
|
|
||||||
$scrollbar-bg-color = $input-enabled-background-color
|
|
||||||
$transparency-grid-square-color = #F0F0F0
|
|
|
@ -1,10 +1,9 @@
|
||||||
@import colors
|
@import colors
|
||||||
$comment-header-background-color = $top-navigation-color
|
$comment-header-background-color = $top-navigation-color
|
||||||
$comment-header-background-color-darktheme = $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
$comment-border-color = #DDD
|
$comment-border-color = #DDD
|
||||||
|
|
||||||
.comment-container
|
.comment-container
|
||||||
|
margin: 0 0 1em 0
|
||||||
padding: 0 0 0 60px
|
padding: 0 0 0 60px
|
||||||
|
|
||||||
.avatar
|
.avatar
|
||||||
|
@ -83,7 +82,7 @@ $comment-border-color = #DDD
|
||||||
|
|
||||||
.edit, .delete, .score-container a, .nickname a
|
.edit, .delete, .score-container a, .nickname a
|
||||||
&:not(.inactive)
|
&:not(.inactive)
|
||||||
color: mix($main-color, $inactive-link-color)
|
color: mix($main-color, $inactive-tab-text-color)
|
||||||
|
|
||||||
i
|
i
|
||||||
margin-right: 0.3em
|
margin-right: 0.3em
|
||||||
|
@ -114,23 +113,8 @@ $comment-border-color = #DDD
|
||||||
.messages
|
.messages
|
||||||
margin: 1em 0
|
margin: 1em 0
|
||||||
|
|
||||||
.darktheme .comment-container .comment header
|
|
||||||
background: $comment-header-background-color-darktheme
|
|
||||||
nav.edit
|
|
||||||
ul
|
|
||||||
li
|
|
||||||
&.active
|
|
||||||
background: $window-color-darktheme
|
|
||||||
border-bottom: 1px solid $window-color-darktheme
|
|
||||||
.edit, .delete, .score-container a, .nickname a
|
|
||||||
&:not(.inactive)
|
|
||||||
color: mix($main-color, $inactive-link-color-darktheme)
|
|
||||||
|
|
||||||
.comment-content
|
.comment-content
|
||||||
p
|
|
||||||
word-wrap: normal
|
|
||||||
word-break: break-word
|
|
||||||
|
|
||||||
ul, ol
|
ul, ol
|
||||||
list-style-position: inside
|
list-style-position: inside
|
||||||
margin: 1em 0
|
margin: 1em 0
|
||||||
|
@ -140,7 +124,7 @@ $comment-border-color = #DDD
|
||||||
font-family: 'MS PGothic', 'MS Pゴシック', 'IPAMonaPGothic', 'Trebuchet MS', Verdana, Futura, Arial, Helvetica, sans-serif
|
font-family: 'MS PGothic', 'MS Pゴシック', 'IPAMonaPGothic', 'Trebuchet MS', Verdana, Futura, Arial, Helvetica, sans-serif
|
||||||
background: #fbfbfb
|
background: #fbfbfb
|
||||||
color: #111
|
color: #111
|
||||||
font-size: 1em
|
font-size: 12pt
|
||||||
line-height: 1
|
line-height: 1
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 4px
|
padding: 4px
|
||||||
|
|
|
@ -2,8 +2,3 @@
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
>li
|
|
||||||
margin-bottom: 1em
|
|
||||||
&:last-child
|
|
||||||
margin-bottom: 0
|
|
||||||
|
|
|
@ -1,25 +1,15 @@
|
||||||
@import colors
|
|
||||||
$comment-border-color = $top-navigation-color
|
|
||||||
$comment-border-color-darktheme = $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
.global-comment-list
|
.global-comment-list
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|
||||||
&>ul
|
&>ul
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
margin: 1em 0 0
|
margin: 1em 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
&>li
|
|
||||||
margin-top: 2em
|
|
||||||
padding-top: 2em
|
|
||||||
border-top: 3px solid $comment-border-color
|
|
||||||
&:first-child
|
|
||||||
margin-top: 0
|
|
||||||
padding-top: 0
|
|
||||||
border-top: none
|
|
||||||
|
|
||||||
@media (max-width: 700px)
|
@media (max-width: 700px)
|
||||||
|
&>li
|
||||||
|
margin-bottom: 5em
|
||||||
|
padding: 1vw
|
||||||
.post-thumbnail
|
.post-thumbnail
|
||||||
margin-bottom: 1em
|
margin-bottom: 1em
|
||||||
.thumbnail
|
.thumbnail
|
||||||
|
@ -29,6 +19,7 @@ $comment-border-color-darktheme = $top-navigation-color-darktheme
|
||||||
@media (min-width: 700px)
|
@media (min-width: 700px)
|
||||||
&>li
|
&>li
|
||||||
padding-left: 13em
|
padding-left: 13em
|
||||||
|
margin-bottom: 2em
|
||||||
.post-thumbnail
|
.post-thumbnail
|
||||||
float: left
|
float: left
|
||||||
margin: 0 0 1em -13em
|
margin: 0 0 1em -13em
|
||||||
|
@ -47,8 +38,3 @@ $comment-border-color-darktheme = $top-navigation-color-darktheme
|
||||||
|
|
||||||
.comments-container
|
.comments-container
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
.darktheme .global-comment-list
|
|
||||||
&>ul
|
|
||||||
&>li
|
|
||||||
border-top: 3px solid $comment-border-color-darktheme
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ form
|
||||||
.input li:first-child
|
.input li:first-child
|
||||||
padding-top: 0
|
padding-top: 0
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
|
|
||||||
form:not(.horizontal)
|
|
||||||
.hint
|
.hint
|
||||||
margin-top: 0.2em
|
margin-top: 0.2em
|
||||||
margin-bottom: 0
|
margin-bottom: 0
|
||||||
|
@ -26,31 +24,18 @@ form:not(.horizontal)
|
||||||
font-size: 80%
|
font-size: 80%
|
||||||
line-height: 120%
|
line-height: 120%
|
||||||
|
|
||||||
.darktheme form:not(.horizontal)
|
|
||||||
.hint
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
||||||
form.horizontal
|
form.horizontal
|
||||||
display: inline-block
|
display: inline-block
|
||||||
margin-bottom: 1em
|
margin-bottom: 1em
|
||||||
.input, .buttons, ul
|
.input, .buttons, ul
|
||||||
display: inline-block
|
display: inline-block
|
||||||
vertical-align: top
|
vertical-align: middle
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
input
|
input
|
||||||
vertical-align: top
|
vertical-align: middle
|
||||||
.buttons
|
.buttons
|
||||||
margin-right: 0.5em
|
margin-right: 0.5em
|
||||||
@media (max-width: 1000px)
|
|
||||||
display: block
|
|
||||||
.input, .buttons, ul
|
|
||||||
display: block
|
|
||||||
margin-top: 0.5em
|
|
||||||
&:first-child
|
|
||||||
margin-top: 0
|
|
||||||
.buttons
|
|
||||||
margin-right: 0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,48 +126,6 @@ input[type=checkbox]:focus + .checkbox:before
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Date and time inputs
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type=date],
|
|
||||||
input[type=time]
|
|
||||||
vertical-align: top
|
|
||||||
font-family: 'Droid Sans', sans-serif
|
|
||||||
font-size: 100%
|
|
||||||
padding: 0.2em 0.3em
|
|
||||||
box-sizing: border-box
|
|
||||||
border: 2px solid $input-enabled-border-color
|
|
||||||
background: $input-enabled-background-color
|
|
||||||
color: $input-enabled-text-color
|
|
||||||
box-shadow: none /* :-moz-submit-invalid on FF */
|
|
||||||
transition: border-color 0.1s linear, background-color 0.1s linear
|
|
||||||
|
|
||||||
&:disabled
|
|
||||||
border: 2px solid $input-disabled-border-color
|
|
||||||
background: $input-disabled-background-color
|
|
||||||
color: $input-disabled-text-color
|
|
||||||
|
|
||||||
&:focus
|
|
||||||
border-color: $main-color
|
|
||||||
|
|
||||||
&[readonly]
|
|
||||||
border: 2px solid $input-disabled-border-color
|
|
||||||
background: $input-disabled-background-color
|
|
||||||
color: $input-disabled-text-color
|
|
||||||
|
|
||||||
.darktheme
|
|
||||||
input[type=date],
|
|
||||||
input[type=time]
|
|
||||||
border: 2px solid darken($input-enabled-border-color, 75%)
|
|
||||||
background: darken($input-enabled-background-color, 75%)
|
|
||||||
color: $input-enabled-text-color-darktheme
|
|
||||||
&:disabled
|
|
||||||
background: darken($input-disabled-background-color, 75%)
|
|
||||||
&[readonly]
|
|
||||||
background: darken($input-disabled-background-color, 75%)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Regular inputs
|
* Regular inputs
|
||||||
*/
|
*/
|
||||||
|
@ -218,21 +161,6 @@ input[type=number]
|
||||||
background: $input-disabled-background-color
|
background: $input-disabled-background-color
|
||||||
color: $input-disabled-text-color
|
color: $input-disabled-text-color
|
||||||
|
|
||||||
.darktheme
|
|
||||||
select,
|
|
||||||
textarea,
|
|
||||||
input[type=text],
|
|
||||||
input[type=email],
|
|
||||||
input[type=password],
|
|
||||||
input[type=number]
|
|
||||||
border: 2px solid darken($input-enabled-border-color, 75%)
|
|
||||||
background: darken($input-enabled-background-color, 75%)
|
|
||||||
color: $input-enabled-text-color-darktheme
|
|
||||||
&:disabled
|
|
||||||
background: darken($input-disabled-background-color, 75%)
|
|
||||||
&[readonly]
|
|
||||||
background: darken($input-disabled-background-color, 75%)
|
|
||||||
|
|
||||||
input[readonly],
|
input[readonly],
|
||||||
input[readonly]+.radio,
|
input[readonly]+.radio,
|
||||||
input[readonly]+.checkbox,
|
input[readonly]+.checkbox,
|
||||||
|
@ -242,25 +170,13 @@ input:disabled
|
||||||
cursor: not-allowed
|
cursor: not-allowed
|
||||||
|
|
||||||
label.color
|
label.color
|
||||||
white-space: nowrap
|
|
||||||
position: relative
|
position: relative
|
||||||
display: flex
|
|
||||||
input[type=text]
|
input[type=text]
|
||||||
margin-right: 0.25em
|
|
||||||
width: auto
|
|
||||||
.preview
|
|
||||||
display: inline-block
|
|
||||||
text-align: center
|
text-align: center
|
||||||
padding: 0 0.5em
|
pointer-events: none
|
||||||
border: 2px solid black
|
input[type=color]
|
||||||
&:after
|
position: absolute
|
||||||
content: 'A'
|
opacity: 0
|
||||||
.background-preview
|
|
||||||
border-right: 0
|
|
||||||
color: transparent
|
|
||||||
.text-preview
|
|
||||||
border-left: 0
|
|
||||||
|
|
||||||
|
|
||||||
form.show-validation .input
|
form.show-validation .input
|
||||||
input:invalid
|
input:invalid
|
||||||
|
@ -271,9 +187,8 @@ form.show-validation .input
|
||||||
outline: 0
|
outline: 0
|
||||||
border: 2px solid $input-good-border-color
|
border: 2px solid $input-good-border-color
|
||||||
background: $input-good-background-color
|
background: $input-good-background-color
|
||||||
.darktheme form.show-validation .input
|
|
||||||
input:valid
|
|
||||||
background: darken($input-good-background-color, 75%)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buttons
|
* Buttons
|
||||||
|
@ -284,13 +199,10 @@ input[type=submit]
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
font-size: 100%
|
font-size: 100%
|
||||||
padding: 0.2em 0.7em
|
padding: 0.2em 0.7em
|
||||||
border-radius: 0
|
|
||||||
border: 2px solid $button-enabled-background-color
|
border: 2px solid $button-enabled-background-color
|
||||||
background: $button-enabled-background-color
|
background: $button-enabled-background-color
|
||||||
color: $button-enabled-text-color
|
color: $button-enabled-text-color
|
||||||
outline: 0 /* something on Chrome */
|
outline: 0 /* something on Chrome */
|
||||||
-moz-appearance: none
|
|
||||||
-webkit-appearance: none
|
|
||||||
|
|
||||||
&:disabled
|
&:disabled
|
||||||
cursor: default
|
cursor: default
|
||||||
|
@ -319,30 +231,25 @@ input::-moz-focus-inner
|
||||||
* File dropper
|
* File dropper
|
||||||
*/
|
*/
|
||||||
.file-dropper-holder
|
.file-dropper-holder
|
||||||
|
display: flex
|
||||||
|
flex-wrap: wrap
|
||||||
.file-dropper
|
.file-dropper
|
||||||
display: block
|
display: block
|
||||||
|
width: 100%
|
||||||
background: $window-color
|
background: $window-color
|
||||||
border: 3px dashed #eee
|
border: 3px dashed #eee
|
||||||
padding: 0.3em 0.5em
|
padding: 0.3em 0.5em
|
||||||
line-height: 140%
|
line-height: 140%
|
||||||
text-align: center
|
text-align: center
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
overflow: hidden
|
|
||||||
word-wrap: break-word
|
word-wrap: break-word
|
||||||
.url-holder
|
input
|
||||||
display: flex
|
|
||||||
margin-top: 0.5em
|
margin-top: 0.5em
|
||||||
input, button
|
width: auto
|
||||||
min-width: 0 /* firefox being sassy */
|
flex: 1
|
||||||
width: auto !important /* don't inherit anything weird */
|
button
|
||||||
input
|
margin-top: 0.5em
|
||||||
flex: 1
|
width: 8em
|
||||||
button
|
|
||||||
margin-left: 0.5em
|
|
||||||
|
|
||||||
.darktheme .file-dropper-holder
|
|
||||||
.file-dropper
|
|
||||||
background: $window-color-darktheme
|
|
||||||
|
|
||||||
input[type=file]:disabled+.file-dropper
|
input[type=file]:disabled+.file-dropper
|
||||||
cursor: default
|
cursor: default
|
||||||
|
@ -353,6 +260,8 @@ input[type=file]:focus+.file-dropper,
|
||||||
.file-dropper.active
|
.file-dropper.active
|
||||||
border-color: $main-color
|
border-color: $main-color
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.autocomplete
|
.autocomplete
|
||||||
position: absolute
|
position: absolute
|
||||||
z-index: 10
|
z-index: 10
|
||||||
|
@ -377,10 +286,6 @@ input[type=file]:focus+.file-dropper,
|
||||||
.disabled
|
.disabled
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
|
|
||||||
.darktheme .autocomplete
|
|
||||||
background: $window-color-darktheme
|
|
||||||
ul li .disabled
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
||||||
.anticomplete
|
.anticomplete
|
||||||
display: none
|
display: none
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
@import colors
|
@import colors
|
||||||
@import mixins
|
@import mixins
|
||||||
|
|
||||||
$active-tab-text-color = $text-color
|
|
||||||
$active-tab-text-color-darktheme = $text-color-darktheme
|
|
||||||
$inactive-tab-text-color = $inactive-link-color
|
|
||||||
$inactive-tab-text-color-darktheme = $inactive-link-color-darktheme
|
|
||||||
|
|
||||||
/* latin */
|
/* latin */
|
||||||
@font-face
|
@font-face
|
||||||
font-family: 'Open Sans';
|
font-family: 'Open Sans';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local('Open Sans'), local('OpenSans'), url(../fonts/open_sans.woff2) format('woff2');
|
src: local('Open Sans'), local('OpenSans'), url(/fonts/open_sans.woff2) format('woff2');
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
|
|
||||||
/* make <body> cover entire viewport */
|
/* make <body> cover entire viewport */
|
||||||
|
@ -26,32 +21,19 @@ body
|
||||||
margin: 0
|
margin: 0
|
||||||
color: $text-color
|
color: $text-color
|
||||||
font-family: 'Open Sans', sans-serif
|
font-family: 'Open Sans', sans-serif
|
||||||
font-size: 1em
|
font-size: 12pt
|
||||||
line-height: 1.4
|
line-height: 18pt
|
||||||
@media (max-width: 800px)
|
@media (max-width: 800px)
|
||||||
font-size: 0.875em
|
font-size: 10pt
|
||||||
|
line-height: 15pt
|
||||||
@media (max-width: 1200px)
|
@media (max-width: 1200px)
|
||||||
font-size: 0.95em
|
font-size: 11pt
|
||||||
|
line-height: 16.5pt
|
||||||
body.darktheme
|
|
||||||
color: $text-color-darktheme
|
|
||||||
background: $window-color-darktheme
|
|
||||||
|
|
||||||
h1, h2, h3
|
h1, h2, h3
|
||||||
font-weight: normal
|
font-weight: normal
|
||||||
margin-bottom: 1em
|
margin-bottom: 1em
|
||||||
|
|
||||||
h1
|
|
||||||
font-size: 2em
|
|
||||||
|
|
||||||
h2
|
|
||||||
font-size: 1.5em
|
|
||||||
|
|
||||||
p,
|
|
||||||
ol,
|
|
||||||
ul
|
|
||||||
margin: 1em 0
|
|
||||||
|
|
||||||
th
|
th
|
||||||
font-weight: normal
|
font-weight: normal
|
||||||
|
|
||||||
|
@ -71,11 +53,6 @@ a
|
||||||
.vim-nav-hint
|
.vim-nav-hint
|
||||||
position: absolute
|
position: absolute
|
||||||
visibility: hidden
|
visibility: hidden
|
||||||
.darktheme a
|
|
||||||
&.inactive
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
&.icon
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
||||||
a.append, span.append
|
a.append, span.append
|
||||||
margin-left: 1em
|
margin-left: 1em
|
||||||
|
@ -84,10 +61,8 @@ form .fa-question-circle-o
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
|
|
||||||
#content-holder
|
#content-holder
|
||||||
padding: 1.5em
|
padding: 1.5vw
|
||||||
text-align: center
|
text-align: center
|
||||||
@media (max-width: 1000px)
|
|
||||||
padding: 1em
|
|
||||||
>.content-wrapper
|
>.content-wrapper
|
||||||
box-sizing: border-box /* make max-width: 100% on this element include padding */
|
box-sizing: border-box /* make max-width: 100% on this element include padding */
|
||||||
text-align: left
|
text-align: left
|
||||||
|
@ -95,30 +70,9 @@ form .fa-question-circle-o
|
||||||
margin: 0 auto
|
margin: 0 auto
|
||||||
>*:first-child, form h1
|
>*:first-child, form h1
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
nav.buttons
|
|
||||||
ul
|
|
||||||
display: block
|
|
||||||
max-width: 100%
|
|
||||||
white-space: nowrap
|
|
||||||
overflow-x: auto
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
height: 6px
|
|
||||||
background-color: $scrollbar-bg-color
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
background-color: $scrollbar-thumb-color
|
|
||||||
>.content-wrapper:not(.transparent)
|
>.content-wrapper:not(.transparent)
|
||||||
background: $top-navigation-color
|
background: $top-navigation-color
|
||||||
padding: 1.8em
|
padding: 2vw
|
||||||
@media (max-width: 1000px)
|
|
||||||
padding: 1.5em
|
|
||||||
.content,
|
|
||||||
.content .subcontent
|
|
||||||
>*:last-child
|
|
||||||
margin-bottom: 0
|
|
||||||
|
|
||||||
.darktheme #content-holder
|
|
||||||
>.content-wrapper:not(.transparent)
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
hr
|
hr
|
||||||
border: 0
|
border: 0
|
||||||
|
@ -126,9 +80,6 @@ hr
|
||||||
margin: 1em 0
|
margin: 1em 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
.darktheme hr
|
|
||||||
border-top: 1px solid darken($line-color, 25%)
|
|
||||||
|
|
||||||
nav
|
nav
|
||||||
ul
|
ul
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
|
@ -174,39 +125,6 @@ nav
|
||||||
li
|
li
|
||||||
display: inline-block
|
display: inline-block
|
||||||
float: left
|
float: left
|
||||||
a
|
|
||||||
padding: 0 1.5em
|
|
||||||
#mobile-navigation-toggle
|
|
||||||
display: none
|
|
||||||
width: 100%
|
|
||||||
padding: 0 1em
|
|
||||||
line-height: 2.3em
|
|
||||||
font-family: inherit
|
|
||||||
border: none
|
|
||||||
background: none
|
|
||||||
color: $active-tab-text-color
|
|
||||||
.site-name
|
|
||||||
display: block
|
|
||||||
float: left
|
|
||||||
max-width: 50vw
|
|
||||||
overflow: hidden
|
|
||||||
text-overflow: ellipsis
|
|
||||||
.toggle-icon
|
|
||||||
display: block
|
|
||||||
float: right
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
text-align: left
|
|
||||||
li
|
|
||||||
display: none
|
|
||||||
float: none
|
|
||||||
a
|
|
||||||
display: block
|
|
||||||
padding: 0 1em
|
|
||||||
#mobile-navigation-toggle
|
|
||||||
display: block
|
|
||||||
&.opened
|
|
||||||
li
|
|
||||||
display: block
|
|
||||||
ul li[data-name=account],
|
ul li[data-name=account],
|
||||||
ul li[data-name=register],
|
ul li[data-name=register],
|
||||||
ul li[data-name=login],
|
ul li[data-name=login],
|
||||||
|
@ -223,26 +141,6 @@ nav
|
||||||
margin-right: 0.6em
|
margin-right: 0.6em
|
||||||
margin-left: calc(0.6em - 1.2em)
|
margin-left: calc(0.6em - 1.2em)
|
||||||
float: left
|
float: left
|
||||||
@media (max-width: 1000px)
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.darktheme nav
|
|
||||||
&.buttons
|
|
||||||
ul
|
|
||||||
li:not(.active) a
|
|
||||||
color: $inactive-tab-text-color-darktheme
|
|
||||||
li:hover:not(.active) a
|
|
||||||
color: $active-tab-text-color-darktheme
|
|
||||||
li.active a
|
|
||||||
background: $active-tab-background-color-darktheme
|
|
||||||
color: $active-tab-text-color-darktheme
|
|
||||||
:focus
|
|
||||||
background: $focused-tab-background-color-darktheme
|
|
||||||
&#top-navigation
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
ul
|
|
||||||
#mobile-navigation-toggle
|
|
||||||
color: $text-color-darktheme
|
|
||||||
|
|
||||||
a .access-key
|
a .access-key
|
||||||
text-decoration: underline
|
text-decoration: underline
|
||||||
|
@ -268,18 +166,6 @@ a .access-key
|
||||||
border: 1px solid $message-success-border-color
|
border: 1px solid $message-success-border-color
|
||||||
background: $message-success-background-color
|
background: $message-success-background-color
|
||||||
|
|
||||||
.darktheme .messages
|
|
||||||
.message
|
|
||||||
&.info
|
|
||||||
border: 1px solid darken($message-info-border-color, 30%)
|
|
||||||
background: darken($message-info-background-color, 60%)
|
|
||||||
&.error
|
|
||||||
border: 1px solid darken($message-error-border-color, 30%)
|
|
||||||
background: darken($message-error-background-color, 60%)
|
|
||||||
&.success
|
|
||||||
border: 1px solid darken($message-success-border-color, 30%)
|
|
||||||
background: darken($message-success-background-color, 80%)
|
|
||||||
|
|
||||||
.thumbnail
|
.thumbnail
|
||||||
/*background-image: attr(data-src url)*/ /* not available yet */
|
/*background-image: attr(data-src url)*/ /* not available yet */
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
|
@ -290,14 +176,9 @@ a .access-key
|
||||||
width: 20px
|
width: 20px
|
||||||
height: 20px
|
height: 20px
|
||||||
&.empty
|
&.empty
|
||||||
background-image:
|
background-image: url('/img/transparency_grid.png')
|
||||||
linear-gradient(45deg, $transparency-grid-square-color 25%, transparent 25%),
|
|
||||||
linear-gradient(-45deg, $transparency-grid-square-color 25%, transparent 25%),
|
|
||||||
linear-gradient(45deg, transparent 75%, $transparency-grid-square-color 75%),
|
|
||||||
linear-gradient(-45deg, transparent 75%, $transparency-grid-square-color 75%)
|
|
||||||
background-position: 0 0, 0 10px, 10px -10px, -10px 0px
|
|
||||||
background-repeat: repeat
|
background-repeat: repeat
|
||||||
background-size: 20px 20px
|
background-size: initial
|
||||||
img
|
img
|
||||||
opacity: 0
|
opacity: 0
|
||||||
width: 100%
|
width: 100%
|
||||||
|
@ -313,14 +194,6 @@ a .access-key
|
||||||
margin-top: 0 !important
|
margin-top: 0 !important
|
||||||
margin-bottom: 0 !important
|
margin-bottom: 0 !important
|
||||||
|
|
||||||
.table-wrap
|
|
||||||
overflow-x: auto
|
|
||||||
&::-webkit-scrollbar
|
|
||||||
height: 6px
|
|
||||||
background-color: $scrollbar-bg-color
|
|
||||||
&::-webkit-scrollbar-thumb
|
|
||||||
background-color: $scrollbar-thumb-color
|
|
||||||
|
|
||||||
/* hack to prevent text from being copied */
|
/* hack to prevent text from being copied */
|
||||||
[data-pseudo-content]:before {
|
[data-pseudo-content]:before {
|
||||||
content: attr(data-pseudo-content)
|
content: attr(data-pseudo-content)
|
||||||
|
|
|
@ -16,17 +16,9 @@
|
||||||
color: mix($text-color, $inactive-link-color)
|
color: mix($text-color, $inactive-link-color)
|
||||||
font-size: 120%
|
font-size: 120%
|
||||||
i
|
i
|
||||||
font-size: 1em
|
font-size: 12pt
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
float: right
|
float: right
|
||||||
line-height: 2em
|
line-height: 2em
|
||||||
.expander-content
|
.expander-content
|
||||||
padding: 0.5em 0.5em 2em 0.5em
|
padding: 0.5em 0.5em 2em 0.5em
|
||||||
|
|
||||||
.darktheme .expander
|
|
||||||
header
|
|
||||||
background: $active-tab-background-color-darktheme
|
|
||||||
a
|
|
||||||
color: mix($text-color-darktheme, $inactive-link-color-darktheme)
|
|
||||||
i
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
font-size: 1.6em
|
font-size: 1.6em
|
||||||
&:first-child
|
&:first-child
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
@media (max-width: 1000px)
|
|
||||||
margin-top: 1.5em
|
|
||||||
&:first-child
|
|
||||||
margin-top: 0
|
|
||||||
nav
|
nav
|
||||||
ul
|
ul
|
||||||
margin: 0 auto
|
margin: 0 auto
|
||||||
|
|
|
@ -6,16 +6,13 @@
|
||||||
margin-bottom: 1em
|
margin-bottom: 1em
|
||||||
h1
|
h1
|
||||||
line-height: initial
|
line-height: initial
|
||||||
font-size: 2.5em
|
font-size: 30pt
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
.messages
|
.message
|
||||||
text-align: center
|
margin-bottom: 2em
|
||||||
.message
|
|
||||||
margin: 0 auto 2em auto
|
|
||||||
|
|
||||||
form
|
form
|
||||||
display: inline-block
|
|
||||||
width: auto
|
width: auto
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
margin: 0 0 2em 0
|
margin: 0 0 2em 0
|
||||||
|
@ -34,8 +31,6 @@
|
||||||
display: flex
|
display: flex
|
||||||
align-items: center
|
align-items: center
|
||||||
justify-content: center
|
justify-content: center
|
||||||
&:empty
|
|
||||||
margin-bottom: 0
|
|
||||||
|
|
||||||
nav
|
nav
|
||||||
a
|
a
|
||||||
|
@ -55,8 +50,6 @@
|
||||||
li
|
li
|
||||||
display: inline
|
display: inline
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
@media (max-width: 800px)
|
|
||||||
display: block
|
|
||||||
.sep
|
.sep
|
||||||
word-spacing: 1.1em
|
word-spacing: 1.1em
|
||||||
background-repeat: no-repeat
|
background-repeat: no-repeat
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
.page
|
.page
|
||||||
position: relative
|
position: relative
|
||||||
.page-header
|
.page-header
|
||||||
margin: 0.5em 0
|
margin: 0.5em 0.5em 0.5em 0
|
||||||
position: relative
|
position: relative
|
||||||
&:before
|
&:before
|
||||||
display: block
|
display: block
|
||||||
|
@ -22,14 +22,6 @@
|
||||||
z-index: 1
|
z-index: 1
|
||||||
span
|
span
|
||||||
position: relative
|
position: relative
|
||||||
background: $window-color
|
background: white
|
||||||
padding: 0 1em
|
padding: 0 1em
|
||||||
z-index: 2
|
z-index: 2
|
||||||
|
|
||||||
.darktheme .pager
|
|
||||||
.page
|
|
||||||
.page-header
|
|
||||||
&:before
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
span
|
|
||||||
background: $window-color-darktheme
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#password-reset
|
|
||||||
max-width: 30em
|
|
|
@ -1,29 +0,0 @@
|
||||||
@import colors
|
|
||||||
|
|
||||||
.content-wrapper.pool-categories
|
|
||||||
width: 100%
|
|
||||||
max-width: 45em
|
|
||||||
table
|
|
||||||
border-spacing: 0
|
|
||||||
width: 100%
|
|
||||||
tr.default td
|
|
||||||
background: $default-pool-category-background-color
|
|
||||||
td, th
|
|
||||||
padding: .4em
|
|
||||||
&.color
|
|
||||||
input[type=text]
|
|
||||||
width: 8em
|
|
||||||
&.usages
|
|
||||||
text-align: center
|
|
||||||
&.remove, &.set-default
|
|
||||||
white-space: pre
|
|
||||||
th
|
|
||||||
white-space: nowrap
|
|
||||||
&:first-child
|
|
||||||
padding-left: 0
|
|
||||||
&:last-child
|
|
||||||
padding-right: 0
|
|
||||||
tfoot
|
|
||||||
display: none
|
|
||||||
form
|
|
||||||
width: auto
|
|
|
@ -1,58 +0,0 @@
|
||||||
@import colors
|
|
||||||
|
|
||||||
div.pool-input
|
|
||||||
position: relative
|
|
||||||
|
|
||||||
.main-control
|
|
||||||
display: flex
|
|
||||||
input
|
|
||||||
flex: 5
|
|
||||||
button
|
|
||||||
flex: 1
|
|
||||||
margin: 0 0 0 0.5em
|
|
||||||
|
|
||||||
|
|
||||||
ul.compact-pools
|
|
||||||
width: 100%
|
|
||||||
margin: 0.5em 0 0 0
|
|
||||||
padding: 0
|
|
||||||
li
|
|
||||||
margin: 0
|
|
||||||
width: 100%
|
|
||||||
line-height: 140%
|
|
||||||
white-space: nowrap
|
|
||||||
overflow: hidden
|
|
||||||
text-overflow: ellipsis
|
|
||||||
transition: background-color 0.5s linear
|
|
||||||
a
|
|
||||||
display: inline
|
|
||||||
a:focus
|
|
||||||
outline: 0
|
|
||||||
box-shadow: inset 0 0 0 2px $main-color
|
|
||||||
&.implication
|
|
||||||
background: $implied-pool-background-color
|
|
||||||
color: $implied-pool-text-color
|
|
||||||
&.new
|
|
||||||
background: $new-pool-background-color
|
|
||||||
color: $new-pool-text-color
|
|
||||||
&.duplicate
|
|
||||||
background: $duplicate-pool-background-color
|
|
||||||
color: $duplicate-pool-text-color
|
|
||||||
i
|
|
||||||
padding-right: 0.4em
|
|
||||||
|
|
||||||
div.pool-input, ul.compact-pools
|
|
||||||
.pool-usages, .pool-weight, .remove-pool
|
|
||||||
color: $inactive-link-color
|
|
||||||
unselectable()
|
|
||||||
.pool-usages, .pool-weight
|
|
||||||
font-size: 90%
|
|
||||||
.pool-usages, .pool-weight
|
|
||||||
margin-left: 0.7em
|
|
||||||
.remove-pool
|
|
||||||
margin-right: 0.5em
|
|
||||||
|
|
||||||
.darktheme
|
|
||||||
div.pool-input, ul.compact-pools
|
|
||||||
.pool-usages, .pool-weight, .remove-pool
|
|
||||||
color: $inactive-link-color-darktheme
|
|
|
@ -1,63 +0,0 @@
|
||||||
@import colors
|
|
||||||
|
|
||||||
.pool-list
|
|
||||||
table
|
|
||||||
width: 100%
|
|
||||||
border-spacing: 0
|
|
||||||
text-align: left
|
|
||||||
line-height: 1.3em
|
|
||||||
tr:hover td
|
|
||||||
background: $top-navigation-color
|
|
||||||
th, td
|
|
||||||
padding: 0.1em 0.5em
|
|
||||||
th
|
|
||||||
white-space: nowrap
|
|
||||||
background: $top-navigation-color
|
|
||||||
.names
|
|
||||||
width: 84%
|
|
||||||
.post-count
|
|
||||||
text-align: center
|
|
||||||
width: 8%
|
|
||||||
.creation-time
|
|
||||||
text-align: center
|
|
||||||
width: 8%
|
|
||||||
white-space: pre
|
|
||||||
ul
|
|
||||||
list-style-type: none
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
display: inline
|
|
||||||
li
|
|
||||||
padding: 0
|
|
||||||
display: inline
|
|
||||||
&:not(:last-child):after
|
|
||||||
content: ', '
|
|
||||||
@media (max-width: 800px)
|
|
||||||
.posts
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.darktheme .pool-list
|
|
||||||
table
|
|
||||||
tr:hover td
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
th
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
.pool-list-header
|
|
||||||
label
|
|
||||||
display: none !important
|
|
||||||
text-align: left
|
|
||||||
form
|
|
||||||
width: auto
|
|
||||||
input[name=search-text]
|
|
||||||
width: 25em
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
width: 100%
|
|
||||||
.append
|
|
||||||
vertical-align: middle
|
|
||||||
font-size: 0.95em
|
|
||||||
color: $inactive-link-color
|
|
||||||
|
|
||||||
.darktheme .pool-list-header
|
|
||||||
.append
|
|
||||||
color: $inactive-link-color-darktheme
|
|
|
@ -1,33 +0,0 @@
|
||||||
#pool
|
|
||||||
width: 100%
|
|
||||||
max-width: 40em
|
|
||||||
h1
|
|
||||||
word-break: break-all
|
|
||||||
line-height: 130%
|
|
||||||
margin-top: 0
|
|
||||||
form
|
|
||||||
width: 100%
|
|
||||||
.pool-edit
|
|
||||||
textarea
|
|
||||||
height: 10em
|
|
||||||
.pool-summary
|
|
||||||
section
|
|
||||||
&.description
|
|
||||||
margin: 1.5em 0 0 0
|
|
||||||
&.details
|
|
||||||
vertical-align: top
|
|
||||||
padding-right: 0.5em
|
|
||||||
ul
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
list-style-type: none
|
|
||||||
li
|
|
||||||
display: inline
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
li:not(:last-of-type):after
|
|
||||||
content: ', '
|
|
||||||
ul:empty:after
|
|
||||||
content: '(none)'
|
|
||||||
section
|
|
||||||
margin-bottom: 1em
|
|
|
@ -1,14 +1,6 @@
|
||||||
@import colors
|
|
||||||
|
|
||||||
.post-container
|
.post-container
|
||||||
.post-content.transparency-grid img
|
.post-content.transparency-grid img
|
||||||
background-image:
|
background: url('/img/transparency_grid.png')
|
||||||
linear-gradient(45deg, $transparency-grid-square-color 25%, transparent 25%),
|
|
||||||
linear-gradient(-45deg, $transparency-grid-square-color 25%, transparent 25%),
|
|
||||||
linear-gradient(45deg, transparent 75%, $transparency-grid-square-color 75%),
|
|
||||||
linear-gradient(-45deg, transparent 75%, $transparency-grid-square-color 75%)
|
|
||||||
background-size: 20px 20px
|
|
||||||
background-position: 0 0, 0 10px, 10px -10px, -10px 0px
|
|
||||||
|
|
||||||
text-align: center
|
text-align: center
|
||||||
.post-content
|
.post-content
|
||||||
|
@ -24,6 +16,3 @@
|
||||||
bottom: 0
|
bottom: 0
|
||||||
width: 100%
|
width: 100%
|
||||||
height: 100%
|
height: 100%
|
||||||
|
|
||||||
img
|
|
||||||
image-orientation: from-image
|
|
||||||
|
|
|
@ -54,96 +54,39 @@
|
||||||
.icon:not(:first-of-type)
|
.icon:not(:first-of-type)
|
||||||
margin-left: 1em
|
margin-left: 1em
|
||||||
|
|
||||||
.edit-overlay
|
.masstag
|
||||||
position: absolute
|
position: absolute
|
||||||
top: 0.5em
|
top: 0.5em
|
||||||
left: 0.5em
|
left: 0.5em
|
||||||
|
display: inline-block
|
||||||
.tag-flipper
|
padding: 0.5em
|
||||||
|
box-sizing: border-box
|
||||||
|
border: 0
|
||||||
|
&:after
|
||||||
display: inline-block
|
display: inline-block
|
||||||
padding: 0.5em
|
width: 1em
|
||||||
box-sizing: border-box
|
height: 1em
|
||||||
border: 0
|
|
||||||
&:after
|
|
||||||
display: inline-block
|
|
||||||
width: 1em
|
|
||||||
height: 1em
|
|
||||||
text-align: center
|
|
||||||
line-height: 1em
|
|
||||||
font-size: 2.2em
|
|
||||||
&.tagged
|
|
||||||
background: rgba(0, 230, 0, 0.7)
|
|
||||||
&:after
|
|
||||||
color: white
|
|
||||||
content: '-'
|
|
||||||
&:not(.tagged)
|
|
||||||
background: rgba(255, 0, 0, 0.7)
|
|
||||||
&:after
|
|
||||||
color: white
|
|
||||||
content: '+'
|
|
||||||
&[data-disabled]
|
|
||||||
background: rgba(200, 200, 200, 0.7)
|
|
||||||
|
|
||||||
.safety-flipper a
|
|
||||||
display: inline-block
|
|
||||||
margin: 0.1em
|
|
||||||
box-sizing: border-box
|
|
||||||
border: 0
|
|
||||||
display: inline-block
|
|
||||||
width: 1.2em
|
|
||||||
height: 1.2em
|
|
||||||
text-align: center
|
text-align: center
|
||||||
line-height: 1em
|
line-height: 1em
|
||||||
font-size: 1.6em
|
font-size: 20pt
|
||||||
border: 3px solid
|
&.tagged
|
||||||
&.safety-safe
|
background: rgba(0, 230, 0, 0.7)
|
||||||
background-color: darken($safety-safe, 5%)
|
|
||||||
border-color: @background-color
|
|
||||||
&:not(.active)
|
|
||||||
background-color: alpha(@background-color, 0.3)
|
|
||||||
&.safety-sketchy
|
|
||||||
background-color: $safety-sketchy
|
|
||||||
border-color: @background-color
|
|
||||||
&:not(.active)
|
|
||||||
background-color: alpha(@background-color, 0.3)
|
|
||||||
&.safety-unsafe
|
|
||||||
background-color: $safety-unsafe
|
|
||||||
border-color: @background-color
|
|
||||||
&:not(.active)
|
|
||||||
background-color: alpha(@background-color, 0.3)
|
|
||||||
&[data-disabled]
|
|
||||||
background: rgba(200, 200, 200, 0.7)
|
|
||||||
|
|
||||||
.delete-flipper
|
|
||||||
display: inline-block
|
|
||||||
padding: 0.5em
|
|
||||||
box-sizing: border-box
|
|
||||||
border: 0
|
|
||||||
&:after
|
&:after
|
||||||
display: inline-block
|
color: white
|
||||||
width: 1em
|
content: '-'
|
||||||
height: 1em
|
&:not(.tagged)
|
||||||
text-align: center
|
background: rgba(255, 0, 0, 0.7)
|
||||||
line-height: 1em
|
&:after
|
||||||
font-size: 2.2em
|
color: white
|
||||||
&.delete
|
content: '+'
|
||||||
background: rgba(255, 0, 0, 0.7)
|
&[data-disabled]
|
||||||
&:after
|
background: rgba(200, 200, 200, 0.7)
|
||||||
color: white
|
|
||||||
font-family: FontAwesome;
|
|
||||||
content: "\f1f8"; // fa-trash
|
|
||||||
&:not(.delete)
|
|
||||||
background: rgba(200, 200, 200, 0.7)
|
|
||||||
&:after
|
|
||||||
color: white
|
|
||||||
content: '-'
|
|
||||||
|
|
||||||
.thumbnail
|
.thumbnail
|
||||||
|
background-position: 50% 30%
|
||||||
width: 100%
|
width: 100%
|
||||||
height: 100%
|
height: 100%
|
||||||
outline-offset: -3px
|
outline-offset: -3px
|
||||||
&:not(.empty)
|
|
||||||
background-position: 50% 30%
|
|
||||||
|
|
||||||
.thumbnail-wrapper.no-tags
|
.thumbnail-wrapper.no-tags
|
||||||
.thumbnail
|
.thumbnail
|
||||||
|
@ -158,22 +101,6 @@
|
||||||
.thumbnail
|
.thumbnail
|
||||||
outline: 4px solid $main-color !important
|
outline: 4px solid $main-color !important
|
||||||
|
|
||||||
.post-flow
|
|
||||||
ul
|
|
||||||
li
|
|
||||||
min-width: inherit
|
|
||||||
width: inherit
|
|
||||||
&:not(.flexbox-dummy)
|
|
||||||
height: 14vw
|
|
||||||
.thumbnail
|
|
||||||
outline-offset: -1px
|
|
||||||
.thumbnail-wrapper.no-tags
|
|
||||||
.thumbnail
|
|
||||||
outline: 2px solid $post-thumbnail-no-tags-border-color
|
|
||||||
&:hover a, a:active, a:focus
|
|
||||||
.thumbnail
|
|
||||||
outline: 2px solid $main-color !important
|
|
||||||
|
|
||||||
.post-list-header
|
.post-list-header
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
text-align: left
|
text-align: left
|
||||||
|
@ -185,75 +112,30 @@
|
||||||
margin-bottom: 0.75em
|
margin-bottom: 0.75em
|
||||||
*
|
*
|
||||||
vertical-align: top
|
vertical-align: top
|
||||||
@media (max-width: 1000px)
|
|
||||||
display: block
|
|
||||||
&.bulk-edit-tags:not(.opened), &.bulk-edit-safety:not(.opened)
|
|
||||||
float: left
|
|
||||||
margin-right: 1em
|
|
||||||
input
|
input
|
||||||
margin-bottom: 0.25em
|
margin-bottom: 0.25em
|
||||||
margin-right: 0.25em
|
margin-right: 0.25em
|
||||||
input[name=search-text]
|
input[name=search-text]
|
||||||
width: 25em
|
width: 25em
|
||||||
@media (max-width: 1000px)
|
input[name=masstag]
|
||||||
display: block
|
width: 12em
|
||||||
width: 100%
|
.masstag-hint, .open-masstag
|
||||||
margin-bottom: 0.5em
|
margin-right: 1em
|
||||||
.append
|
.append
|
||||||
vertical-align: middle
|
|
||||||
font-size: 0.95em
|
font-size: 0.95em
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
.bulk-edit
|
.masstag
|
||||||
&:not(.opened)
|
&:not(.active)
|
||||||
.close
|
|
||||||
display: none
|
|
||||||
&.opened
|
|
||||||
.open
|
|
||||||
display: none
|
|
||||||
&.hidden
|
|
||||||
display: none
|
|
||||||
.bulk-edit-tags
|
|
||||||
&.opened
|
|
||||||
.hint
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
display: block
|
|
||||||
margin-bottom: 0.5em
|
|
||||||
&:not(.opened)
|
|
||||||
[type=text],
|
[type=text],
|
||||||
.start
|
.start-tagging,
|
||||||
|
.stop-tagging
|
||||||
display: none
|
display: none
|
||||||
.hint
|
.masstag-hint
|
||||||
display: none
|
display: none
|
||||||
input[name=tag]
|
&.active
|
||||||
width: 24em
|
.open-masstag
|
||||||
@media (max-width: 1000px)
|
|
||||||
display: block
|
|
||||||
width: 100%
|
|
||||||
margin-bottom: 0.5em
|
|
||||||
.append
|
|
||||||
&.open,
|
|
||||||
&.hint
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
margin-left: 0
|
|
||||||
.hint
|
|
||||||
margin-right: 1em
|
|
||||||
.bulk-edit-safety
|
|
||||||
.append
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
margin-left: 0
|
|
||||||
.bulk-edit-delete
|
|
||||||
&.opened
|
|
||||||
.start
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
margin-left: 0
|
|
||||||
&:not(.opened)
|
|
||||||
.start
|
|
||||||
display: none
|
display: none
|
||||||
.append.open
|
|
||||||
@media (max-width: 1000px)
|
|
||||||
margin-left: 0
|
|
||||||
.start
|
|
||||||
margin-left: 1em
|
|
||||||
.safety
|
.safety
|
||||||
margin-right: 0.25em
|
margin-right: 0.25em
|
||||||
&.safety-safe
|
&.safety-safe
|
||||||
|
|
|
@ -7,66 +7,49 @@
|
||||||
|
|
||||||
>.sidebar
|
>.sidebar
|
||||||
margin-right: 1em
|
margin-right: 1em
|
||||||
min-width: 21em
|
min-width: 20em
|
||||||
max-width: 21em
|
max-width: 20em
|
||||||
line-height: 160%
|
line-height: 160%
|
||||||
|
|
||||||
a:active
|
a:active
|
||||||
border: 0
|
border: 0
|
||||||
outline: 0
|
outline: 0
|
||||||
|
|
||||||
>.sidebar>nav.buttons, >.content nav.buttons
|
nav.buttons
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
display: flex
|
display: flex
|
||||||
flex-wrap: wrap
|
flex-wrap: wrap
|
||||||
article
|
article
|
||||||
flex: 1 0 33%
|
flex: 1 0 33%
|
||||||
a
|
a
|
||||||
display: inline-block
|
display: inline-block
|
||||||
width: 100%
|
width: 100%
|
||||||
padding: 0.3em 0
|
padding: 0.3em 0
|
||||||
|
text-align: center
|
||||||
|
vertical-align: middle
|
||||||
|
transition: background 0.2s linear
|
||||||
|
&:not(.inactive):hover
|
||||||
|
background: lighten($main-color, 90%)
|
||||||
|
i
|
||||||
|
font-size: 140%
|
||||||
text-align: center
|
text-align: center
|
||||||
vertical-align: middle
|
|
||||||
transition: background 0.2s linear, box-shadow 0.2s linear
|
|
||||||
&:not(.inactive):hover
|
|
||||||
background: lighten($main-color, 90%)
|
|
||||||
i
|
|
||||||
font-size: 140%
|
|
||||||
text-align: center
|
|
||||||
@media (max-width: 800px)
|
|
||||||
margin-top: 0.6em
|
|
||||||
margin-bottom: 0.6em
|
|
||||||
|
|
||||||
>.content
|
>.content
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
.post-container
|
.post-container
|
||||||
margin-bottom: 0.6em
|
margin-bottom: 2em
|
||||||
|
|
||||||
.post-content
|
.post-content
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
.after-mobile-controls
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
.darktheme .post-view
|
|
||||||
>.sidebar, >.content
|
|
||||||
nav.buttons
|
|
||||||
article
|
|
||||||
a:not(.inactive):hover
|
|
||||||
background: unset
|
|
||||||
box-shadow: inset 0 0 0 0.3em $main-color
|
|
||||||
|
|
||||||
@media (max-width: 800px)
|
@media (max-width: 800px)
|
||||||
.post-view
|
.post-view
|
||||||
flex-wrap: wrap
|
flex-wrap: wrap
|
||||||
>.after-mobile-controls
|
|
||||||
order: 3
|
|
||||||
>.sidebar
|
>.sidebar
|
||||||
order: 2
|
order: 2
|
||||||
min-width: 100%
|
min-width: 100%
|
||||||
max-width: 0
|
max-width: 0
|
||||||
margin-right: 0
|
|
||||||
>.content
|
>.content
|
||||||
order: 1
|
order: 1
|
||||||
|
|
||||||
|
@ -119,6 +102,7 @@
|
||||||
h1
|
h1
|
||||||
margin-bottom: 0.5em
|
margin-bottom: 0.5em
|
||||||
.thumbnail
|
.thumbnail
|
||||||
|
background-position: 50% 30%
|
||||||
width: 4em
|
width: 4em
|
||||||
height: 3em
|
height: 3em
|
||||||
li
|
li
|
||||||
|
@ -146,24 +130,10 @@
|
||||||
display: inline-block
|
display: inline-block
|
||||||
|
|
||||||
.management
|
.management
|
||||||
ul
|
li
|
||||||
list-style-type: none
|
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
|
||||||
li
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
.post-source
|
label
|
||||||
textarea
|
|
||||||
white-space: pre
|
|
||||||
overflow-wrap: normal
|
|
||||||
overflow-x: scroll
|
|
||||||
|
|
||||||
form
|
|
||||||
width: auto
|
|
||||||
|
|
||||||
label:not(.file-dropper)
|
|
||||||
margin-bottom: 0.3em
|
margin-bottom: 0.3em
|
||||||
display: block
|
display: block
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
@import colors
|
@import colors
|
||||||
$upload-header-background-color = $top-navigation-color
|
$upload-header-background-color = $top-navigation-color
|
||||||
$upload-header-background-color-darktheme = $top-navigation-color-darktheme
|
|
||||||
$upload-border-color = #DDD
|
$upload-border-color = #DDD
|
||||||
$cancel-button-color = tomato
|
$cancel-button-color = tomato
|
||||||
|
|
||||||
|
@ -13,12 +12,8 @@ $cancel-button-color = tomato
|
||||||
|
|
||||||
&.inactive input[type=submit],
|
&.inactive input[type=submit],
|
||||||
&.inactive .skip-duplicates
|
&.inactive .skip-duplicates
|
||||||
&.inactive .always-upload-similar
|
|
||||||
&.inactive .pause-remain-on-error
|
|
||||||
&.uploading input[type=submit],
|
&.uploading input[type=submit],
|
||||||
&.uploading .skip-duplicates,
|
&.uploading .skip-duplicates,
|
||||||
&.uploading .always-upload-similar
|
|
||||||
&.uploading .pause-remain-on-error
|
|
||||||
&:not(.uploading) .cancel
|
&:not(.uploading) .cancel
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
|
@ -27,8 +22,6 @@ $cancel-button-color = tomato
|
||||||
.file-dropper
|
.file-dropper
|
||||||
font-size: 150%
|
font-size: 150%
|
||||||
padding: 2em
|
padding: 2em
|
||||||
small
|
|
||||||
font-size: 60%
|
|
||||||
|
|
||||||
input[type=submit]
|
input[type=submit]
|
||||||
margin-top: 1em
|
margin-top: 1em
|
||||||
|
@ -43,12 +36,6 @@ $cancel-button-color = tomato
|
||||||
.skip-duplicates
|
.skip-duplicates
|
||||||
margin-left: 1em
|
margin-left: 1em
|
||||||
|
|
||||||
.always-upload-similar
|
|
||||||
margin-left: 1em
|
|
||||||
|
|
||||||
.pause-remain-on-error
|
|
||||||
margin-left: 1em
|
|
||||||
|
|
||||||
form>.messages
|
form>.messages
|
||||||
margin-top: 1em
|
margin-top: 1em
|
||||||
|
|
||||||
|
@ -62,14 +49,6 @@ $cancel-button-color = tomato
|
||||||
margin: 0 0 1.2em 0
|
margin: 0 0 1.2em 0
|
||||||
padding-left: 13em
|
padding-left: 13em
|
||||||
|
|
||||||
img
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
|
|
||||||
video
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
|
|
||||||
&>.thumbnail-wrapper
|
&>.thumbnail-wrapper
|
||||||
float: left
|
float: left
|
||||||
width: 12em
|
width: 12em
|
||||||
|
@ -168,15 +147,3 @@ $cancel-button-color = tomato
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
&:last-child .move-down
|
&:last-child .move-down
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
.darktheme &:first-child .move-up
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
.darktheme &:last-child .move-down
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
||||||
.darktheme #post-upload .uploadables-container .uploadable-container
|
|
||||||
.uploadable header
|
|
||||||
background: $upload-header-background-color-darktheme
|
|
||||||
&:first-child .move-up
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
&:last-child .move-down
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
|
@ -8,16 +8,11 @@ $snapshot-merged-background-color = #FEC
|
||||||
|
|
||||||
ul
|
ul
|
||||||
margin: 0 auto
|
margin: 0 auto
|
||||||
padding: 0
|
|
||||||
width: 100%
|
width: 100%
|
||||||
max-width: 35em
|
max-width: 35em
|
||||||
list-style-type: none
|
list-style-type: none
|
||||||
|
|
||||||
li
|
li
|
||||||
margin-bottom: 1em
|
|
||||||
&:last-child
|
|
||||||
margin-bottom: 0
|
|
||||||
|
|
||||||
.time
|
.time
|
||||||
float: right
|
float: right
|
||||||
|
|
||||||
|
@ -31,34 +26,19 @@ $snapshot-merged-background-color = #FEC
|
||||||
div.operation-created
|
div.operation-created
|
||||||
background: $snapshot-created-background-color
|
background: $snapshot-created-background-color
|
||||||
&+.details
|
&+.details
|
||||||
background: alpha(@background, 50%)
|
background: lighten($snapshot-created-background-color, 50%)
|
||||||
div.operation-modified
|
div.operation-modified
|
||||||
background: $snapshot-modified-background-color
|
background: $snapshot-modified-background-color
|
||||||
&+.details
|
&+.details
|
||||||
background: alpha(@background, 50%)
|
background: lighten($snapshot-modified-background-color, 50%)
|
||||||
div.operation-deleted
|
div.operation-deleted
|
||||||
background: $snapshot-deleted-background-color
|
background: $snapshot-deleted-background-color
|
||||||
&+.details
|
&+.details
|
||||||
background: alpha(@background, 50%)
|
background: lighten($snapshot-deleted-background-color, 50%)
|
||||||
div.operation-merged
|
div.operation-merged
|
||||||
background: $snapshot-merged-background-color
|
background: $snapshot-merged-background-color
|
||||||
&+.details
|
&+.details
|
||||||
background: alpha(@background, 50%)
|
background: lighten($snapshot-merged-background-color, 50%)
|
||||||
|
|
||||||
.darktheme .snapshot-list ul li
|
div.details
|
||||||
div.operation-created
|
margin-bottom: 2em
|
||||||
background: darken($snapshot-created-background-color, 80%)
|
|
||||||
&+.details
|
|
||||||
background: alpha(@background, 50%)
|
|
||||||
div.operation-modified
|
|
||||||
background: darken($snapshot-modified-background-color, 80%)
|
|
||||||
&+.details
|
|
||||||
background: alpha(@background, 50%)
|
|
||||||
div.operation-deleted
|
|
||||||
background: darken($snapshot-deleted-background-color, 80%)
|
|
||||||
&+.details
|
|
||||||
background: alpha(@background, 50%)
|
|
||||||
div.operation-merged
|
|
||||||
background: darken($snapshot-merged-background-color, 80%)
|
|
||||||
&+.details
|
|
||||||
background: alpha(@background, 50%)
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
.content-wrapper.tag-categories
|
.content-wrapper.tag-categories
|
||||||
width: 100%
|
width: 100%
|
||||||
max-width: 45em
|
max-width: 40em
|
||||||
table
|
table
|
||||||
border-spacing: 0
|
border-spacing: 0
|
||||||
width: 100%
|
width: 100%
|
||||||
|
@ -11,19 +11,13 @@
|
||||||
td, th
|
td, th
|
||||||
padding: .4em
|
padding: .4em
|
||||||
&.color
|
&.color
|
||||||
input[type=text]
|
text-align: center
|
||||||
width: 8em
|
|
||||||
&.usages
|
&.usages
|
||||||
text-align: center
|
text-align: center
|
||||||
&.remove, &.set-default
|
&.remove, &.set-default
|
||||||
white-space: pre
|
white-space: pre
|
||||||
th
|
|
||||||
white-space: nowrap
|
|
||||||
&:first-child
|
|
||||||
padding-left: 0
|
|
||||||
&:last-child
|
|
||||||
padding-right: 0
|
|
||||||
tfoot
|
tfoot
|
||||||
display: none
|
display: none
|
||||||
form
|
form
|
||||||
width: auto
|
width: auto
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ div.tag-input
|
||||||
|
|
||||||
.wrapper
|
.wrapper
|
||||||
margin-left: 0.5em
|
margin-left: 0.5em
|
||||||
background: $window-color
|
background: $tag-suggestions-background-color
|
||||||
border: 1px solid $tag-suggestions-border-color
|
border: 1px solid $tag-suggestions-border-color
|
||||||
width: 15em
|
width: 15em
|
||||||
word-break: break-all
|
word-break: break-all
|
||||||
|
@ -62,7 +62,7 @@ div.tag-input
|
||||||
max-height: 20em
|
max-height: 20em
|
||||||
padding: 0.5em 1em 0 1em
|
padding: 0.5em 1em 0 1em
|
||||||
li:last-child
|
li:last-child
|
||||||
border-bottom: 0.5em solid alpha($window-color, 0)
|
border-bottom: 0.5em solid alpha($tag-suggestions-background-color, 0)
|
||||||
li
|
li
|
||||||
margin: 0
|
margin: 0
|
||||||
font-size: 90%
|
font-size: 90%
|
||||||
|
@ -86,12 +86,6 @@ div.tag-input
|
||||||
font-size: 90%
|
font-size: 90%
|
||||||
unselectable()
|
unselectable()
|
||||||
|
|
||||||
@keyframes tag-added-to-post
|
|
||||||
from
|
|
||||||
max-height: 0
|
|
||||||
to
|
|
||||||
max-height: 5em
|
|
||||||
|
|
||||||
ul.compact-tags
|
ul.compact-tags
|
||||||
width: 100%
|
width: 100%
|
||||||
margin: 0.5em 0 0 0
|
margin: 0.5em 0 0 0
|
||||||
|
@ -109,30 +103,18 @@ ul.compact-tags
|
||||||
a:focus
|
a:focus
|
||||||
outline: 0
|
outline: 0
|
||||||
box-shadow: inset 0 0 0 2px $main-color
|
box-shadow: inset 0 0 0 2px $main-color
|
||||||
// these 3 added when tag is added to ul
|
|
||||||
&.added, &.new, &.implication
|
|
||||||
animation: tag-added-to-post 1s ease forwards
|
|
||||||
&.implication
|
&.implication
|
||||||
|
background: $implied-tag-background-color
|
||||||
color: $implied-tag-text-color
|
color: $implied-tag-text-color
|
||||||
background-color: $implied-tag-background-color
|
|
||||||
&.new
|
&.new
|
||||||
|
background: $new-tag-background-color
|
||||||
color: $new-tag-text-color
|
color: $new-tag-text-color
|
||||||
background-color: $new-tag-background-color
|
|
||||||
&.duplicate
|
&.duplicate
|
||||||
|
background: $duplicate-tag-background-color
|
||||||
color: $duplicate-tag-text-color
|
color: $duplicate-tag-text-color
|
||||||
background-color: $duplicate-tag-background-color
|
|
||||||
i
|
i
|
||||||
padding-right: 0.4em
|
padding-right: 0.4em
|
||||||
|
|
||||||
.darktheme ul.compact-tags
|
|
||||||
li
|
|
||||||
&.new
|
|
||||||
background-color: darken($new-tag-background-color, 80%)
|
|
||||||
&.implication
|
|
||||||
background-color: darken($implied-tag-background-color, 85%)
|
|
||||||
&.duplicate
|
|
||||||
background-color: darken($duplicate-tag-background-color, 80%)
|
|
||||||
|
|
||||||
div.tag-input, ul.compact-tags
|
div.tag-input, ul.compact-tags
|
||||||
.tag-usages, .tag-weight, .remove-tag
|
.tag-usages, .tag-weight, .remove-tag
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
|
@ -143,19 +125,3 @@ div.tag-input, ul.compact-tags
|
||||||
margin-left: 0.7em
|
margin-left: 0.7em
|
||||||
.remove-tag
|
.remove-tag
|
||||||
margin-right: 0.5em
|
margin-right: 0.5em
|
||||||
|
|
||||||
.darktheme
|
|
||||||
div.tag-input .tag-suggestions
|
|
||||||
.buttons a
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
.wrapper
|
|
||||||
background: $window-color-darktheme
|
|
||||||
ul li:last-child
|
|
||||||
border-bottom: 0.5em solid alpha($window-color-darktheme, 0)
|
|
||||||
p
|
|
||||||
background: darken($tag-suggestions-header-color, 80%)
|
|
||||||
.append
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
div.tag-input, ul.compact-tags
|
|
||||||
.tag-usages, .tag-weight, .remove-tag
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
th, td
|
th, td
|
||||||
padding: 0.1em 0.5em
|
padding: 0.1em 0.5em
|
||||||
th
|
th
|
||||||
white-space: nowrap
|
|
||||||
background: $top-navigation-color
|
background: $top-navigation-color
|
||||||
.names
|
.names
|
||||||
width: 28%
|
width: 28%
|
||||||
|
@ -40,13 +39,6 @@
|
||||||
.implications, .suggestions
|
.implications, .suggestions
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
.darktheme .tag-list
|
|
||||||
table
|
|
||||||
tr:hover td
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
th
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
.tag-list-header
|
.tag-list-header
|
||||||
label
|
label
|
||||||
display: none !important
|
display: none !important
|
||||||
|
@ -54,14 +46,7 @@
|
||||||
form
|
form
|
||||||
width: auto
|
width: auto
|
||||||
input[name=search-text]
|
input[name=search-text]
|
||||||
width: 25em
|
max-width: 15em
|
||||||
@media (max-width: 1000px)
|
|
||||||
width: 100%
|
|
||||||
.append
|
.append
|
||||||
vertical-align: middle
|
|
||||||
font-size: 0.95em
|
font-size: 0.95em
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
|
|
||||||
.darktheme .tag-list-header
|
|
||||||
.append
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
|
@ -21,15 +21,10 @@
|
||||||
.details
|
.details
|
||||||
font-size: 90%
|
font-size: 90%
|
||||||
line-height: 130%
|
line-height: 130%
|
||||||
.image
|
|
||||||
margin: 0.25em 0.6em 0.25em 0
|
|
||||||
.thumbnail
|
.thumbnail
|
||||||
width: 3em
|
width: 3em
|
||||||
height: 3em
|
height: 3em
|
||||||
|
margin: 0.25em 0.6em 0 0
|
||||||
.darktheme .user-list
|
|
||||||
ul li
|
|
||||||
background: $top-navigation-color-darktheme
|
|
||||||
|
|
||||||
.user-list-header
|
.user-list-header
|
||||||
label
|
label
|
||||||
|
@ -38,14 +33,7 @@
|
||||||
form
|
form
|
||||||
width: auto
|
width: auto
|
||||||
input[name=search-text]
|
input[name=search-text]
|
||||||
width: 25em
|
max-width: 15em
|
||||||
@media (max-width: 1000px)
|
|
||||||
width: 100%
|
|
||||||
.append
|
.append
|
||||||
vertical-align: middle
|
|
||||||
font-size: 0.95em
|
font-size: 0.95em
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
|
|
||||||
.darktheme .user-list-header
|
|
||||||
.append
|
|
||||||
color: $inactive-link-color-darktheme
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
@import colors
|
|
||||||
$token-border-color = $active-tab-background-color
|
|
||||||
|
|
||||||
#user
|
#user
|
||||||
width: 100%
|
width: 100%
|
||||||
max-width: 35em
|
max-width: 35em
|
||||||
|
@ -40,43 +37,7 @@ $token-border-color = $active-tab-background-color
|
||||||
height: 1px
|
height: 1px
|
||||||
clear: both
|
clear: both
|
||||||
|
|
||||||
#user-tokens
|
|
||||||
|
|
||||||
.token-flex-container
|
|
||||||
width: 100%
|
|
||||||
display: flex;
|
|
||||||
flex-direction column;
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
|
|
||||||
.full-width
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
.token-flex-row
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0.2em;
|
|
||||||
|
|
||||||
.no-wrap
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
.token-input
|
|
||||||
min-height: 2em;
|
|
||||||
line-height: 2em;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.token-flex-column
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.token-flex-labels
|
|
||||||
padding-right: 0.5em
|
|
||||||
|
|
||||||
hr
|
|
||||||
border-top: 3px solid $token-border-color
|
|
||||||
|
|
||||||
form
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
#user-delete form
|
#user-delete form
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
#!/usr/bin/dumb-init /bin/sh
|
|
||||||
|
|
||||||
# Integrate environment variables
|
|
||||||
sed -i "s|__BACKEND__|${BACKEND_HOST}|" \
|
|
||||||
/etc/nginx/nginx.conf
|
|
||||||
sed -i "s|__BASEURL__|${BASE_URL:-/}|g" \
|
|
||||||
/var/www/index.htm \
|
|
||||||
/var/www/manifest.json
|
|
||||||
|
|
||||||
# Start server
|
|
||||||
exec nginx
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class='comment-container'>
|
<div class='comment-container'>
|
||||||
<div class='avatar'>
|
<div class='avatar'>
|
||||||
<% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %>
|
<% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %>
|
||||||
<a href='<%- ctx.formatClientLink('user', ctx.user.name) %>'>
|
<a href='/user/<%- encodeURIComponent(ctx.user.name) %>'>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<%= ctx.makeThumbnail(ctx.user ? ctx.user.avatarUrl : null) %>
|
<%= ctx.makeThumbnail(ctx.user ? ctx.user.avatarUrl : null) %>
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
<nav class='readonly'><%
|
<nav class='readonly'><%
|
||||||
%><strong><span class='nickname'><%
|
%><strong><span class='nickname'><%
|
||||||
%><% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %><%
|
%><% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %><%
|
||||||
%><a href='<%- ctx.formatClientLink('user', ctx.user.name) %>'><%
|
%><a href='/user/<%- encodeURIComponent(ctx.user.name) %>'><%
|
||||||
%><% } %><%
|
%><% } %><%
|
||||||
|
|
||||||
%><%- ctx.user ? ctx.user.name : 'Deleted user' %><%
|
%><%- ctx.user ? ctx.user.name : 'Deleted user' %><%
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class='global-comment-list'>
|
<div class='global-comment-list'>
|
||||||
<ul><!--
|
<ul><!--
|
||||||
--><% for (let post of ctx.response.results) { %><!--
|
--><% for (let post of ctx.results) { %><!--
|
||||||
--><li><!--
|
--><li><!--
|
||||||
--><div class='post-thumbnail'><!--
|
--><div class='post-thumbnail'><!--
|
||||||
--><% if (ctx.canViewPosts) { %><!--
|
--><% if (ctx.canViewPosts) { %><!--
|
||||||
--><a href='<%- ctx.formatClientLink('post', post.id) %>'><!--
|
--><a href='/post/<%- encodeURIComponent(post.id) %>'><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><%= ctx.makeThumbnail(post.thumbnailUrl) %><!--
|
--><%= ctx.makeThumbnail(post.thumbnailUrl) %><!--
|
||||||
--><% if (ctx.canViewPosts) { %><!--
|
--><% if (ctx.canViewPosts) { %><!--
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<div class='pager'>
|
<div class='pager'>
|
||||||
<div class='page-header-holder'></div>
|
<div class='page-header-holder'></div>
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
<div class='page-guard top'></div>
|
|
||||||
<div class='pages-holder'></div>
|
<div class='pages-holder'></div>
|
||||||
<div class='page-guard bottom'></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,19 +8,9 @@
|
||||||
<% } %>
|
<% } %>
|
||||||
<br/>
|
<br/>
|
||||||
Or just click on this box.
|
Or just click on this box.
|
||||||
<% if (ctx.extraText) { %>
|
|
||||||
<br/>
|
|
||||||
<small><%= ctx.extraText %></small>
|
|
||||||
<% } %>
|
|
||||||
</label>
|
</label>
|
||||||
<% if (ctx.allowUrls) { %>
|
<% if (ctx.allowUrls) { %>
|
||||||
<div class='url-holder'>
|
<input type='text' name='url' placeholder='Alternatively, paste an URL here.'/>
|
||||||
<input type='text' name='url' placeholder='<%- ctx.urlPlaceholder %>'/>
|
<button>Add URL</button>
|
||||||
<% if (ctx.lock) { %>
|
|
||||||
<button>Confirm</button>
|
|
||||||
<% } else { %>
|
|
||||||
<button>Add URL</button>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<div class='content-wrapper' id='help'>
|
<div class='content-wrapper' id='help'>
|
||||||
<nav class='buttons primary'><!--
|
<nav class='buttons primary'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li data-name='about'><a href='<%- ctx.formatClientLink('help', 'about') %>'>About</a></li><!--
|
--><li data-name='about'><a href='/help/about'>About</a></li><!--
|
||||||
--><li data-name='keyboard'><a href='<%- ctx.formatClientLink('help', 'keyboard') %>'>Keyboard</a></li><!--
|
--><li data-name='keyboard'><a href='/help/keyboard'>Keyboard</a></li><!--
|
||||||
--><li data-name='search'><a href='<%- ctx.formatClientLink('help', 'search') %>'>Search syntax</a></li><!--
|
--><li data-name='search'><a href='/help/search'>Search syntax</a></li><!--
|
||||||
--><li data-name='comments'><a href='<%- ctx.formatClientLink('help', 'comments') %>'>Comments</a></li><!--
|
--><li data-name='comments'><a href='/help/comments'>Comments</a></li><!--
|
||||||
--><li data-name='tos'><a href='<%- ctx.formatClientLink('help', 'tos') %>'>Terms of service</a></li><!--
|
--><li data-name='tos'><a href='/help/tos'>Terms of service</a></li><!--
|
||||||
--></ul><!--
|
--></ul><!--
|
||||||
--></nav>
|
--></nav>
|
||||||
|
|
||||||
|
|
|
@ -33,15 +33,10 @@ shortcuts:</p>
|
||||||
<td><kbd>P</kbd></td>
|
<td><kbd>P</kbd></td>
|
||||||
<td>Focus first post in post list</td>
|
<td>Focus first post in post list</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><kbd>Delete</kbd></td>
|
|
||||||
<td>Delete post (while in edit mode)</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>Additionally, each item in the top navigation can be accessed using a
|
<p>Additionally, each item in top navigation can be accessed using feature
|
||||||
feature called “access keys”. Pressing the underlined letter while
|
called “access keys”. Pressing underlined letter while holding
|
||||||
holding Shift or Alt+Shift (depending on your browser) will go to the desired
|
Shfit or Alt+Shift (depending on your browser) will go to the desired page
|
||||||
page (most browsers) or focus the link (IE).</p>
|
(most browsers) or focus the link (IE).</p>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<nav class='buttons secondary'><!--
|
<nav class='buttons secondary'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li data-name='default'><a href='<%- ctx.formatClientLink('help', 'search') %>'>General</a></li><!--
|
--><li data-name='default'><a href='/help/search'>General</a></li><!--
|
||||||
--><li data-name='posts'><a href='<%- ctx.formatClientLink('help', 'search', 'posts') %>'>Posts</a></li><!--
|
--><li data-name='posts'><a href='/help/search/posts'>Posts</a></li><!--
|
||||||
--><li data-name='users'><a href='<%- ctx.formatClientLink('help', 'search', 'users') %>'>Users</a></li><!--
|
--><li data-name='users'><a href='/help/search/users'>Users</a></li><!--
|
||||||
--><li data-name='tags'><a href='<%- ctx.formatClientLink('help', 'search', 'tags') %>'>Tags</a></li><!--
|
--><li data-name='tags'><a href='/help/search/tags'>Tags</a></li><!--
|
||||||
--><li data-name='pools'><a href='<%- ctx.formatClientLink('help', 'search', 'pools') %>'>Pools</li><!--
|
|
||||||
--></ul><!--
|
--></ul><!--
|
||||||
--></nav>
|
--></nav>
|
||||||
|
|
||||||
|
|
|
@ -80,9 +80,6 @@ take following form:</p>
|
||||||
<code>,desc</code> to control the sort direction, which can be also controlled
|
<code>,desc</code> to control the sort direction, which can be also controlled
|
||||||
by negating the whole token.</p>
|
by negating the whole token.</p>
|
||||||
|
|
||||||
<p>You can escape special characters such as <code>:</code> and <code>-</code>
|
|
||||||
by prepending them with a backslash: <code>\\</code>.</p>
|
|
||||||
|
|
||||||
<h1>Example</h1>
|
<h1>Example</h1>
|
||||||
|
|
||||||
<p>Searching for posts with following query:</p>
|
<p>Searching for posts with following query:</p>
|
||||||
|
@ -92,8 +89,3 @@ by prepending them with a backslash: <code>\\</code>.</p>
|
||||||
<p>will show flash files tagged as sea, that were liked by seven people at
|
<p>will show flash files tagged as sea, that were liked by seven people at
|
||||||
most, uploaded by user Pirate.</p>
|
most, uploaded by user Pirate.</p>
|
||||||
|
|
||||||
<p>Searching for posts with <code>re:zero</code> will show an error message
|
|
||||||
about unknown named token.</p>
|
|
||||||
|
|
||||||
<p>Searching for posts with <code>re\:zero</code> will show posts tagged with
|
|
||||||
<code>re:zero</code>.</p>
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
<p><strong>Anonymous tokens</strong></p>
|
|
||||||
|
|
||||||
<p>Same as <code>name</code> token.</p>
|
|
||||||
|
|
||||||
<p><strong>Named tokens</strong></p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><code>name</code></td>
|
|
||||||
<td>having given name (accepts wildcards)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>category</code></td>
|
|
||||||
<td>having given category (accepts wildcards)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>creation-date</code></td>
|
|
||||||
<td>created at given date</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>creation-time</code></td>
|
|
||||||
<td>alias of <code>creation-date</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>last-edit-date</code></td>
|
|
||||||
<td>edited at given date</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>last-edit-time</code></td>
|
|
||||||
<td>alias of <code>last-edit-date</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>edit-date</code></td>
|
|
||||||
<td>alias of <code>last-edit-date</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>edit-time</code></td>
|
|
||||||
<td>alias of <code>last-edit-date</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>post-count</code></td>
|
|
||||||
<td>alias of <code>usages</code></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p><strong>Sort style tokens</strong></p>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><code>random</code></td>
|
|
||||||
<td>as random as it can get</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>name</code></td>
|
|
||||||
<td>A to Z</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>category</code></td>
|
|
||||||
<td>category (A to Z)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>creation-date</code></td>
|
|
||||||
<td>recently created first</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>creation-time</code></td>
|
|
||||||
<td>alias of <code>creation-date</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>last-edit-date</code></td>
|
|
||||||
<td>recently edited first</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>last-edit-time</code></td>
|
|
||||||
<td>alias of <code>creation-time</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>edit-date</code></td>
|
|
||||||
<td>alias of <code>creation-time</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>edit-time</code></td>
|
|
||||||
<td>alias of <code>creation-time</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>post-count</code></td>
|
|
||||||
<td>number of posts</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p><strong>Special tokens</strong></p>
|
|
||||||
|
|
||||||
<p>None.</p>
|
|
|
@ -12,7 +12,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>tag</code></td>
|
<td><code>tag</code></td>
|
||||||
<td>having given tag (accepts wildcards)</td>
|
<td>having given tag</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>score</code></td>
|
<td><code>score</code></td>
|
||||||
|
@ -20,31 +20,23 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>uploader</code></td>
|
<td><code>uploader</code></td>
|
||||||
<td>uploaded by given user (accepts wildcards)</td>
|
<td>uploaded by given user</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>upload</code></td>
|
<td><code>upload</code></td>
|
||||||
<td>alias of <code>uploader</code></td>
|
<td>alias of <code>upload</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>submit</code></td>
|
<td><code>submit</code></td>
|
||||||
<td>alias of <code>uploader</code></td>
|
<td>alias of <code>upload</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>comment</code></td>
|
<td><code>comment</code></td>
|
||||||
<td>commented by given user (accepts wildcards)</td>
|
<td>commented by given user</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>fav</code></td>
|
<td><code>fav</code></td>
|
||||||
<td>favorited by given user (accepts wildcards)</td>
|
<td>favorited by given user</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>source</code></td>
|
|
||||||
<td>having given source URL (accepts wildcards)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>pool</code></td>
|
|
||||||
<td>belonging to the pool with the given ID</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>tag-count</code></td>
|
<td><code>tag-count</code></td>
|
||||||
|
@ -62,10 +54,6 @@
|
||||||
<td><code>note-count</code></td>
|
<td><code>note-count</code></td>
|
||||||
<td>having given number of annotations</td>
|
<td>having given number of annotations</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>note-text</code></td>
|
|
||||||
<td>having given note text (accepts wildcards)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>relation-count</code></td>
|
<td><code>relation-count</code></td>
|
||||||
<td>having given number of relations</td>
|
<td>having given number of relations</td>
|
||||||
|
@ -78,21 +66,9 @@
|
||||||
<td><code>type</code></td>
|
<td><code>type</code></td>
|
||||||
<td>given type of posts. <code><value></code> can be either <code>image</code>, <code>animation</code> (or <code>animated</code> or <code>anim</code>), <code>flash</code> (or <code>swf</code>) or <code>video</code> (or <code>webm</code>).</td>
|
<td>given type of posts. <code><value></code> can be either <code>image</code>, <code>animation</code> (or <code>animated</code> or <code>anim</code>), <code>flash</code> (or <code>swf</code>) or <code>video</code> (or <code>webm</code>).</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>flag</code></td>
|
|
||||||
<td>having given flag. <code><value></code> can be either <code>loop</code> or <code>sound</code>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>sha1</code></td>
|
|
||||||
<td>having given SHA1 checksum</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>md5</code></td>
|
|
||||||
<td>having given MD5 checksum</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>content-checksum</code></td>
|
<td><code>content-checksum</code></td>
|
||||||
<td>alias of <code>sha1</code></td>
|
<td>having given SHA1 checksum</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>file-size</code></td>
|
<td><code>file-size</code></td>
|
||||||
|
@ -110,14 +86,6 @@
|
||||||
<td><code>image-area</code></td>
|
<td><code>image-area</code></td>
|
||||||
<td>having given number of pixels (image width * image height)</td>
|
<td>having given number of pixels (image width * image height)</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>image-aspect-ratio</code></td>
|
|
||||||
<td>having given aspect ratio (image width / image height)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>image-ar</code></td>
|
|
||||||
<td>alias of <code>image-aspect-ratio</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>width</code></td>
|
<td><code>width</code></td>
|
||||||
<td>alias of <code>image-width</code></td>
|
<td>alias of <code>image-width</code></td>
|
||||||
|
@ -130,14 +98,6 @@
|
||||||
<td><code>area</code></td>
|
<td><code>area</code></td>
|
||||||
<td>alias of <code>image-area</code></td>
|
<td>alias of <code>image-area</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>aspect-ratio</code></td>
|
|
||||||
<td>alias of <code>image-aspect-ratio</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>ar</code></td>
|
|
||||||
<td>alias of <code>image-aspect-ratio</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>creation-date</code></td>
|
<td><code>creation-date</code></td>
|
||||||
<td>posted at given date</td>
|
<td>posted at given date</td>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>category</code></td>
|
<td><code>category</code></td>
|
||||||
<td>having given category (accepts wildcards)</td>
|
<td>having given category</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>creation-date</code></td>
|
<td><code>creation-date</code></td>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<%= ctx.makeTextInput({name: 'search-text', placeholder: 'enter some tags'}) %>
|
<%= ctx.makeTextInput({name: 'search-text', placeholder: 'enter some tags'}) %>
|
||||||
<input type='submit' value='Search'/>
|
<input type='submit' value='Search'/>
|
||||||
<span class=sep>or</span>
|
<span class=sep>or</span>
|
||||||
<a href='<%- ctx.formatClientLink('posts') %>'>browse all posts</a>
|
<a href='/posts'>browse all posts</a>
|
||||||
</form>
|
</form>
|
||||||
<% } %>
|
<% } %>
|
||||||
<div class='post-info-container'></div>
|
<div class='post-info-container'></div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><%- ctx.postCount %> posts</li><span class='sep'>
|
<li><%- ctx.postCount %> posts</li><span class='sep'>
|
||||||
</span><li><%= ctx.makeFileSize(ctx.diskUsage) %></li><span class='sep'>
|
</span><li><%= ctx.makeFileSize(ctx.diskUsage) %></li><span class='sep'>
|
||||||
</span><li>Build <a class='version' href='https://github.com/rr-/szurubooru/commits/master'><%- ctx.version %></a><%- ctx.isDevelopmentMode ? " (DEV MODE)" : "" %> from <%= ctx.makeRelativeTime(ctx.buildDate) %></li><span class='sep'>
|
</span><li>Build <a class='version' href='https://github.com/rr-/szurubooru/commits/master'><%- ctx.version %></a> from <%= ctx.makeRelativeTime(ctx.buildDate) %></li><span class='sep'>
|
||||||
</span><% if (ctx.canListSnapshots) { %><li><a href='<%- ctx.formatClientLink('history') %>'>History</a></li><span class='sep'>
|
</span><% if (ctx.canListSnapshots) { %><li><a href='/history'>History</a></li><span class='sep'>
|
||||||
</span><% } %>
|
</span><% } %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -2,31 +2,16 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8'/>
|
<meta charset='utf-8'/>
|
||||||
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>
|
||||||
<meta name='theme-color' content='#24aadd'/>
|
<title><!-- configured in the config file --></title>
|
||||||
<meta name='apple-mobile-web-app-capable' content='yes'/>
|
<link href='/css/app.min.css' rel='stylesheet' type='text/css'/>
|
||||||
<meta name='apple-mobile-web-app-status-bar-style' content='black'/>
|
<link href='/css/vendor.min.css' rel='stylesheet' type='text/css'/>
|
||||||
<meta name='msapplication-TileColor' content='#ffffff'/>
|
<link rel='shortcut icon' type='image/png' href='/img/favicon.png'/>
|
||||||
<meta name="msapplication-TileImage" content="/img/mstile-150x150.png">
|
|
||||||
<title>Loading...</title>
|
|
||||||
<!-- Base HTML Placeholder -->
|
|
||||||
<link href='css/app.min.css' rel='stylesheet' type='text/css'/>
|
|
||||||
<link href='css/vendor.min.css' rel='stylesheet' type='text/css'/>
|
|
||||||
<link rel='shortcut icon' type='image/png' href='img/favicon.png'/>
|
|
||||||
<link rel='apple-touch-icon' sizes='180x180' href='img/apple-touch-icon.png'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-640x1136.png' media='(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-750x1294.png' media='(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1242x2148.png' media='(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1125x2436.png' media='(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1536x2048.png' media='(min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-1668x2224.png' media='(min-device-width: 834px) and (max-device-width: 834px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
|
||||||
<link rel='apple-touch-startup-image' href='img/apple-touch-startup-image-2048x2732.png' media='(min-device-width: 1024px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait)'/>
|
|
||||||
<link rel='manifest' href='manifest.json'/>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='top-navigation-holder'></div>
|
<div id='top-navigation-holder'></div>
|
||||||
<div id='content-holder'></div>
|
<div id='content-holder'></div>
|
||||||
<script type='text/javascript' src='js/vendor.min.js'></script>
|
<script type='text/javascript' src='/js/vendor.min.js'></script>
|
||||||
<script type='text/javascript' src='js/app.min.js'></script>
|
<script type='text/javascript' src='/js/app.min.js'></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
|
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<input type='submit' value='Log in'/>
|
<input type='submit' value='Log in'/>
|
||||||
<a class='append' href='<%- ctx.formatClientLink('password-reset') %>'>Forgot the password?</a>
|
<% if (ctx.canSendMails) { %>
|
||||||
|
<a class='append' href='/password-reset'>Forgot the password?</a>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<nav class='buttons'>
|
<nav class='buttons'>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<% if (ctx.prevPage !== ctx.currentPage) { %>
|
<% if (ctx.prevLinkActive) { %>
|
||||||
<a rel='prev' class='prev' href='<%- ctx.getClientUrlForPage(ctx.pages.get(ctx.prevPage).offset, ctx.pages.get(ctx.prevPage).limit) %>'>
|
<a class='prev' href='<%- ctx.prevLink %>'>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='prev' class='prev disabled'>
|
<a class='prev disabled'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<i class='fa fa-chevron-left'></i>
|
<i class='fa fa-chevron-left'></i>
|
||||||
<span class='vim-nav-hint'>< Previous page</span>
|
<span class='vim-nav-hint'>< Previous page</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<% for (let page of ctx.pages.values()) { %>
|
<% for (let page of ctx.pages) { %>
|
||||||
<% if (page.ellipsis) { %>
|
<% if (page.ellipsis) { %>
|
||||||
<li>…</li>
|
<li>…</li>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
@ -20,16 +20,16 @@
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<li>
|
<li>
|
||||||
<% } %>
|
<% } %>
|
||||||
<a href='<%- ctx.getClientUrlForPage(page.offset, page.limit) %>'><%- page.number %></a>
|
<a href='<%- page.link %>'><%- page.number %></a>
|
||||||
</li>
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<% if (ctx.nextPage !== ctx.currentPage) { %>
|
<% if (ctx.nextLinkActive) { %>
|
||||||
<a rel='next' class='next' href='<%- ctx.getClientUrlForPage(ctx.pages.get(ctx.nextPage).offset, ctx.pages.get(ctx.nextPage).limit) %>'>
|
<a class='next' href='<%- ctx.nextLink %>'>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='next' class='next disabled'>
|
<a class='next disabled'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<i class='fa fa-chevron-right'></i>
|
<i class='fa fa-chevron-right'></i>
|
||||||
<span class='vim-nav-hint'>Next page ></span>
|
<span class='vim-nav-hint'>Next page ></span>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class='not-found'>
|
<div class='not-found'>
|
||||||
<h1>Not found</h1>
|
<h1>Not found</h1>
|
||||||
<p><%- ctx.path %> is not a valid URL.</p>
|
<p><%- ctx.path %> is not a valid URL.</p>
|
||||||
<p><a href='<%- ctx.formatClientLink() %>'>Back to main page</a></p>
|
<p><a href='/'>Back to main page</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,30 +1,23 @@
|
||||||
<div class='content-wrapper' id='password-reset'>
|
<div class='content-wrapper' id='password-reset'>
|
||||||
<h1>Password reset</h1>
|
<h1>Password reset</h1>
|
||||||
<% if (ctx.canSendMails) { %>
|
<form autocomplete='off'>
|
||||||
<form autocomplete='off'>
|
<ul class='input'>
|
||||||
<ul class='input'>
|
<li>
|
||||||
<li>
|
<%= ctx.makeTextInput({
|
||||||
<%= ctx.makeTextInput({
|
text: 'User name or e-mail address',
|
||||||
text: 'User name or e-mail address',
|
name: 'user-name',
|
||||||
name: 'user-name',
|
required: true,
|
||||||
required: true,
|
}) %>
|
||||||
}) %>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p><small>Proceeding will send an e-mail that contains a password reset
|
<p><small>Proceeding will send an e-mail that contains a password reset
|
||||||
link. Clicking it is going to generate a new password for your account.
|
link. Clicking it is going to generate a new password for your account.
|
||||||
It is recommended to change that password to something else.</small></p>
|
It is recommended to change that password to something else.</small></p>
|
||||||
|
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<input type='submit' value='Proceed'/>
|
<input type='submit' value='Proceed'/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<% } else { %>
|
|
||||||
<p>We do not support automatic password resetting.</p>
|
|
||||||
<% if (ctx.contactEmail) { %>
|
|
||||||
<p>Please send an e-mail to <a href='mailto:<%- ctx.contactEmail %>'><%- ctx.contactEmail %></a> to go through a manual procedure.</p>
|
|
||||||
<% } %>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<div class='content-wrapper' id='pool'>
|
|
||||||
<h1><%- ctx.getPrettyName(ctx.pool.names[0]) %></h1>
|
|
||||||
<nav class='buttons'><!--
|
|
||||||
--><ul><!--
|
|
||||||
--><li data-name='summary'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id) %>'>Summary</a></li><!--
|
|
||||||
--><% if (ctx.canEditAnything) { %><!--
|
|
||||||
--><li data-name='edit'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id, 'edit') %>'>Edit</a></li><!--
|
|
||||||
--><% } %><!--
|
|
||||||
--><% if (ctx.canMerge) { %><!--
|
|
||||||
--><li data-name='merge'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id, 'merge') %>'>Merge with…</a></li><!--
|
|
||||||
--><% } %><!--
|
|
||||||
--><% if (ctx.canDelete) { %><!--
|
|
||||||
--><li data-name='delete'><a href='<%- ctx.formatClientLink('pool', ctx.pool.id, 'delete') %>'>Delete</a></li><!--
|
|
||||||
--><% } %><!--
|
|
||||||
--></ul><!--
|
|
||||||
--></nav>
|
|
||||||
<div class='pool-content-holder'></div>
|
|
||||||
</div>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<div class='content-wrapper pool-categories'>
|
|
||||||
<form>
|
|
||||||
<h1>Pool categories</h1>
|
|
||||||
<div class="table-wrap">
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class='name'>Category name</th>
|
|
||||||
<th class='color'>CSS color</th>
|
|
||||||
<th class='usages'>Usages</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if (ctx.canCreate) { %>
|
|
||||||
<p><a href class='add'>Add new category</a></p>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<div class='messages'></div>
|
|
||||||
|
|
||||||
<% if (ctx.canCreate || ctx.canEditName || ctx.canEditColor || ctx.canDelete) { %>
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' class='save' value='Save changes'>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<% if (ctx.poolCategory.isDefault) { %><%
|
|
||||||
%><tr data-category='<%- ctx.poolCategory.name %>' class='default'><%
|
|
||||||
%><% } else { %><%
|
|
||||||
%><tr data-category='<%- ctx.poolCategory.name %>'><%
|
|
||||||
%><% } %>
|
|
||||||
<td class='name'>
|
|
||||||
<% if (ctx.canEditName) { %>
|
|
||||||
<%= ctx.makeTextInput({value: ctx.poolCategory.name, required: true}) %>
|
|
||||||
<% } else { %>
|
|
||||||
<%- ctx.poolCategory.name %>
|
|
||||||
<% } %>
|
|
||||||
</td>
|
|
||||||
<td class='color'>
|
|
||||||
<% if (ctx.canEditColor) { %>
|
|
||||||
<%= ctx.makeColorInput({value: ctx.poolCategory.color}) %>
|
|
||||||
<% } else { %>
|
|
||||||
<%- ctx.poolCategory.color %>
|
|
||||||
<% } %>
|
|
||||||
</td>
|
|
||||||
<td class='usages'>
|
|
||||||
<% if (ctx.poolCategory.name) { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: 'category:' + ctx.poolCategory.name}) %>'>
|
|
||||||
<%- ctx.poolCategory.poolCount %>
|
|
||||||
</a>
|
|
||||||
<% } else { %>
|
|
||||||
<%- ctx.poolCategory.poolCount %>
|
|
||||||
<% } %>
|
|
||||||
</td>
|
|
||||||
<% if (ctx.canDelete) { %>
|
|
||||||
<td class='remove'>
|
|
||||||
<% if (ctx.poolCategory.poolCount) { %>
|
|
||||||
<a class='inactive' title="Can't delete category in use">Remove</a>
|
|
||||||
<% } else { %>
|
|
||||||
<a href>Remove</a>
|
|
||||||
<% } %>
|
|
||||||
</td>
|
|
||||||
<% } %>
|
|
||||||
<% if (ctx.canSetDefault) { %>
|
|
||||||
<td class='set-default'>
|
|
||||||
<a href>Make default</a>
|
|
||||||
</td>
|
|
||||||
<% } %>
|
|
||||||
</tr>
|
|
|
@ -1,42 +0,0 @@
|
||||||
<div class='content-wrapper pool-create'>
|
|
||||||
<form>
|
|
||||||
<ul class='input'>
|
|
||||||
<li class='names'>
|
|
||||||
<%= ctx.makeTextInput({
|
|
||||||
text: 'Names',
|
|
||||||
value: '',
|
|
||||||
required: true,
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
<li class='category'>
|
|
||||||
<%= ctx.makeSelect({
|
|
||||||
text: 'Category',
|
|
||||||
keyValues: ctx.categories,
|
|
||||||
selectedKey: 'default',
|
|
||||||
required: true,
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
<li class='description'>
|
|
||||||
<%= ctx.makeTextarea({
|
|
||||||
text: 'Description',
|
|
||||||
value: '',
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
<li class='posts'>
|
|
||||||
<%= ctx.makeTextInput({
|
|
||||||
text: 'Posts',
|
|
||||||
value: '',
|
|
||||||
placeholder: 'space-separated post IDs',
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<% if (ctx.canCreate) { %>
|
|
||||||
<div class='messages'></div>
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' class='save' value='Create pool'>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<div class='pool-delete'>
|
|
||||||
<form>
|
|
||||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
|
||||||
|
|
||||||
<ul class='input'>
|
|
||||||
<li>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
name: 'confirm-deletion',
|
|
||||||
text: 'I confirm that I want to delete this pool.',
|
|
||||||
required: true,
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class='messages'></div>
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' value='Delete pool'/>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<div class='content-wrapper pool-edit'>
|
|
||||||
<form>
|
|
||||||
<ul class='input'>
|
|
||||||
<li class='names'>
|
|
||||||
<% if (ctx.canEditNames) { %>
|
|
||||||
<%= ctx.makeTextInput({
|
|
||||||
text: 'Names',
|
|
||||||
value: ctx.pool.names.join(' '),
|
|
||||||
required: true,
|
|
||||||
}) %>
|
|
||||||
<% } %>
|
|
||||||
</li>
|
|
||||||
<li class='category'>
|
|
||||||
<% if (ctx.canEditCategory) { %>
|
|
||||||
<%= ctx.makeSelect({
|
|
||||||
text: 'Category',
|
|
||||||
keyValues: ctx.categories,
|
|
||||||
selectedKey: ctx.pool.category,
|
|
||||||
required: true,
|
|
||||||
}) %>
|
|
||||||
<% } %>
|
|
||||||
</li>
|
|
||||||
<li class='description'>
|
|
||||||
<% if (ctx.canEditDescription) { %>
|
|
||||||
<%= ctx.makeTextarea({
|
|
||||||
text: 'Description',
|
|
||||||
value: ctx.pool.description,
|
|
||||||
}) %>
|
|
||||||
<% } %>
|
|
||||||
</li>
|
|
||||||
<li class='posts'>
|
|
||||||
<% if (ctx.canEditPosts) { %>
|
|
||||||
<%= ctx.makeTextInput({
|
|
||||||
text: 'Posts',
|
|
||||||
placeholder: 'space-separated post IDs',
|
|
||||||
value: ctx.pool.posts.map(post => post.id).join(' ')
|
|
||||||
}) %>
|
|
||||||
<% } %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<% if (ctx.canEditAnything) { %>
|
|
||||||
<div class='messages'></div>
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' class='save' value='Save changes'>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<div class='pool-input'>
|
|
||||||
<div class='main-control'>
|
|
||||||
<input type='text' placeholder='type to add…'/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class='compact-pools'></ul>
|
|
||||||
</div>
|
|
|
@ -1,22 +0,0 @@
|
||||||
<div class='pool-merge'>
|
|
||||||
<form>
|
|
||||||
<ul class='input'>
|
|
||||||
<li class='target'>
|
|
||||||
<%= ctx.makeTextInput({name: 'target-pool', required: true, text: 'Target pool', pattern: ctx.poolNamePattern}) %>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<p>Posts in the two pools will be combined.
|
|
||||||
Category needs to be handled manually.</p>
|
|
||||||
|
|
||||||
<%= ctx.makeCheckbox({required: true, text: 'I confirm that I want to merge this pool.'}) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class='messages'></div>
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' value='Merge pool'/>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<div class='content-wrapper pool-summary'>
|
|
||||||
<section class='details'>
|
|
||||||
<section>
|
|
||||||
Category:
|
|
||||||
<span class='<%= ctx.makeCssName(ctx.pool.category, 'pool') %>'><%- ctx.pool.category %></span>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
Aliases:<br/>
|
|
||||||
<ul><!--
|
|
||||||
--><% for (let name of ctx.pool.names.slice(1)) { %><!--
|
|
||||||
--><li><%= ctx.makePoolLink(ctx.pool.id, false, false, ctx.pool, name) %></li><!--
|
|
||||||
--><% } %><!--
|
|
||||||
--></ul>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class='description'>
|
|
||||||
<hr/>
|
|
||||||
<%= ctx.makeMarkdown(ctx.pool.description || 'This pool has no description yet.') %>
|
|
||||||
<p>This pool has <a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + ctx.pool.id}) %>'><%- ctx.pool.postCount %> post(s)</a>.</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
|
@ -1,22 +0,0 @@
|
||||||
<div class='pool-list-header'>
|
|
||||||
<form class='horizontal'>
|
|
||||||
<ul class='input'>
|
|
||||||
<li>
|
|
||||||
<%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' value='Search'/>
|
|
||||||
<a class='button append' href='<%- ctx.formatClientLink('help', 'search', 'pools') %>'>Syntax help</a>
|
|
||||||
|
|
||||||
<% if (ctx.canCreate) { %>
|
|
||||||
<a class='append' href='<%- ctx.formatClientLink('pool', 'create') %>'>Add new pool</a>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (ctx.canEditPoolCategories) { %>
|
|
||||||
<a class='append' href='<%- ctx.formatClientLink('pool-categories') %>'>Pool categories</a>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,48 +0,0 @@
|
||||||
<div class='pool-list table-wrap'>
|
|
||||||
<% if (ctx.response.results.length) { %>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<th class='names'>
|
|
||||||
<% if (ctx.parameters.query == 'sort:name' || !ctx.parameters.query) { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: '-sort:name'}) %>'>Pool name(s)</a>
|
|
||||||
<% } else { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: 'sort:name'}) %>'>Pool name(s)</a>
|
|
||||||
<% } %>
|
|
||||||
</th>
|
|
||||||
<th class='post-count'>
|
|
||||||
<% if (ctx.parameters.query == 'sort:post-count') { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: '-sort:post-count'}) %>'>Post count</a>
|
|
||||||
<% } else { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: 'sort:post-count'}) %>'>Post count</a>
|
|
||||||
<% } %>
|
|
||||||
</th>
|
|
||||||
<th class='creation-time'>
|
|
||||||
<% if (ctx.parameters.query == 'sort:creation-time') { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: '-sort:creation-time'}) %>'>Created on</a>
|
|
||||||
<% } else { %>
|
|
||||||
<a href='<%- ctx.formatClientLink('pools', {query: 'sort:creation-time'}) %>'>Created on</a>
|
|
||||||
<% } %>
|
|
||||||
</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<% for (let pool of ctx.response.results) { %>
|
|
||||||
<tr>
|
|
||||||
<td class='names'>
|
|
||||||
<ul>
|
|
||||||
<% for (let name of pool.names) { %>
|
|
||||||
<li><%= ctx.makePoolLink(pool.id, false, false, pool, name) %></li>
|
|
||||||
<% } %>
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
<td class='post-count'>
|
|
||||||
<a href='<%- ctx.formatClientLink('posts', {query: 'pool:' + pool.id}) %>'><%- pool.postCount %></a>
|
|
||||||
</td>
|
|
||||||
<td class='creation-time'>
|
|
||||||
<%= ctx.makeRelativeTime(pool.creationTime) %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% } %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
|
@ -17,7 +17,6 @@
|
||||||
class: 'resize-listener',
|
class: 'resize-listener',
|
||||||
controls: true,
|
controls: true,
|
||||||
loop: (ctx.post.flags || []).includes('loop'),
|
loop: (ctx.post.flags || []).includes('loop'),
|
||||||
playsinline: true,
|
|
||||||
autoplay: ctx.autoplay,
|
autoplay: ctx.autoplay,
|
||||||
},
|
},
|
||||||
ctx.makeElement('source', {
|
ctx.makeElement('source', {
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<h1>Post #<%- ctx.post.id %></h1>
|
<h1>Post #<%- ctx.post.id %></h1>
|
||||||
<nav class='buttons'><!--
|
<nav class='buttons'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li><a href='<%- ctx.formatClientLink('post', ctx.post.id) %>'><i class='fa fa-reply'></i> Main view</a></li><!--
|
--><li><a href='/post/<%- ctx.post.id %>'><i class='fa fa-reply'></i> Main view</a></li><!--
|
||||||
--><% if (ctx.canMerge) { %><!--
|
--><% if (ctx.canMerge) { %><!--
|
||||||
--><li data-name='merge'><a href='<%- ctx.formatClientLink('post', ctx.post.id, 'merge') %>'>Merge with…</a></li><!--
|
--><li data-name='merge'><a href='/post/<%- ctx.post.id %>/merge'>Merge with…</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul><!--
|
--></ul><!--
|
||||||
--></nav>
|
--></nav>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
|
|
||||||
<% if (ctx.enableSafety && ctx.canEditPostSafety) { %>
|
<% if (ctx.canEditPostSafety) { %>
|
||||||
<section class='safety'>
|
<section class='safety'>
|
||||||
<label>Safety</label>
|
<label>Safety</label>
|
||||||
<div class='radio-wrapper'>
|
<div class='radio-wrapper'>
|
||||||
|
@ -50,32 +50,14 @@
|
||||||
name: 'loop',
|
name: 'loop',
|
||||||
checked: ctx.post.flags.includes('loop'),
|
checked: ctx.post.flags.includes('loop'),
|
||||||
}) %>
|
}) %>
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Sound',
|
|
||||||
name: 'sound',
|
|
||||||
checked: ctx.post.flags.includes('sound'),
|
|
||||||
}) %>
|
|
||||||
</section>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (ctx.canEditPostSource) { %>
|
|
||||||
<section class='post-source'>
|
|
||||||
<%= ctx.makeTextarea({
|
|
||||||
text: 'Source',
|
|
||||||
value: ctx.post.source,
|
|
||||||
}) %>
|
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (ctx.canEditPostTags) { %>
|
<% if (ctx.canEditPostTags) { %>
|
||||||
<section class='tags'>
|
<section class='tags'>
|
||||||
<%= ctx.makeTextInput({}) %>
|
<%= ctx.makeTextInput({
|
||||||
</section>
|
value: ctx.post.tags.join(' '),
|
||||||
<% } %>
|
}) %>
|
||||||
|
|
||||||
<% if (ctx.canEditPoolPosts) { %>
|
|
||||||
<section class='pools'>
|
|
||||||
<%= ctx.makeTextInput({}) %>
|
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
@ -84,12 +66,6 @@
|
||||||
<a href class='add'>Add a note</a>
|
<a href class='add'>Add a note</a>
|
||||||
<%= ctx.makeTextarea({disabled: true, text: 'Content (supports Markdown)', rows: '8'}) %>
|
<%= ctx.makeTextarea({disabled: true, text: 'Content (supports Markdown)', rows: '8'}) %>
|
||||||
<a href class='delete inactive'>Delete selected note</a>
|
<a href class='delete inactive'>Delete selected note</a>
|
||||||
<% if (ctx.hasClipboard) { %>
|
|
||||||
<br/>
|
|
||||||
<a href class='copy'>Export notes to clipboard</a>
|
|
||||||
<br/>
|
|
||||||
<a href class='paste'>Import notes from clipboard</a>
|
|
||||||
<% } %>
|
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
<article class='previous-post'>
|
<article class='previous-post'>
|
||||||
<% if (ctx.prevPostId) { %>
|
<% if (ctx.prevPostId) { %>
|
||||||
<% if (ctx.editMode) { %>
|
<% if (ctx.editMode) { %>
|
||||||
<a rel='prev' href='<%= ctx.getPostEditUrl(ctx.prevPostId, ctx.parameters) %>'>
|
<a href='<%= ctx.getPostEditUrl(ctx.prevPostId, ctx.parameters) %>'>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='prev' href='<%= ctx.getPostUrl(ctx.prevPostId, ctx.parameters) %>'>
|
<a href='<%= ctx.getPostUrl(ctx.prevPostId, ctx.parameters) %>'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='prev' class='inactive'>
|
<a class='inactive'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<i class='fa fa-chevron-left'></i>
|
<i class='fa fa-chevron-left'></i>
|
||||||
<span class='vim-nav-hint'>< Previous post</span>
|
<span class='vim-nav-hint'>< Previous post</span>
|
||||||
|
@ -18,18 +18,17 @@
|
||||||
<article class='next-post'>
|
<article class='next-post'>
|
||||||
<% if (ctx.nextPostId) { %>
|
<% if (ctx.nextPostId) { %>
|
||||||
<% if (ctx.editMode) { %>
|
<% if (ctx.editMode) { %>
|
||||||
<a rel='next' href='<%= ctx.getPostEditUrl(ctx.nextPostId, ctx.parameters) %>'>
|
<a href='<%= ctx.getPostEditUrl(ctx.nextPostId, ctx.parameters) %>'>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='next' href='<%= ctx.getPostUrl(ctx.nextPostId, ctx.parameters) %>'>
|
<a href='<%= ctx.getPostUrl(ctx.nextPostId, ctx.parameters) %>'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a rel='next' class='inactive'>
|
<a class='inactive'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<i class='fa fa-chevron-right'></i>
|
<i class='fa fa-chevron-right'></i>
|
||||||
<span class='vim-nav-hint'>Next post ></span>
|
<span class='vim-nav-hint'>Next post ></span>
|
||||||
</a>
|
</a>
|
||||||
</article>
|
</article>
|
||||||
<% if (ctx.canEditPosts || ctx.canDeletePosts || ctx.canFeaturePosts) { %>
|
|
||||||
<article class='edit-post'>
|
<article class='edit-post'>
|
||||||
<% if (ctx.editMode) { %>
|
<% if (ctx.editMode) { %>
|
||||||
<a href='<%= ctx.getPostUrl(ctx.post.id, ctx.parameters) %>'>
|
<a href='<%= ctx.getPostUrl(ctx.post.id, ctx.parameters) %>'>
|
||||||
|
@ -37,13 +36,16 @@
|
||||||
<span class='vim-nav-hint'>Back to view mode</span>
|
<span class='vim-nav-hint'>Back to view mode</span>
|
||||||
</a>
|
</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%= ctx.getPostEditUrl(ctx.post.id, ctx.parameters) %>'>
|
<% if (ctx.canEditPosts || ctx.canDeletePosts || ctx.canFeaturePosts) { %>
|
||||||
<i class='fa fa-pencil'></i>
|
<a href='<%= ctx.getPostEditUrl(ctx.post.id, ctx.parameters) %>'>
|
||||||
<span class='vim-nav-hint'>Edit post</span>
|
<% } else { %>
|
||||||
|
<a class='inactive'>
|
||||||
|
<% } %>
|
||||||
|
<i class='fa fa-pencil'></i>
|
||||||
|
<span class='vim-nav-hint'>Edit post</span>
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</article>
|
</article>
|
||||||
<% } %>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class='sidebar-container'></div>
|
<div class='sidebar-container'></div>
|
||||||
|
@ -52,16 +54,13 @@
|
||||||
<div class='content'>
|
<div class='content'>
|
||||||
<div class='post-container'></div>
|
<div class='post-container'></div>
|
||||||
|
|
||||||
<div class='after-mobile-controls'>
|
<% if (ctx.canListComments) { %>
|
||||||
<div class='description'></div>
|
<div class='comments-container'></div>
|
||||||
<% if (ctx.canCreateComments) { %>
|
<% } %>
|
||||||
<h2>Add comment</h2>
|
|
||||||
<div class='comment-form-container'></div>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% if (ctx.canListComments) { %>
|
<% if (ctx.canCreateComments) { %>
|
||||||
<div class='comments-container'></div>
|
<h2>Add comment</h2>
|
||||||
<% } %>
|
<div class='comment-form-container'></div>
|
||||||
</div>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -35,14 +35,7 @@
|
||||||
'image/gif': 'GIF',
|
'image/gif': 'GIF',
|
||||||
'image/jpeg': 'JPEG',
|
'image/jpeg': 'JPEG',
|
||||||
'image/png': 'PNG',
|
'image/png': 'PNG',
|
||||||
'image/webp': 'WEBP',
|
|
||||||
'image/bmp': 'BMP',
|
|
||||||
'image/avif': 'AVIF',
|
|
||||||
'image/heif': 'HEIF',
|
|
||||||
'image/heic': 'HEIC',
|
|
||||||
'video/webm': 'WEBM',
|
'video/webm': 'WEBM',
|
||||||
'video/mp4': 'MPEG-4',
|
|
||||||
'video/quicktime': 'MOV',
|
|
||||||
'application/x-shockwave-flash': 'SWF',
|
'application/x-shockwave-flash': 'SWF',
|
||||||
}[ctx.post.mimeType] +
|
}[ctx.post.mimeType] +
|
||||||
' (' +
|
' (' +
|
||||||
|
|
|
@ -8,22 +8,11 @@
|
||||||
'image/gif': 'GIF',
|
'image/gif': 'GIF',
|
||||||
'image/jpeg': 'JPEG',
|
'image/jpeg': 'JPEG',
|
||||||
'image/png': 'PNG',
|
'image/png': 'PNG',
|
||||||
'image/webp': 'WEBP',
|
|
||||||
'image/bmp': 'BMP',
|
|
||||||
'image/avif': 'AVIF',
|
|
||||||
'image/heif': 'HEIF',
|
|
||||||
'image/heic': 'HEIC',
|
|
||||||
'video/webm': 'WEBM',
|
'video/webm': 'WEBM',
|
||||||
'video/mp4': 'MPEG-4',
|
|
||||||
'video/quicktime': 'MOV',
|
|
||||||
'application/x-shockwave-flash': 'SWF',
|
'application/x-shockwave-flash': 'SWF',
|
||||||
}[ctx.post.mimeType] %><!--
|
}[ctx.post.mimeType] %>
|
||||||
--></a>
|
</a>
|
||||||
(<%- ctx.post.canvasWidth %>x<%- ctx.post.canvasHeight %>)
|
(<%- ctx.post.canvasWidth %>x<%- ctx.post.canvasHeight %>)
|
||||||
<% if (ctx.post.flags.length) { %><!--
|
|
||||||
--><% if (ctx.post.flags.includes('loop')) { %><i class='fa fa-repeat'></i><% } %><!--
|
|
||||||
--><% if (ctx.post.flags.includes('sound')) { %><i class='fa fa-volume-up'></i><% } %>
|
|
||||||
<% } %>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='upload-info'>
|
<section class='upload-info'>
|
||||||
|
@ -31,12 +20,10 @@
|
||||||
<%= ctx.makeRelativeTime(ctx.post.creationTime) %>
|
<%= ctx.makeRelativeTime(ctx.post.creationTime) %>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if (ctx.enableSafety) { %>
|
<section class='safety'>
|
||||||
<section class='safety'>
|
<i class='fa fa-circle safety-<%- ctx.post.safety %>'></i><!--
|
||||||
<i class='fa fa-circle safety-<%- ctx.post.safety %>'></i><!--
|
--><%- ctx.post.safety[0].toUpperCase() + ctx.post.safety.slice(1) %>
|
||||||
--><%- ctx.post.safety[0].toUpperCase() + ctx.post.safety.slice(1) %>
|
</section>
|
||||||
</section>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<section class='zoom'>
|
<section class='zoom'>
|
||||||
<a href class='fit-original'>Original zoom</a> ·
|
<a href class='fit-original'>Original zoom</a> ·
|
||||||
|
@ -45,20 +32,10 @@
|
||||||
<a href class='fit-both'>both</a>
|
<a href class='fit-both'>both</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if (ctx.post.source) { %>
|
|
||||||
<section class='source'>
|
|
||||||
Source: <% for (let i = 0; i < ctx.post.sourceSplit.length; i++) { %>
|
|
||||||
<% if (i != 0) { %>·<% } %>
|
|
||||||
<a href='<%- ctx.post.sourceSplit[i] %>' title='<%- ctx.post.sourceSplit[i] %>'><%- ctx.extractRootDomain(ctx.post.sourceSplit[i]) %></a>
|
|
||||||
<% } %>
|
|
||||||
</section>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<section class='search'>
|
<section class='search'>
|
||||||
Search on
|
Search on
|
||||||
<a href='http://iqdb.org/?url=<%- encodeURIComponent(ctx.post.fullContentUrl) %>'>IQDB</a> ·
|
<a href='http://iqdb.org/?url=<%- encodeURIComponent(ctx.post.contentUrl) %>'>IQDB</a> ·
|
||||||
<a href='https://danbooru.donmai.us/posts?tags=md5:<%- ctx.post.checksumMD5 %>'>Danbooru</a> ·
|
<a href='https://www.google.com/searchbyimage?&image_url=<%- encodeURIComponent(ctx.post.contentUrl) %>'>Google Images</a>
|
||||||
<a href='https://lens.google.com/uploadbyurl?url=<%- encodeURIComponent(ctx.post.fullContentUrl) %>'>Google Images</a>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='social'>
|
<section class='social'>
|
||||||
|
@ -90,20 +67,20 @@
|
||||||
--><% for (let tag of ctx.post.tags) { %><!--
|
--><% for (let tag of ctx.post.tags) { %><!--
|
||||||
--><li><!--
|
--><li><!--
|
||||||
--><% if (ctx.canViewTags) { %><!--
|
--><% if (ctx.canViewTags) { %><!--
|
||||||
--><a href='<%- ctx.formatClientLink('tag', tag.names[0]) %>' class='<%= ctx.makeCssName(tag.category, 'tag') %>'><!--
|
--><a href='/tag/<%- encodeURIComponent(tag) %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!--
|
||||||
--><i class='fa fa-tag'></i><!--
|
--><i class='fa fa-tag'></i><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><% if (ctx.canViewTags) { %><!--
|
--><% if (ctx.canViewTags) { %><!--
|
||||||
--></a><!--
|
--></a><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><% if (ctx.canListPosts) { %><!--
|
--><% if (ctx.canListPosts) { %><!--
|
||||||
--><a href='<%- ctx.formatClientLink('posts', {query: ctx.escapeTagName(tag.names[0])}) %>' class='<%= ctx.makeCssName(tag.category, 'tag') %>'><!--
|
--><a href='/posts/query=<%- encodeURIComponent(tag) %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><%- ctx.getPrettyName(tag.names[0]) %><!--
|
--><%- tag %> <!--
|
||||||
--><% if (ctx.canListPosts) { %><!--
|
--><% if (ctx.canListPosts) { %><!--
|
||||||
--></a><!--
|
--></a><!--
|
||||||
--><% } %> <!--
|
--><% } %><!--
|
||||||
--><span class='tag-usages' data-pseudo-content='<%- tag.postCount %>'></span><!--
|
--><span class='tag-usages' data-pseudo-content='<%- ctx.getTagUsages(tag) %>'></span><!--
|
||||||
--></li><!--
|
--></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul>
|
--></ul>
|
||||||
|
|
|
@ -7,28 +7,12 @@
|
||||||
|
|
||||||
<span class='skip-duplicates'>
|
<span class='skip-duplicates'>
|
||||||
<%= ctx.makeCheckbox({
|
<%= ctx.makeCheckbox({
|
||||||
text: 'Skip duplicate',
|
text: 'Skip duplicates',
|
||||||
name: 'skip-duplicates',
|
name: 'skip-duplicates',
|
||||||
checked: false,
|
checked: false,
|
||||||
}) %>
|
}) %>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class='always-upload-similar'>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Force upload similar',
|
|
||||||
name: 'always-upload-similar',
|
|
||||||
checked: false,
|
|
||||||
}) %>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class='pause-remain-on-error'>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Pause on error',
|
|
||||||
name: 'pause-remain-on-error',
|
|
||||||
checked: true,
|
|
||||||
}) %>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input type='button' value='Cancel' class='cancel'/>
|
<input type='button' value='Cancel' class='cancel'/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,16 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class='body'>
|
<div class='body'>
|
||||||
<% if (ctx.enableSafety) { %>
|
<div class='safety'>
|
||||||
<div class='safety'>
|
<% for (let safety of ['safe', 'sketchy', 'unsafe']) { %>
|
||||||
<% for (let safety of ['safe', 'sketchy', 'unsafe']) { %>
|
<%= ctx.makeRadio({
|
||||||
<%= ctx.makeRadio({
|
name: 'safety-' + ctx.uploadable.key,
|
||||||
name: 'safety-' + ctx.uploadable.key,
|
value: safety,
|
||||||
value: safety,
|
text: safety[0].toUpperCase() + safety.substr(1),
|
||||||
text: safety[0].toUpperCase() + safety.substr(1),
|
selectedValue: ctx.uploadable.safety,
|
||||||
selectedValue: ctx.uploadable.safety,
|
}) %>
|
||||||
}) %>
|
<% } %>
|
||||||
<% } %>
|
</div>
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<div class='options'>
|
<div class='options'>
|
||||||
<% if (ctx.canUploadAnonymously) { %>
|
<% if (ctx.canUploadAnonymously) { %>
|
||||||
|
@ -61,7 +59,16 @@
|
||||||
text: 'Upload anonymously',
|
text: 'Upload anonymously',
|
||||||
name: 'anonymous',
|
name: 'anonymous',
|
||||||
checked: ctx.uploadable.anonymous,
|
checked: ctx.uploadable.anonymous,
|
||||||
readonly: ctx.uploadable.forceAnonymous,
|
}) %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (['video'].includes(ctx.uploadable.type)) { %>
|
||||||
|
<div class='loop-video'>
|
||||||
|
<%= ctx.makeCheckbox({
|
||||||
|
text: 'Loop video',
|
||||||
|
name: 'loop-video',
|
||||||
|
checked: ctx.uploadable.flags.includes('loop'),
|
||||||
}) %>
|
}) %>
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -1,37 +1,24 @@
|
||||||
<div class='post-list-header'><%
|
<div class='post-list-header'><%
|
||||||
%><form class='horizontal search'><%
|
%><form class='horizontal'><%
|
||||||
%><%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %><%
|
%><%= ctx.makeTextInput({text: 'Search query', id: 'search-text', name: 'search-text', value: ctx.parameters.query}) %><%
|
||||||
%><wbr/><%
|
%><wbr/><%
|
||||||
%><input class='mousetrap' type='submit' value='Search'/><%
|
%><input class='mousetrap' type='submit' value='Search'/><%
|
||||||
%><wbr/><%
|
%><wbr/><%
|
||||||
%><% if (ctx.enableSafety) { %><%
|
%><input data-safety=safe type='button' class='mousetrap safety safety-safe <%- ctx.settings.listPosts.safe ? '' : 'disabled' %>'/><%
|
||||||
%><input data-safety=safe type='button' class='mousetrap safety safety-safe <%- ctx.settings.listPosts.safe ? '' : 'disabled' %>'/><%
|
%><input data-safety=sketchy type='button' class='mousetrap safety safety-sketchy <%- ctx.settings.listPosts.sketchy ? '' : 'disabled' %>'/><%
|
||||||
%><input data-safety=sketchy type='button' class='mousetrap safety safety-sketchy <%- ctx.settings.listPosts.sketchy ? '' : 'disabled' %>'/><%
|
%><input data-safety=unsafe type='button' class='mousetrap safety safety-unsafe <%- ctx.settings.listPosts.unsafe ? '' : 'disabled' %>'/><%
|
||||||
%><input data-safety=unsafe type='button' class='mousetrap safety safety-unsafe <%- ctx.settings.listPosts.unsafe ? '' : 'disabled' %>'/><%
|
|
||||||
%><% } %><%
|
|
||||||
%><wbr/><%
|
%><wbr/><%
|
||||||
%><a class='mousetrap button append' href='<%- ctx.formatClientLink('help', 'search', 'posts') %>'>Syntax help</a><%
|
%><a class='mousetrap button append' href='/help/search/posts'>Syntax help</a><%
|
||||||
|
%><% if (ctx.canMassTag) { %><%
|
||||||
|
%><wbr/><%
|
||||||
|
%><span class='masstag'><%
|
||||||
|
%><span class='append masstag-hint'>Tagging with:</span><%
|
||||||
|
%><a href class='mousetrap button append open-masstag'>Mass tag</a><%
|
||||||
|
%><wbr/><%
|
||||||
|
%><%= ctx.makeTextInput({name: 'masstag', value: ctx.parameters.tag}) %><%
|
||||||
|
%><input class='mousetrap start-tagging' type='submit' value='Start tagging'/><%
|
||||||
|
%><a href class='mousetrap button append stop-tagging'>Stop tagging</a><%
|
||||||
|
%></span><%
|
||||||
|
%><% } %><%
|
||||||
%></form><%
|
%></form><%
|
||||||
%><% if (ctx.canBulkEditTags) { %><%
|
|
||||||
%><form class='horizontal bulk-edit bulk-edit-tags'><%
|
|
||||||
%><span class='append hint'>Tagging with:</span><%
|
|
||||||
%><a href class='mousetrap button append open'>Mass tag</a><%
|
|
||||||
%><%= ctx.makeTextInput({name: 'tag', value: ctx.parameters.tag}) %><%
|
|
||||||
%><input class='mousetrap start' type='submit' value='Start tagging'/><%
|
|
||||||
%><a href class='mousetrap button append close'>Stop tagging</a><%
|
|
||||||
%></form><%
|
|
||||||
%><% } %><%
|
|
||||||
%><% if (ctx.enableSafety && ctx.canBulkEditSafety) { %><%
|
|
||||||
%><form class='horizontal bulk-edit bulk-edit-safety'><%
|
|
||||||
%><a href class='mousetrap button append open'>Mass edit safety</a><%
|
|
||||||
%><a href class='mousetrap button append close'>Stop editing safety</a><%
|
|
||||||
%></form><%
|
|
||||||
%><% } %><%
|
|
||||||
%><% if (ctx.canBulkDelete) { %><%
|
|
||||||
%><form class='horizontal bulk-edit bulk-edit-delete'><%
|
|
||||||
%><a href class='mousetrap button append open'>Mass delete</a><%
|
|
||||||
%><input class='mousetrap start' type='submit' value='Delete selected posts'/><%
|
|
||||||
%><a href class='mousetrap button append close'>Stop deleting</a><%
|
|
||||||
%></form><%
|
|
||||||
%><% } %><%
|
|
||||||
%></div>
|
%></div>
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
<% if (ctx.postFlow) { %><div class='post-list post-flow'><% } else { %><div class='post-list'><% } %>
|
<div class='post-list'>
|
||||||
<% if (ctx.response.results.length) { %>
|
<% if (ctx.results.length) { %>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let post of ctx.response.results) { %>
|
<% for (let post of ctx.results) { %>
|
||||||
<li data-post-id='<%= post.id %>'>
|
<li>
|
||||||
<a class='thumbnail-wrapper <%= post.tags.length > 0 ? "tags" : "no-tags" %>'
|
<a class='thumbnail-wrapper <%= post.tags.length > 0 ? "tags" : "no-tags" %>'
|
||||||
title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag.names[0]).join(' ') || 'none' %>'
|
title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') || 'none' %>'
|
||||||
href='<%= ctx.canViewPosts ? ctx.getPostUrl(post.id, ctx.parameters) : '' %>'>
|
href='<%= ctx.canViewPosts ? ctx.getPostUrl(post.id, ctx.parameters) : "" %>'>
|
||||||
<%= ctx.makeThumbnail(post.thumbnailUrl) %>
|
<%= ctx.makeThumbnail(post.thumbnailUrl) %>
|
||||||
<span class='type' data-type='<%- post.type %>'>
|
<span class='type' data-type='<%- post.type %>'>
|
||||||
<% if (post.type == 'video' || post.type == 'flash' || post.type == 'animation') { %>
|
<%- post.type %>
|
||||||
<span class='icon'><i class='fa fa-film'></i></span>
|
|
||||||
<% } else { %>
|
|
||||||
<%- post.type %>
|
|
||||||
<% } %>
|
|
||||||
</span>
|
</span>
|
||||||
<% if (post.score || post.favoriteCount || post.commentCount) { %>
|
<% if (post.score || post.favoriteCount || post.commentCount) { %>
|
||||||
<span class='stats'>
|
<span class='stats'>
|
||||||
|
@ -37,24 +33,10 @@
|
||||||
</span>
|
</span>
|
||||||
<% } %>
|
<% } %>
|
||||||
</a>
|
</a>
|
||||||
<span class='edit-overlay'>
|
<% if (ctx.canMassTag && ctx.parameters && ctx.parameters.tag) { %>
|
||||||
<% if (ctx.canBulkEditTags && ctx.parameters && ctx.parameters.tag) { %>
|
<a href data-post-id='<%= post.id %>' class='masstag'>
|
||||||
<a href class='tag-flipper'>
|
</a>
|
||||||
</a>
|
<% } %>
|
||||||
<% } %>
|
|
||||||
<% if (ctx.canBulkEditSafety && ctx.parameters && ctx.parameters.safety) { %>
|
|
||||||
<span class='safety-flipper'>
|
|
||||||
<% for (let safety of ['safe', 'sketchy', 'unsafe']) { %>
|
|
||||||
<a href data-safety='<%- safety %>' class='safety-<%- safety %><%- post.safety === safety ? ' active' : '' %>'>
|
|
||||||
</a>
|
|
||||||
<% } %>
|
|
||||||
</span>
|
|
||||||
<% } %>
|
|
||||||
<% if (ctx.canBulkDelete && ctx.parameters && ctx.parameters.delete) { %>
|
|
||||||
<a href class='delete-flipper'>
|
|
||||||
</a>
|
|
||||||
<% } %>
|
|
||||||
</span>
|
|
||||||
</li>
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%= ctx.makeFlexboxAlign() %>
|
<%= ctx.makeFlexboxAlign() %>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<ul class='input'>
|
<ul class='input'>
|
||||||
<li>
|
<li>
|
||||||
<%= ctx.makeCheckbox({
|
<%= ctx.makeCheckbox({
|
||||||
text: "Enable keyboard shortcuts <a class='append icon' href='" + ctx.formatClientLink('help', 'keyboard') + "'><i class='fa fa-question-circle-o'></i></a>",
|
text: "Enable keyboard shortcuts <a class='append icon' href='/help/keyboard'><i class='fa fa-question-circle-o'></i></a>",
|
||||||
name: 'keyboard-shortcuts',
|
name: 'keyboard-shortcuts',
|
||||||
checked: ctx.browsingSettings.keyboardShortcuts,
|
checked: ctx.browsingSettings.keyboardShortcuts,
|
||||||
}) %>
|
}) %>
|
||||||
|
@ -22,15 +22,6 @@
|
||||||
}) %>
|
}) %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Use dark theme',
|
|
||||||
name: 'dark-theme',
|
|
||||||
checked: ctx.browsingSettings.darkTheme,
|
|
||||||
}) %>
|
|
||||||
<p class='hint'>Changing this setting will require you to refresh the page for it to apply.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<%= ctx.makeCheckbox({
|
<%= ctx.makeCheckbox({
|
||||||
text: 'Upscale small posts',
|
text: 'Upscale small posts',
|
||||||
|
@ -47,15 +38,6 @@
|
||||||
<p class='hint'>Rather than using a paged navigation, smoothly scrolls through the content.</p>
|
<p class='hint'>Rather than using a paged navigation, smoothly scrolls through the content.</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Use post flow',
|
|
||||||
name: 'post-flow',
|
|
||||||
checked: ctx.browsingSettings.postFlow,
|
|
||||||
}) %>
|
|
||||||
<p class='hint'>Use a content-aware flow for thumbnails on the post search page.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<%= ctx.makeCheckbox({
|
<%= ctx.makeCheckbox({
|
||||||
text: 'Enable transparency grid',
|
text: 'Enable transparency grid',
|
||||||
|
@ -81,15 +63,6 @@
|
||||||
checked: ctx.browsingSettings.autoplayVideos,
|
checked: ctx.browsingSettings.autoplayVideos,
|
||||||
}) %>
|
}) %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
|
||||||
<%= ctx.makeCheckbox({
|
|
||||||
text: 'Display underscores as spaces',
|
|
||||||
name: 'underscores-as-spaces',
|
|
||||||
checked: ctx.browsingSettings.tagUnderscoresAsSpaces,
|
|
||||||
}) %>
|
|
||||||
<p class='hint'>Display all underscores as if they were spaces. This is only a visual change, which means that you'll still have to use underscores when searching or editing tags.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class='snapshot-list'>
|
<div class='snapshot-list'>
|
||||||
<% if (ctx.response.results.length) { %>
|
<% if (ctx.results.length) { %>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let item of ctx.response.results) { %>
|
<% for (let item of ctx.results) { %>
|
||||||
<li>
|
<li>
|
||||||
<div class='header operation-<%= item.operation %>'>
|
<div class='header operation-<%= item.operation %>'>
|
||||||
<span class='time'>
|
<span class='time'>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<div class='content-wrapper' id='tag'>
|
<div class='content-wrapper' id='tag'>
|
||||||
<h1><%- ctx.getPrettyName(ctx.tag.names[0]) %></h1>
|
<h1><%- ctx.tag.names[0] %></h1>
|
||||||
<nav class='buttons'><!--
|
<nav class='buttons'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li data-name='summary'><a href='<%- ctx.formatClientLink('tag', ctx.tag.names[0]) %>'>Summary</a></li><!--
|
--><li data-name='summary'><a href='/tag/<%- encodeURIComponent(ctx.tag.names[0]) %>'>Summary</a></li><!--
|
||||||
--><% if (ctx.canEditAnything) { %><!--
|
--><% if (ctx.canEditAnything) { %><!--
|
||||||
--><li data-name='edit'><a href='<%- ctx.formatClientLink('tag', ctx.tag.names[0], 'edit') %>'>Edit</a></li><!--
|
--><li data-name='edit'><a href='/tag/<%- encodeURIComponent(ctx.tag.names[0]) %>/edit'>Edit</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><% if (ctx.canMerge) { %><!--
|
--><% if (ctx.canMerge) { %><!--
|
||||||
--><li data-name='merge'><a href='<%- ctx.formatClientLink('tag', ctx.tag.names[0], 'merge') %>'>Merge with…</a></li><!--
|
--><li data-name='merge'><a href='/tag/<%- encodeURIComponent(ctx.tag.names[0]) %>/merge'>Merge with…</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><% if (ctx.canDelete) { %><!--
|
--><% if (ctx.canDelete) { %><!--
|
||||||
--><li data-name='delete'><a href='<%- ctx.formatClientLink('tag', ctx.tag.names[0], 'delete') %>'>Delete</a></li><!--
|
--><li data-name='delete'><a href='/tag/<%- encodeURIComponent(ctx.tag.names[0]) %>/delete'>Delete</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul><!--
|
--></ul><!--
|
||||||
--></nav>
|
--></nav>
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
<div class='content-wrapper tag-categories'>
|
<div class='content-wrapper tag-categories'>
|
||||||
<form>
|
<form>
|
||||||
<h1>Tag categories</h1>
|
<h1>Tag categories</h1>
|
||||||
<div class="table-wrap">
|
<table>
|
||||||
<table>
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th class='name'>Category name</th>
|
||||||
<th class='name'>Category name</th>
|
<th class='color'>CSS color</th>
|
||||||
<th class='color'>CSS color</th>
|
<th class='usages'>Usages</th>
|
||||||
<th class='order'>Order</th>
|
</tr>
|
||||||
<th class='usages'>Usages</th>
|
</thead>
|
||||||
</tr>
|
<tbody>
|
||||||
</thead>
|
</tbody>
|
||||||
<tbody>
|
</table>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if (ctx.canCreate) { %>
|
<% if (ctx.canCreate) { %>
|
||||||
<p><a href class='add'>Add new category</a></p>
|
<p><a href class='add'>Add new category</a></p>
|
||||||
|
@ -22,7 +19,7 @@
|
||||||
|
|
||||||
<div class='messages'></div>
|
<div class='messages'></div>
|
||||||
|
|
||||||
<% if (ctx.canCreate || ctx.canEditName || ctx.canEditColor || ctx.canEditOrder || ctx.canDelete) { %>
|
<% if (ctx.canCreate || ctx.canEditName || ctx.canEditColor || ctx.canDelete) { %>
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<input type='submit' class='save' value='Save changes'>
|
<input type='submit' class='save' value='Save changes'>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,16 +17,9 @@
|
||||||
<%- ctx.tagCategory.color %>
|
<%- ctx.tagCategory.color %>
|
||||||
<% } %>
|
<% } %>
|
||||||
</td>
|
</td>
|
||||||
<td class='order'>
|
|
||||||
<% if (ctx.canEditOrder) { %>
|
|
||||||
<%= ctx.makeNumericInput({value: ctx.tagCategory.order}) %>
|
|
||||||
<% } else { %>
|
|
||||||
<%- ctx.tagCategory.order %>
|
|
||||||
<% } %>
|
|
||||||
</td>
|
|
||||||
<td class='usages'>
|
<td class='usages'>
|
||||||
<% if (ctx.tagCategory.name) { %>
|
<% if (ctx.tagCategory.name) { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'category:' + ctx.tagCategory.name}) %>'>
|
<a href='/tags/query=category:<%- encodeURIComponent(ctx.tagCategory.name) %>'>
|
||||||
<%- ctx.tagCategory.tagCount %>
|
<%- ctx.tagCategory.tagCount %>
|
||||||
</a>
|
</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class='tag-delete'>
|
<div class='tag-delete'>
|
||||||
<form>
|
<form>
|
||||||
<p>This tag has <a href='<%- ctx.formatClientLink('posts', {query: ctx.escapeTagName(ctx.tag.names[0])}) %>'><%- ctx.tag.postCount %> usage(s)</a>.</p>
|
<p>This tag has <a href='/posts/query=<%- encodeURIComponent(ctx.tag.names[0]) %>'><%- ctx.tag.postCount %> usage(s)</a>.</p>
|
||||||
|
|
||||||
<ul class='input'>
|
<ul class='input'>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -22,12 +22,18 @@
|
||||||
</li>
|
</li>
|
||||||
<li class='implications'>
|
<li class='implications'>
|
||||||
<% if (ctx.canEditImplications) { %>
|
<% if (ctx.canEditImplications) { %>
|
||||||
<%= ctx.makeTextInput({text: 'Implications'}) %>
|
<%= ctx.makeTextInput({
|
||||||
|
text: 'Implications',
|
||||||
|
value: ctx.tag.implications.join(' '),
|
||||||
|
}) %>
|
||||||
<% } %>
|
<% } %>
|
||||||
</li>
|
</li>
|
||||||
<li class='suggestions'>
|
<li class='suggestions'>
|
||||||
<% if (ctx.canEditSuggestions) { %>
|
<% if (ctx.canEditSuggestions) { %>
|
||||||
<%= ctx.makeTextInput({text: 'Suggestions'}) %>
|
<%= ctx.makeTextInput({
|
||||||
|
text: 'Suggestions',
|
||||||
|
value: ctx.tag.suggestions.join(' '),
|
||||||
|
}) %>
|
||||||
<% } %>
|
<% } %>
|
||||||
</li>
|
</li>
|
||||||
<li class='description'>
|
<li class='description'>
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
<form>
|
<form>
|
||||||
<ul class='input'>
|
<ul class='input'>
|
||||||
<li class='target'>
|
<li class='target'>
|
||||||
<%= ctx.makeTextInput({name: 'target-tag', required: true, text: 'Target tag', pattern: ctx.tagNamePattern}) %>
|
<%= ctx.makeTextInput({required: true, text: 'Target tag', pattern: ctx.tagNamePattern}) %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<p>Usages in posts, suggestions and implications will be
|
<p>Usages in posts, suggestions and implications will be
|
||||||
merged. Category needs to be handled manually.</p>
|
merged. Category and aliases need to be handled manually.</p>
|
||||||
|
|
||||||
<%= ctx.makeCheckbox({name: 'alias', text: 'Make this tag an alias of the target tag.'}) %>
|
|
||||||
|
|
||||||
<%= ctx.makeCheckbox({required: true, text: 'I confirm that I want to merge this tag.'}) %>
|
<%= ctx.makeCheckbox({required: true, text: 'I confirm that I want to merge this tag.'}) %>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
Aliases:<br/>
|
Aliases:<br/>
|
||||||
<ul><!--
|
<ul><!--
|
||||||
--><% for (let name of ctx.tag.names.slice(1)) { %><!--
|
--><% for (let name of ctx.tag.names.slice(1)) { %><!--
|
||||||
--><li><%= ctx.makeTagLink(name, false, false, ctx.tag) %></li><!--
|
--><li><%= ctx.makeTagLink(name) %></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul>
|
--></ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
Implications:<br/>
|
Implications:<br/>
|
||||||
<ul><!--
|
<ul><!--
|
||||||
--><% for (let tag of ctx.tag.implications) { %><!--
|
--><% for (let tag of ctx.tag.implications) { %><!--
|
||||||
--><li><%= ctx.makeTagLink(tag.names[0], false, false, tag) %></li><!--
|
--><li><%= ctx.makeTagLink(tag) %></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul>
|
--></ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
Suggestions:<br/>
|
Suggestions:<br/>
|
||||||
<ul><!--
|
<ul><!--
|
||||||
--><% for (let tag of ctx.tag.suggestions) { %><!--
|
--><% for (let tag of ctx.tag.suggestions) { %><!--
|
||||||
--><li><%= ctx.makeTagLink(tag.names[0], false, false, tag) %></li><!--
|
--><li><%= ctx.makeTagLink(tag) %></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul>
|
--></ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -36,6 +36,6 @@
|
||||||
<section class='description'>
|
<section class='description'>
|
||||||
<hr/>
|
<hr/>
|
||||||
<%= ctx.makeMarkdown(ctx.tag.description || 'This tag has no description yet.') %>
|
<%= ctx.makeMarkdown(ctx.tag.description || 'This tag has no description yet.') %>
|
||||||
<p>This tag has <a href='<%- ctx.formatClientLink('posts', {query: ctx.escapeTagName(ctx.tag.names[0])}) %>'><%- ctx.tag.postCount %> usage(s)</a>.</p>
|
<p>This tag has <a href='/posts/query=<%- encodeURIComponent(ctx.tag.names[0]) %>'><%- ctx.tag.postCount %> usage(s)</a>.</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<input type='submit' value='Search'/>
|
<input type='submit' value='Search'/>
|
||||||
<a class='button append' href='<%- ctx.formatClientLink('help', 'search', 'tags') %>'>Syntax help</a>
|
<a class='button append' href='/help/search/tags'>Syntax help</a>
|
||||||
<% if (ctx.canEditTagCategories) { %>
|
<% if (ctx.canEditTagCategories) { %>
|
||||||
<a class='append' href='<%- ctx.formatClientLink('tag-categories') %>'>Tag categories</a>
|
<a class='append' href='/tag-categories'>Tag categories</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,58 +1,58 @@
|
||||||
<div class='tag-list table-wrap'>
|
<div class='tag-list'>
|
||||||
<% if (ctx.response.results.length) { %>
|
<% if (ctx.results.length) { %>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<th class='names'>
|
<th class='names'>
|
||||||
<% if (ctx.parameters.query == 'sort:name' || !ctx.parameters.query) { %>
|
<% if (ctx.query == 'sort:name' || !ctx.query) { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: '-sort:name'}) %>'>Tag name(s)</a>
|
<a href='/tags/query=-sort:name'>Tag name(s)</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'sort:name'}) %>'>Tag name(s)</a>
|
<a href='/tags/query=sort:name'>Tag name(s)</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</th>
|
</th>
|
||||||
<th class='implications'>
|
<th class='implications'>
|
||||||
<% if (ctx.parameters.query == 'sort:implication-count') { %>
|
<% if (ctx.query == 'sort:implication-count') { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: '-sort:implication-count'}) %>'>Implications</a>
|
<a href='/tags/query=-sort:implication-count'>Implications</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'sort:implication-count'}) %>'>Implications</a>
|
<a href='/tags/query=sort:implication-count'>Implications</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</th>
|
</th>
|
||||||
<th class='suggestions'>
|
<th class='suggestions'>
|
||||||
<% if (ctx.parameters.query == 'sort:suggestion-count') { %>
|
<% if (ctx.query == 'sort:suggestion-count') { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: '-sort:suggestion-count'}) %>'>Suggestions</a>
|
<a href='/tags/query=-sort:suggestion-count'>Suggestions</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'sort:suggestion-count'}) %>'>Suggestions</a>
|
<a href='/tags/query=sort:suggestion-count'>Suggestions</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</th>
|
</th>
|
||||||
<th class='usages'>
|
<th class='usages'>
|
||||||
<% if (ctx.parameters.query == 'sort:usages') { %>
|
<% if (ctx.query == 'sort:usages') { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: '-sort:usages'}) %>'>Usages</a>
|
<a href='/tags/query=-sort:usages'>Usages</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'sort:usages'}) %>'>Usages</a>
|
<a href='/tags/query=sort:usages'>Usages</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</th>
|
</th>
|
||||||
<th class='creation-time'>
|
<th class='creation-time'>
|
||||||
<% if (ctx.parameters.query == 'sort:creation-time') { %>
|
<% if (ctx.query == 'sort:creation-time') { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: '-sort:creation-time'}) %>'>Created on</a>
|
<a href='/tags/query=-sort:creation-time'>Created on</a>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<a href='<%- ctx.formatClientLink('tags', {query: 'sort:creation-time'}) %>'>Created on</a>
|
<a href='/tags/query=sort:creation-time'>Created on</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</th>
|
</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% for (let tag of ctx.response.results) { %>
|
<% for (let tag of ctx.results) { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td class='names'>
|
<td class='names'>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let name of tag.names) { %>
|
<% for (let name of tag.names) { %>
|
||||||
<li><%= ctx.makeTagLink(name, false, false, tag) %></li>
|
<li><%= ctx.makeTagLink(name) %></li>
|
||||||
<% } %>
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
<td class='implications'>
|
<td class='implications'>
|
||||||
<% if (tag.implications.length) { %>
|
<% if (tag.implications.length) { %>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let relation of tag.implications) { %>
|
<% for (let name of tag.implications) { %>
|
||||||
<li><%= ctx.makeTagLink(relation.names[0], false, false, relation) %></li>
|
<li><%= ctx.makeTagLink(name) %></li>
|
||||||
<% } %>
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
@ -62,8 +62,8 @@
|
||||||
<td class='suggestions'>
|
<td class='suggestions'>
|
||||||
<% if (tag.suggestions.length) { %>
|
<% if (tag.suggestions.length) { %>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let relation of tag.suggestions) { %>
|
<% for (let name of tag.suggestions) { %>
|
||||||
<li><%= ctx.makeTagLink(relation.names[0], false, false, relation) %></li>
|
<li><%= ctx.makeTagLink(name) %></li>
|
||||||
<% } %>
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
<nav id='top-navigation' class='buttons'><!--
|
<nav id='top-navigation' class='buttons'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><button id="mobile-navigation-toggle"><!--
|
|
||||||
--><span class="site-name"><%- ctx.name %></span><!--
|
|
||||||
--><span class="toggle-icon"><i class="fa fa-bars"></i></span><!--
|
|
||||||
--></button><!--
|
|
||||||
--><% for (let item of ctx.items) { %><!--
|
--><% for (let item of ctx.items) { %><!--
|
||||||
--><% if (item.available) { %><!--
|
--><% if (item.available) { %><!--
|
||||||
--><li data-name='<%- item.key %>'><!--
|
--><li data-name='<%- item.key %>'><!--
|
||||||
|
|
|
@ -2,15 +2,12 @@
|
||||||
<h1><%- ctx.user.name %></h1>
|
<h1><%- ctx.user.name %></h1>
|
||||||
<nav class='buttons'><!--
|
<nav class='buttons'><!--
|
||||||
--><ul><!--
|
--><ul><!--
|
||||||
--><li data-name='summary'><a href='<%- ctx.formatClientLink('user', ctx.user.name) %>'>Summary</a></li><!--
|
--><li data-name='summary'><a href='/user/<%- encodeURIComponent(ctx.user.name) %>'>Summary</a></li><!--
|
||||||
--><% if (ctx.canEditAnything) { %><!--
|
--><% if (ctx.canEditAnything) { %><!--
|
||||||
--><li data-name='edit'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'edit') %>'>Settings</a></li><!--
|
--><li data-name='edit'><a href='/user/<%- encodeURIComponent(ctx.user.name) %>/edit'>Account settings</a></li><!--
|
||||||
--><% } %><!--
|
|
||||||
--><% if (ctx.canListTokens) { %><!--
|
|
||||||
--><li data-name='list-tokens'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'list-tokens') %>'>Login tokens</a></li><!--
|
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--><% if (ctx.canDelete) { %><!--
|
--><% if (ctx.canDelete) { %><!--
|
||||||
--><li data-name='delete'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'delete') %>'>Delete</a></li><!--
|
--><li data-name='delete'><a href='/user/<%- encodeURIComponent(ctx.user.name) %>/delete'>Account deletion</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
--></ul><!--
|
--></ul><!--
|
||||||
--></nav>
|
--></nav>
|
||||||
|
|
|
@ -51,6 +51,6 @@
|
||||||
<li><i class='fa fa-star-half-o'></i> vote up/down on posts and comments</li>
|
<li><i class='fa fa-star-half-o'></i> vote up/down on posts and comments</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr/>
|
<hr/>
|
||||||
<p>By creating an account, you are agreeing to the <a href='<%- ctx.formatClientLink('help', 'tos') %>'>Terms of Service</a>.</p>
|
<p>By creating an account, you are agreeing to the <a href='/help/tos'>Terms of Service</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
<nav>
|
<nav>
|
||||||
<p><strong>Quick links</strong></p>
|
<p><strong>Quick links</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href='<%- ctx.formatClientLink('posts', {query: 'submit:' + ctx.user.name}) %>'><%- ctx.user.uploadedPostCount %> uploads</a></li>
|
<li><a href='/posts/query=submit:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.uploadedPostCount %> uploads</a></li>
|
||||||
<li><a href='<%- ctx.formatClientLink('posts', {query: 'fav:' + ctx.user.name}) %>'><%- ctx.user.favoritePostCount %> favorites</a></li>
|
<li><a href='/posts/query=fav:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.favoritePostCount %> favorites</a></li>
|
||||||
<li><a href='<%- ctx.formatClientLink('posts', {query: 'comment:' + ctx.user.name}) %>'><%- ctx.user.commentCount %> comments</a></li>
|
<li><a href='/posts/query=comment:<%- encodeURIComponent(ctx.user.name) %>'><%- ctx.user.commentCount %> comments</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@
|
||||||
<nav>
|
<nav>
|
||||||
<p><strong>Only visible to you</strong></p>
|
<p><strong>Only visible to you</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href='<%- ctx.formatClientLink('posts', {query: 'special:liked'}) %>'><%- ctx.user.likedPostCount %> liked posts</a></li>
|
<li><a href='/posts/query=special:liked'><%- ctx.user.likedPostCount %> liked posts</a></li>
|
||||||
<li><a href='<%- ctx.formatClientLink('posts', {query: 'special:disliked'}) %>'><%- ctx.user.dislikedPostCount %> disliked posts</a></li>
|
<li><a href='/posts/query=special:disliked'><%- ctx.user.dislikedPostCount %> disliked posts</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
<div id='user-tokens'>
|
|
||||||
<div class='messages'></div>
|
|
||||||
<% if (ctx.tokens.length > 0) { %>
|
|
||||||
<div class='token-flex-container'>
|
|
||||||
<% _.each(ctx.tokens, function(token, index) { %>
|
|
||||||
<div class='token-flex-row'>
|
|
||||||
<div class='token-flex-column token-flex-labels'>
|
|
||||||
<div class='token-flex-row'>Token:</div>
|
|
||||||
<div class='token-flex-row'>Note:</div>
|
|
||||||
<div class='token-flex-row'>Created:</div>
|
|
||||||
<div class='token-flex-row'>Expires:</div>
|
|
||||||
<div class='token-flex-row no-wrap'>Last used:</div>
|
|
||||||
</div>
|
|
||||||
<div class='token-flex-column full-width'>
|
|
||||||
<div class='token-flex-row'><%= token.token %></div>
|
|
||||||
<div class='token-flex-row'>
|
|
||||||
<% if (token.note !== null) { %>
|
|
||||||
<%= token.note %>
|
|
||||||
<% } else { %>
|
|
||||||
No note
|
|
||||||
<% } %>
|
|
||||||
<a class='token-change-note' data-token-id='<%= index %>' href='#'>(change)</a>
|
|
||||||
</div>
|
|
||||||
<div class='token-flex-row'><%= ctx.makeRelativeTime(token.creationTime) %></div>
|
|
||||||
<div class='token-flex-row'>
|
|
||||||
<% if (token.expirationTime) { %>
|
|
||||||
<%= ctx.makeRelativeTime(token.expirationTime) %>
|
|
||||||
<% } else { %>
|
|
||||||
No expiration
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
<div class='token-flex-row'><%= ctx.makeRelativeTime(token.lastUsageTime) %></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='token-flex-row'>
|
|
||||||
<div class='token-flex-column full-width'>
|
|
||||||
<div class='token-flex-row'>
|
|
||||||
<form class='token' data-token-id='<%= index %>'>
|
|
||||||
<% if (token.isCurrentAuthToken) { %>
|
|
||||||
<input type='submit' value='Delete and logout'
|
|
||||||
title='This token is used to authenticate this client, deleting it will force a logout.'/>
|
|
||||||
<% } else { %>
|
|
||||||
<input type='submit' value='Delete'/>
|
|
||||||
<% } %>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<% }); %>
|
|
||||||
</div>
|
|
||||||
<% } else { %>
|
|
||||||
<h2>No Registered Tokens</h2>
|
|
||||||
<% } %>
|
|
||||||
<form id='create-token-form'>
|
|
||||||
<ul class='input'>
|
|
||||||
<li class='note'>
|
|
||||||
<%= ctx.makeTextInput({
|
|
||||||
text: 'Note',
|
|
||||||
id: 'note',
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
<li class='expirationTime'>
|
|
||||||
<%= ctx.makeDateInput({
|
|
||||||
text: 'Expires',
|
|
||||||
id: 'expirationTime',
|
|
||||||
}) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class='buttons'>
|
|
||||||
<input type='submit' value='Create token'/>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<input type='submit' value='Search'/>
|
<input type='submit' value='Search'/>
|
||||||
<a class='append' href='<%- ctx.formatClientLink('help', 'search', 'users') %>'>Syntax help</a>
|
<a class='append' href='/help/search/users'>Syntax help</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class='user-list'>
|
<div class='user-list'>
|
||||||
<ul><!--
|
<ul><!--
|
||||||
--><% for (let user of ctx.response.results) { %><!--
|
--><% for (let user of ctx.results) { %><!--
|
||||||
--><li>
|
--><li>
|
||||||
<div class='wrapper'>
|
<div class='wrapper'>
|
||||||
<% if (ctx.canViewUsers) { %>
|
<% if (ctx.canViewUsers) { %>
|
||||||
<a class='image' href='<%- ctx.formatClientLink('user', user.name) %>'>
|
<a class='image' href='/user/<%- encodeURIComponent(user.name) %>'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%= ctx.makeThumbnail(user.avatarUrl) %>
|
<%= ctx.makeThumbnail(user.avatarUrl) %>
|
||||||
<% if (ctx.canViewUsers) { %>
|
<% if (ctx.canViewUsers) { %>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<% } %>
|
<% } %>
|
||||||
<div class='details'>
|
<div class='details'>
|
||||||
<% if (ctx.canViewUsers) { %>
|
<% if (ctx.canViewUsers) { %>
|
||||||
<a href='<%- ctx.formatClientLink('user', user.name) %>'>
|
<a href='/user/<%- encodeURIComponent(user.name) %>'>
|
||||||
<% } %>
|
<% } %>
|
||||||
<%- user.name %>
|
<%- user.name %>
|
||||||
<% if (ctx.canViewUsers) { %>
|
<% if (ctx.canViewUsers) { %>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 113 KiB |
Binary file not shown.
Before Width: | Height: | Size: 113 KiB |
BIN
client/img/transparency_grid.png
Normal file
BIN
client/img/transparency_grid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 B |
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue