Compare commits

..

3 Commits

Author SHA1 Message Date
90c42d2e64 Update version.txt
All checks were successful
Release build and push docker image / build-and-push-release (push) Successful in 4m30s
2024-10-14 17:00:05 +00:00
7cd3f9ef3a Add .github/actions/common-docker-build/action.yml 2024-10-14 16:59:53 +00:00
a44e2e6635 Update .github/workflows/master.yml 2024-10-14 16:59:29 +00:00
462 changed files with 4169 additions and 42138 deletions

View File

@ -1,27 +1,17 @@
.DS_Store
.idea
*.iws
*.iml
*.ipr
out/
/data/uploads/*
!/data/uploads/.gitkeep
/data/db/*
!/data/db/.gitkeep
data/uploads/*
!data/uploads/sample.jpg
data/db/*
!data/db/slideshow.json.dist
/plugins/user/*
!/plugins/user/.gitkeep
*.lock
__pycache__/
*.log
/var/run/*
!/var/run/.gitkeep
*.swp
var/run/*
!var/run/.gitkeep
.env
venv/
node_modules
tmp.py
!/plugins/user/Dashboard
/data/www/plugins/*
!/data/www/plugins/.gitkeep
/var/run/storage/*
!/var/run/storage/.gitkeep

View File

@ -1,11 +1,4 @@
# Core
DEBUG=false
SECRET_KEY=ANY_SECRET_KEY_HERE
# Application Server
PORT=5000
BIND=0.0.0.0
EXTERNAL_STORAGE_MOUNTPOINT=%application_dir%/var/run/storage
# Misc
DEMO=false
SECRET_KEY=ANY_SECRET_KEY_HERE
AUTOCONFIGURE_LX_FILE=/home/pi/.config/lxsession/LXDE-pi/autostart # Replace by "/dev/null" if not needed

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
custom: https://paypal.me/jierka

View File

@ -1,46 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] "
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Hardware (please complete the following information):**
- *Device*: `Raspberry Xb+`
- *OS*: `Raspbian vXX` [use command *lsb_release -a*]
- *Architecture*: `armvX` [use command *uname -a*]
**Sofware (please complete the following information):**
- *Obscreen version*: `v1.XX`
- *Installation method*: `Docker` or `System`
- *Browser*: `Chromium` or `Chrome`
- *Player method*: `Systemd with obscreen-player.service` or `Manually`
**Additional context**
Add any other context about the problem here.
**Extra (Recommended)**
You can send us a backup of your data to help speed up the debugging process. Please ensure that no sensitive data is included in your slides and follow these steps:
```bash
cd obscreen
tar -vcf data.tar data/
```
Afterward, attach the `data.tar` file to your issue attachment.

View File

@ -1,21 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE] "
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

0
.github/actions/common-docker-build/action.yml vendored Executable file → Normal file
View File

View File

@ -1,41 +0,0 @@
name: Nightly build synced with develop and push docker image
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
build-and-push-nightly:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
ref: develop
- name: Set up Git
run: |
git config --global user.name 'github-actions'
git config --global user.email 'github-actions@github.com'
- name: Sync nightly branch
run: |
git checkout nightly
git merge develop --no-edit
git push origin nightly --force
- name: Checkout nightly branch
uses: actions/checkout@v2
with:
ref: nightly
- name: Call common build workflow
uses: ./.github/actions/common-docker-build
with:
build_tags: csmith1865/obscreen:nightly
manifest_tags: type=semver,pattern=nightly
flavor: ""
docker_username: ${{ secrets.DOCKER_USERNAME }}
docker_password: ${{ secrets.DOCKER_PASSWORD }}

View File

@ -1,28 +0,0 @@
name: PR build and push docker image
on:
pull_request:
types: [opened, synchronize, labeled]
push:
branches-ignore:
- master
- develop
- nightly
workflow_dispatch:
jobs:
build-and-push-pr:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.labels.*.name, 'build-pr')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Call common build workflow
uses: ./.github/actions/common-docker-build
with:
build_tags: csmith1865/obscreen:pr-${{ github.event.pull_request.number }}
manifest_tags: type=semver,pattern=pr
flavor: ""
docker_username: ${{ secrets.DOCKER_USERNAME }}
docker_password: ${{ secrets.DOCKER_PASSWORD }}

24
.gitignore vendored
View File

@ -1,30 +1,18 @@
.DS_Store
.idea
*.iws
*.iml
*.ipr
out/
/data/uploads/*
!/data/uploads/.gitkeep
/data/db/*
!/data/db/.gitkeep
data/uploads/*
!data/uploads/sample.jpg
data/db/*
!data/db/slideshow.json.dist
/plugins/user/*
!/plugins/user/.gitkeep
*.lock
__pycache__/
*.log
/var/run/*
!/var/run/.gitkeep
var/run/*
!var/run/.gitkeep
*.swp
.env
venv/
node_modules
tmp.py
!/plugins/user/Dashboard
/data/www/plugins/*
!/data/www/plugins/.gitkeep
/var/run/storage/*
!/var/run/storage/.gitkeep
*.egg-info
/build/
/dist/

View File

@ -1,24 +1,12 @@
FROM python:3.9-slim-bullseye
FROM python:3.9.17-alpine3.17
# Install ffmpeg and other dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libc6-dev \
sqlite3 \
libsqlite3-dev \
ntfs-3g \
ffmpeg \
build-essential \
curl \
tar \
bash \
&& rm -rf /var/lib/apt/lists/*
RUN apk add --no-cache git chromium \
&& apk add --no-cache --virtual .build-deps git gcc musl-dev
WORKDIR /app
COPY . .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install -r requirements.txt && apk del .build-deps gcc musl-dev
ENTRYPOINT ["python", "/app/obscreen.py"]

View File

@ -1,4 +0,0 @@
include README.md
include LICENSE
docs/setup-run-on-rpi.md
docs/setup-run-headless.md

190
README.md
View File

@ -1,120 +1,124 @@
<div align="center" width="100%">
<img src="./docs/img/obscreen.png" width="128" alt="" />
</div>
# <img src="https://github.com/jr-k/obscreen/blob/master/docs/obscreen.png" width="22"> Obscreen
# Obscreen
🧑‍🎄 Open to feature request and pull request
Obscreen is a user-friendly self-hosted digital signage tool leveraging chromium browser.
**⭐️ You liked it ? Give this repository a star, it's free :)**
<a target="_blank" href="https://git.sumisu.xyz/csmith1865/obscreen"><img src="https://img.shields.io/gitea/stars/csmith1865/obscreen?gitea_url=https%3A%2F%2Fgit.sumisu.xyz&style=flat" /></a> <a target="_blank" href="https://hub.docker.com/r/csmith1865/obscreen"><img src="https://img.shields.io/docker/pulls/csmith1865/obscreen" /></a> <a target="_blank" href="https://hub.docker.com/r/csmith1865/obscreen"><img src="https://img.shields.io/docker/v/csmith1865/obscreen/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://git.sumisu.xyz/csmith1865/obscreen"><img src="https://img.shields.io/gitea/last-commit/csmith1865/obscreen?gitea_url=https%3A%2F%2Fgit.sumisu.xyz&style=flat" /></a>
## About
Use a RaspberryPi to show a full-screen slideshow (Kiosk-mode)
<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/screenshot-playlist-edit.png" width="700" alt="" />
[![Docker Pulls](https://badgen.net/docker/pulls/jierka/obscreen?icon=docker&label=docker%20pulls)](https://hub.docker.com/r/jierka/obscreen/)
🧑‍🎄 Open to feature request and pull request. [Cast your vote for your preferred ones on the Canny platform](https://obscreen.canny.io/feature-requests)
⭐️ You liked it ? Give this repository a star, it's free :)
---
## 🕹️ Live Demo
Try it!
Demo Server (Location: Roubaix - France): [https://demo.obscreen.io](https://demo.obscreen.io/login?username=admin&password=admin)
It is a temporary live demo, all data will be deleted after 30 minutes (~30secs downtime).
## 🎉 Features
- Dead simple chromium webview inside
- Fancy graphical user interface
### Features:
- Dead simple chromium webview
- Clear GUI
- Fleet view to manage many devices easily
- Very few dependencies
- Embeddable SQLite database
- Fleet screen management
- Playlist management
- Authentication management
- Plays content from flashdrive in offline mode
- Core API & Plugin system to extend capabilities
- [Multi Languages](https://git.sumisu.xyz/csmith1865/obscreen/src/branch/master/lang)
- Cast pictures and iframes to Chromecast
- No costly monthly pricing plan per screen or whatever, no cloud, no telemetry
- JSON database files
- Plugin system
- No stupid pricing plan
- No cloud
- No telemetry
## 👨‍🍳 How to install
![Obscreen Screenshot](https://github.com/jr-k/obscreen/blob/master/docs/screenshot.png "Obscreen Screenshot")
### 🔴 [I want to power a RaspberryPi and automatically see my slideshow on a screen connected to it and manage the slideshow](docs/setup-run-on-rpi.md)
### 🔵 [I just want a slideshow manager and I'll deal with screen and browser myself](docs/setup-run-headless.md)
## 🐳 Run with docker
### With docker (for test)
```bash
# Prepare application data file tree
mkdir -p obscreen/data/db obscreen/data/uploads && cd obscreen
## 📸 More Screenshots
# Run the Docker container
# 🚨 If you ARE NOT on a RaspberryPi
# - replace '/home/pi/.config/lxsession/LXDE-pi/autostart' with '/dev/null'
# 🚨 Else make sure that
# - file '/home/pi/.config/lxsession/LXDE-pi/autostart' exists and is writeable
docker run --rm --name obscreen --pull=always \
-e DEBUG=false \
-e PORT=5000 \
-e AUTOCONFIGURE_LX_FILE=/app/var/run/lxfile \
-e SECRET_KEY=ANY_SECRET_KEY_HERE \
-p 5000:5000 \
-v ./data/db:/app/data/db \
-v ./data/uploads:/app/data/uploads \
-v /home/pi/.config/lxsession/LXDE-pi/autostart:/app/var/run/lxfile \
jierka/obscreen:latest
```
Light Mode:
### With docker-compose
```bash
# Prepare application data file tree
mkdir -p obscreen/data/db obscreen/data/uploads && cd obscreen
<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/screenshot-light-mode.png" width="512" alt="" />
# Download docker-compose.yml
# 🚨 If you ARE NOT on a RaspberryPi
curl https://raw.githubusercontent.com/jr-k/obscreen/master/docker-compose.norpi.yml > docker-compose.yml
# 🚨 If you ARE on a RaspberryPi
curl https://raw.githubusercontent.com/jr-k/obscreen/master/docker-compose.yml > docker-compose.yml
Content Explorer:
# Run
docker compose up
```
<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/screenshot-content-explorer.png" width="512" alt="" />
## 📠 Run system wide
### Install
```bash
# Install system dependencies
sudo apt-get update
sudo apt-get install -y git chromium-browser unclutter
Settings Page:
# Get files
git clone https://github.com/jr-k/obscreen.git && cd obscreen
<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/screenshot-settings.png" width="512" alt="" />
# Install application dependencies
pip3 install -r requirements.txt
Add Content Modal:
# Add some sample data
cp data/db/slideshow.json.dist data/db/slideshow.json
<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/screenshot-add-content.png" width="512" alt="" />
# Customize server default values
cp .env.dist .env
```
## 🫡 Motivation
### Configure
- Server configuration is editable in `.env` file.
- Application configuration is available in `http://localhost:5000/settings` page.
- I was searching for a self-hosted monitoring tool similar to "Screenly", but struggled with "Anthias" (formerly Screenly OSE) due to compatibility issues on some webpages. Chromium does a great job at rendering webpages, so I decided to create my own solution based on browsers.
- Enjoy a beautiful graphical interface
- My goal was to keep the code as simple as possible, using reliable technology with minimal dependencies.
- Aim to showcase the power of the Raspberry Pi 5.
- Deploy my first true Docker image to Docker Hub using a continuous deployment pipeline.
### Start server (for test)
```bash
./obscreen.py
```
If you value this project, please think about awarding it a ⭐. Thanks ! 🙏
### Start server forever with systemctl
```bash
sudo ln -s "$(pwd)/system/obscreen.service" /etc/systemd/system/obscreen.service
sudo systemctl daemon-reload
sudo systemctl enable obscreen.service
sudo systemctl start obscreen.service
```
## 🗺️ Short-term roadmap
- New `Composition` content type: Check out a [video demo here](https://demo.obscreen.io/data/uploads/compositions.mp4)
- New `Text` Content Type: Display text with customizable styles, including options for scrolling effects.
- New `HTML` Content Type: Display HTML snippets for more powerful text customization, giving you full control over the content.
- Fleet Studio Management: Reviving a legacy feature
- Remote Player Server: A new way to manage a player from the studio without needing SSH access to player
To troubleshoot you can check logs
```bash
sudo journalctl -u obscreen -f
```
## 🛟 Discussion / Need help ?
## 👌 Usage
- Page which plays slideshow is reachable at `http://localhost:5000`
- Slideshow manager is reachable at `http://localhost:5000/manage`
### Join our Discord
[<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/img/discord.png" width="64">](https://discord.obscreen.io)
## ✨ You are done now :)
- If everything is set up correctly, the RaspberryPi shall start chromium in fullscreen directly after boot screen and after some seconds of showing the date & time (`views/player/default.jinja.html`) your slideshow shall start and loop endlessly.
- Make sure that `AUTOCONFIGURE_LX_FILE` exists and is writeable !
### Open an Issue
[<img src="https://git.sumisu.xyz/csmith1865/obscreen/raw/branch/master/docs/img/github.png" width="64">](https://git.sumisu.xyz/csmith1865/obscreen/issues/new/choose)
## 📎 Additional
### Troubleshoot
### Hardware checks
- Basic Setup
For basic RaspberryPi setup you can use most of the available guides, for example this one:
https://gist.github.com/blackjid/dfde6bedef148253f987
- HDMI Mode
You may need to set the HDMI Mode on the raspi to ensure the hdmi resolution matches your screen exactly. Here is the official documentation:
https://www.raspberrypi.org/documentation/configuration/config-txt/video.md
<details closed>
<summary><h3>Why aren't the videos starting?</h3></summary>
This is "normal" behavior. Videos do not play automatically in Chrome because it requires user interaction with the page (a simple click inside the webpage is enough). If you open the console, you'll see the error: [Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first...](https://goo.gl/xX8pDD)
To resolve this, you need to use the Chrome flag `--autoplay-policy=no-user-gesture-required`. When connecting a Raspberry Pi with Obscreen Player autorun, this issue doesn't occur because the flag is handled automatically for you. You need to enable this flag yourself otherwise.
---
</details>
## 👑 Contributions
### Create Pull Requests
We accept all types of pull requests.
### Test Beta Version
Check out the latest beta release here: https://github.com/jr-k/obscreen/releases
### Translations
If you want to translate Obscreen into your language, please visit [Languages Files](https://git.sumisu.xyz/csmith1865/obscreen/src/branch/master/lang).
### Spelling & Grammar
Feel free to correct the grammar in the documentation or code.
My mother language is not English and my grammar is not that great.
However, I used this one: `(2,82) = 1920x1080 60Hz 1080p`

View File

32
data/db/slideshow.json.dist Executable file
View File

@ -0,0 +1,32 @@
{
"version": 2,
"keys": [
"duration",
"enabled",
"location",
"name",
"position",
"type",
"cron_schedule"
],
"data": {
"0": {
"location": "data/uploads/sample.jpg",
"duration": 10,
"type": "picture",
"enabled": true,
"name": "Picture Sample",
"position": 0,
"cron_schedule": null
},
"1": {
"location": "https://unix.org",
"duration": 20,
"type": "url",
"enabled": true,
"name": "URL Sample",
"position": 1,
"cron_schedule": null
}
}
}

View File

BIN
data/uploads/sample.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

View File

@ -1,12 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/favicon/mstile-70x70.png"/>
<square150x150logo src="/favicon/mstile-150x150.png"/>
<square310x310logo src="/favicon/mstile-310x3150.png"/>
<square310x310logo src="/favicon/mstile-310x310.png"/>
<TileColor>#333333</TileColor>
</tile>
</msapplication>
</browserconfig>
<browserconfig><msapplication><tile><square70x70logo src="/favicon/ms-icon-70x70.png"/><square150x150logo src="/favicon/ms-icon-150x150.png"/><square310x310logo src="/favicon/ms-icon-310x310.png"/><TileColor>#692fbd</TileColor></tile></msapplication></browserconfig>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,211 +0,0 @@
/*
* Explr.js v1.4
* Explorer-like tree jQuery plugin
* https://github.com/faisalman/explr-js
*
* Copyright © 2010-2011 Faisal Salman <f@faisalman.com>
* Dual licensed under GPLv2 & MIT
*/
.explr-tree * {
margin: 0;
padding: 0;
}
.explr-tree,
.explr-tree ol,
.explr-tree ul {
display: block;
font-family: Ubuntu, Helvetica, Tahoma, sans-serif;
font-size: 12px;
letter-spacing: normal;
line-height: 12px;
list-style: none;
margin: 0;
padding-bottom: 0;
padding-left: 20px;
padding-top: 5px;
position: relative;
}
.explr-tree {
overflow: auto;
}
.explr-tree li {
background: url("../../img/explr/folder.png") 16px 2px no-repeat;
display: block;
position: relative;
white-space: nowrap;
}
.explr-tree li a {
color: #555;
display: block;
font-size: 12px;
margin-left: 30px;
padding: 3px 0 5px 8px;
text-decoration: none;
}
.explr-tree li a:hover {
color: #ff0084;
text-decoration: underline;
}
.explr-line {
/*border-left: 1px dotted #999;*/
/*border-bottom: 1px dotted #999;*/
height: 22px;
position: absolute;
margin-left: 0;
margin-top: -12px;
width: 12px;
}
.explr-tree ol>li:first-child>.explr-line,
.explr-tree ul>li:first-child>.explr-line {
margin-top: -8px;
height: 18px;
}
.explr-line-fix {
/*border-left: 1px dotted #999;*/
}
.explr-icon {
background-repeat: no-repeat;
background-position: 0 0;
height: 16px;
width: 16px;
}
.explr-item i.fa {
position: absolute;
z-index: 1;
top: 2px;
font-size: 14px;
left: 16px;
color: rgb(187, 187, 187);
width: 18px;
text-align: center;
}
.explr-toggler {
background-repeat: no-repeat;
background-position: 0 0;
height: 16px;
margin-left: -8px;
margin-top: 2px;
position: absolute;
width: 40px;
}
/*.explr-plus { background-image: url("../../img/explr/plus.png"); }*/
/*.explr-minus { background-image: url("../../img/explr/busy.png"); }*/
/* Menu icons: */
.explr-tree .icon-text > li, .explr-tree li.icon-text { background-image: none; }
.explr-tree .icon-file > li, .explr-tree li.icon-file { background-image: url("../../img/explr/attibutes.png"); }
.explr-tree .icon-address > li, .explr-tree li.icon-address { background-image: url("../../img/explr/address.png"); }
.explr-tree .icon-archives > li, .explr-tree li.icon-archives { background-image: url("../../img/explr/archives.png"); }
.explr-tree .icon-badge > li, .explr-tree li.icon-badge { background-image: url("../../img/explr/bestseller.png"); }
.explr-tree .icon-bank > li, .explr-tree li.icon-bank { background-image: url("../../img/explr/bank.png"); }
.explr-tree .icon-basket > li, .explr-tree li.icon-basket { background-image: url("../../img/explr/basket.png"); }
.explr-tree .icon-board > li, .explr-tree li.icon-board { background-image: url("../../img/explr/order.png"); }
.explr-tree .icon-board2 > li, .explr-tree li.icon-board2 { background-image: url("../../img/explr/order-1.png"); }
.explr-tree .icon-book > li, .explr-tree li.icon-book { background-image: url("../../img/explr/library.png"); }
.explr-tree .icon-bookmark > li, .explr-tree li.icon-bookmark { background-image: url("../../img/explr/bookmark.png"); }
.explr-tree .icon-business > li, .explr-tree li.icon-business { background-image: url("../../img/explr/business-contact.png"); }
.explr-tree .icon-calendar > li, .explr-tree li.icon-calendar { background-image: url("../../img/explr/calendar.png"); }
.explr-tree .icon-card > li, .explr-tree li.icon-card { background-image: url("../../img/explr/credit-card.png"); }
.explr-tree .icon-card2 > li, .explr-tree li.icon-card2 { background-image: url("../../img/explr/my-account.png"); }
.explr-tree .icon-chain > li, .explr-tree li.icon-chain { background-image: url("../../img/explr/link.png"); }
.explr-tree .icon-chart > li, .explr-tree li.icon-chart { background-image: url("../../img/explr/statistics.png"); }
.explr-tree .icon-check > li, .explr-tree li.icon-check { background-image: url("../../img/explr/check.png"); }
.explr-tree .icon-clock > li, .explr-tree li.icon-clock { background-image: url("../../img/explr/full-time.png"); }
.explr-tree .icon-comment > li, .explr-tree li.icon-comment { background-image: url("../../img/explr/comment.png"); }
.explr-tree .icon-config > li, .explr-tree li.icon-config { background-image: url("../../img/explr/config.png"); }
.explr-tree .icon-customers > li, .explr-tree li.icon-customers { background-image: url("../../img/explr/customers.png"); }
.explr-tree .icon-cv > li, .explr-tree li.icon-cv { background-image: url("../../img/explr/cv.png"); }
.explr-tree .icon-db > li, .explr-tree li.icon-db { background-image: url("../../img/explr/database.png"); }
.explr-tree .icon-direction > li, .explr-tree li.icon-direction { background-image: url("../../img/explr/milestone.png"); }
.explr-tree .icon-flag > li, .explr-tree li.icon-flag { background-image: url("../../img/explr/flag.png"); }
.explr-tree .icon-folder > li, .explr-tree li.icon-folder, .explr-icon-folder { background-image: url("../../img/explr/folder.png"); }
.explr-tree .icon-folder2 > li, .explr-tree li.icon-folder2 { background-image: url("../../img/explr/finished-work.png"); }
.explr-tree .icon-folder3 > li, .explr-tree li.icon-folder3 { background-image: url("../../img/explr/upcoming-work.png"); }
.explr-tree .icon-hand > li, .explr-tree li.icon-hand { background-image: url("../../img/explr/freelance.png"); }
.explr-tree .icon-heart > li, .explr-tree li.icon-heart { background-image: url("../../img/explr/heart.png"); }
.explr-tree .icon-help > li, .explr-tree li.icon-help { background-image: url("../../img/explr/consulting.png"); }
.explr-tree .icon-home > li, .explr-tree li.icon-home { background-image: url("../../img/explr/home.png"); }
.explr-tree .icon-lamp > li, .explr-tree li.icon-lamp { background-image: url("../../img/explr/lightbulb.png"); }
.explr-tree .icon-left > li, .explr-tree li.icon-left { background-image: url("../../img/explr/sign-out.png"); }
.explr-tree .icon-left2 > li, .explr-tree li.icon-left2 { background-image: url("../../img/explr/login.png"); }
.explr-tree .icon-lock > li, .explr-tree li.icon-lock { background-image: url("../../img/explr/lock.png"); }
.explr-tree .icon-mail > li, .explr-tree li.icon-mail { background-image: url("../../img/explr/contact.png"); }
.explr-tree .icon-mail2 > li, .explr-tree li.icon-mail2 { background-image: url("../../img/explr/email.png"); }
.explr-tree .icon-palette > li, .explr-tree li.icon-palette { background-image: url("../../img/explr/drawings.png"); }
.explr-tree .icon-pencil > li, .explr-tree li.icon-pencil { background-image: url("../../img/explr/edit.png"); }
.explr-tree .icon-pencil2 > li, .explr-tree li.icon-pencil2 { background-image: url("../../img/explr/pencil.png"); }
.explr-tree .icon-phone > li, .explr-tree li.icon-phone { background-image: url("../../img/explr/phone.png"); }
.explr-tree .icon-photo > li, .explr-tree li.icon-photo { background-image: url("../../img/explr/photography.png"); }
.explr-tree .icon-print > li, .explr-tree li.icon-print { background-image: url("../../img/explr/print.png"); }
.explr-tree .icon-project > li, .explr-tree li.icon-project { background-image: url("../../img/explr/project.png"); }
.explr-tree .icon-refresh > li, .explr-tree li.icon-refresh { background-image: url("../../img/explr/refresh.png"); }
.explr-tree .icon-right > li, .explr-tree li.icon-right { background-image: url("../../img/explr/sign-in.png"); }
.explr-tree .icon-right2 > li, .explr-tree li.icon-right2 { background-image: url("../../img/explr/logout.png"); }
.explr-tree .icon-showreel > li, .explr-tree li.icon-showreel { background-image: url("../../img/explr/showreel.png"); }
.explr-tree .icon-star > li, .explr-tree li.icon-star { background-image: url("../../img/explr/star.png"); }
.explr-tree .icon-tag > li, .explr-tree li.icon-tag { background-image: url("../../img/explr/tag.png"); }
.explr-tree .icon-text2 > li, .explr-tree li.icon-text2 { background-image: url("../../img/explr/issue.png"); }
.explr-tree .icon-text3 > li, .explr-tree li.icon-text3 { background-image: url("../../img/explr/future-projects.png"); }
.explr-tree .icon-text4 > li, .explr-tree li.icon-text4 { background-image: url("../../img/explr/old-versions.png"); }
.explr-tree .icon-user > li, .explr-tree li.icon-user { background-image: url("../../img/explr/user.png"); }
.explr-tree .icon-world > li, .explr-tree li.icon-world { background-image: url("../../img/explr/world.png"); }
.explr-tree .icon-zoom > li, .explr-tree li.icon-zoom { background-image: url("../../img/explr/zoom.png"); }
.explr-tree .icon-youtube > li, .explr-tree li.icon-youtube { background-image: url("../../img/explr/youtube.png"); }
.explr-tree .icon-globe > li, .explr-tree li.icon-globe { background-image: url("../../img/explr/globe.png"); }
.explr-tree .icon-video > li, .explr-tree li.icon-video { background-image: url("../../img/explr/video.png"); }
.explr-tree .icon-landscape > li, .explr-tree li.icon-landscape { background-image: url("../../img/explr/landscape.png"); }
/* IE Hack Fixes: */
.explr-ie,
.explr-ie ol,
.explr-ie ul {
margin-left: 4px;
padding-left: 16px;
position: static;
}
.explr-ie ol,
.explr-ie ul {
overflow: hidden;
}
.explr-ie {
padding-top: 20px;
}
.explr-ie .explr-line,
.explr-ie .explr-toggler {
top: 0;
left: 4px;
}
.explr-ie li {
height: auto !important;
height: 24px;
*padding-top: 12px;
_padding-top: 0;
}
.explr-ie li a {
*position: absolute;
_position: static;
*top: 0;
_top: auto;
}

721
data/www/css/main.css Normal file
View File

@ -0,0 +1,721 @@
* {
font-family: Roboto;
}
html {
height: 100vh;
margin: 0;
padding: 0;
display: flex;
background-color: #0f0035;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
align-self: stretch;
}
body {
margin: 0;
padding: 0;
flex: 1;
background-color: #0f0035;
color: #fff;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
align-self: stretch;
}
.invisible {
visibility: hidden !important;
}
.hidden {
display: none !important;
}
.tac {
text-align: center;
}
a {
text-decoration: none;
}
.container {
background: rgba(0, 0, 0, 0.1);
margin: auto;
display: flex;
align-self: stretch;
flex-direction: column;
justify-content: flex-start;
align-items: center;
flex: 1;
min-width: 70%;
@media only screen and (max-width: 1200px) {
min-width: 95%;
}
}
header {
text-align: center;
display: flex;
justify-content: flex-start;
align-items: center;
align-self: stretch;
padding: 0 25px 0 25px;
}
header .logo {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
header .logo a {
color: inherit;
display: flex;
justify-content: center;
align-items: center;
}
header .logo img {
width: 32px;
height: 32px;
margin-right: 10px;
}
header nav {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
flex: 1;
}
header nav ul {
list-style: none;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
header nav ul li {
margin: 0 15px;
}
header nav ul li.user-menu {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
border: 1px solid #0bc44e;
padding: 5px 15px;
border-radius: 4px;
background: rgba(14, 239, 95, .2);
}
header nav ul li.user-menu .logout {
color: rgb(255, 255, 255);
}
header nav ul li.user-menu .username {
margin-right: 20px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
font-weight: bold;
color: #0bc44e;
}
header nav ul li.user-menu .username i {
margin-right: 5px;
font-size: 12px;
}
header nav ul li a {
color: rgba(255, 255, 255, 0.6);
text-decoration: none;
}
header nav ul li a:hover,
header nav ul li.active a {
color: white;
}
.toolbar {
display: flex;
flex-direction: row;
padding: 0 25px 0 25px;
align-self: stretch;
}
.toolbar h2 {
padding: 0 25px 0 0;
}
.toolbar .toolbar-actions {
flex: 1;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
a.btn,
button {
background-color: #fff;
border-radius: 5px;
border: 1px solid #bc48ff;
color: #270035;
padding: 10px 30px;
text-decoration: none;
margin: 10px;
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-weight: 400;
font-size: 14px;
transition: .2s linear all;
}
a.btn:hover,
button:hover {
color: #bc48ff;
}
button.purple {
font-weight: bold;
border: 1px solid #692fbd;
color: white;
background: #692fbd;
background: linear-gradient(90deg, #bc48ff 0%, #692fbd 100%);
}
button.green {
font-weight: bold;
color: white;
border: 1px solid #0eef5f;
background: linear-gradient(90deg, #2fde6f 0%, #13c251 100%);
}
button.normal:hover {
color: white;
border-color: #692fbd;
background: #692fbd;
background: linear-gradient(90deg, #bc48ff 0%, #692fbd 100%);
}
button.green:hover,
button.purple:hover {
border: 1px solid #fff;
}
.alert {
margin: 10px 30px 20px 30px;
padding: 20px 50px;
align-self: stretch;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border-radius: 4px;
}
.alert-info {
color: rgb(70, 70, 70);
border: 1px solid rgb(70, 70, 70);
background: rgba(70, 70, 70, .2);
}
.alert-success {
color: rgb(14, 239, 95);
border: 1px solid rgb(14, 239, 95);
background: rgba(14, 239, 95, .2);
}
.alert-error {
color: rgb(239, 14, 93);
border: 1px solid rgb(239, 14, 93);
background: rgba(239, 14, 93, .2);
}
.panel {
background: rgba(255, 255, 255, 0.15);
border-radius: 5px;
padding: 0 25px 80px 25px;
margin: 10px 25px;
border-left: 5px solid #0eef5f;
align-self: stretch;
}
.panel h3 {
color: #fff;
}
.panel-inactive {
background: white;
color: #AAA;
border-color: #BBB;
}
.panel-inactive h3 {
color: #333;
}
.panel table {
width: 100%;
margin-top: 30px;
border-collapse: collapse;
text-align: left;
font-weight: normal;
}
.panel th {
border-bottom: 1px solid #fff;
border-collapse: collapse;
padding: 10px;
font-weight: normal;
}
.panel-inactive th {
border-color: #EEE;
}
.panel td {
border-collapse: collapse;
padding: 10px;
}
.panel td a.item.sort {
cursor: move;
}
.panel td a.item-name {
color: white;
}
.panel-inactive td a.item-name {
color: #AAA;
}
.panel td a.item-name:hover {
text-decoration: underline;
}
.panel td.actions a {
background: white;
color: #333;
border: 1px solid #AAA;
border-radius: 4px;
padding: 2px;
width: 35px;
display: inline-block;
text-align: center;
margin: 0 2px;
}
.panel td.actions a:hover {
color: #0eef5f;
border-color: #0eef5f;
}
.panel td.actions a.item-edit:hover {
color: #bc48ff;
border-color: #bc48ff;
}
.panel td.actions a.item-delete:hover {
color: #ef0e0e;
border-color: #ef0e0e;
}
.panel td.infos {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
}
.panel td.infos .inner {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
}
.panel a {
color: #0eef5f;
text-decoration: none;
}
.panel a:hover {
color: #0bc44e;
}
.icon-right {
margin: 0 0 0 10px;
}
.icon-left {
margin: 0 10px 0 0;
}
.pure-material-switch {
z-index: 0;
position: relative;
display: inline-block;
}
.pure-material-switch > input {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
z-index: -1;
position: absolute;
right: 6px;
top: -8px;
display: block;
margin: 0;
border-radius: 50%;
width: 40px;
height: 40px;
background-color: rgba(0, 0, 0, 0.38);
outline: none;
opacity: 0;
transform: scale(1);
pointer-events: none;
transition: opacity 0.3s 0.1s, transform 0.2s 0.1s;
}
.pure-material-switch > span {
display: inline-block;
width: 100%;
cursor: pointer;
}
.pure-material-switch > span::before {
content: "";
float: right;
display: inline-block;
margin: 5px 0 5px 10px;
border-radius: 7px;
width: 36px;
height: 14px;
background-color: rgba(0, 0, 0, 0.38);
vertical-align: top;
transition: background-color 0.2s, opacity 0.2s;
}
.pure-material-switch > span::after {
content: "";
position: absolute;
top: 2px;
right: 16px;
border-radius: 50%;
width: 20px;
height: 20px;
background-color: rgb(255, 255, 255);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
transition: background-color 0.2s, transform 0.2s;
}
.pure-material-switch > input:checked {
right: -10px;
background-color: rgb(14, 239, 95);
}
.pure-material-switch > input:checked + span::before {
background-color: rgba(14, 239, 95, 0.6);
}
.pure-material-switch > input:checked + span::after {
background-color: rgb(14, 239, 95);
transform: translateX(16px);
}
.pure-material-switch:hover > input {
opacity: 0.04;
}
.pure-material-switch > input:focus {
opacity: 0.12;
}
.pure-material-switch:hover > input:focus {
opacity: 0.16;
}
.pure-material-switch > input:active {
opacity: 1;
transform: scale(0);
transition: transform 0s, opacity 0s;
}
.pure-material-switch > input:active + span::before {
background-color: rgba(14, 239, 95, 0.6);
}
.pure-material-switch > input:checked:active + span::before {
background-color: rgba(0, 0, 0, 0.38);
}
.pure-material-switch > input:disabled {
opacity: 0;
}
.pure-material-switch > input:disabled + span {
color: rgb(0, 0, 0);
opacity: 0.38;
cursor: default;
}
.pure-material-switch > input:disabled + span::before {
background-color: rgba(0, 0, 0, 0.38);
}
.pure-material-switch > input:checked:disabled + span::before {
background-color: rgba(14, 239, 95, 0.6);
}
.modals {
position: fixed;
background: rgba(0, 0, 0, 0.4);
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.modals-outer {
min-width: 30%;
display: flex;
flex-direction: column;
overflow: auto;
}
.modals-outer .modal-close {
color: white;
font-size: 30px;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin-bottom: 20px;
margin-top: 0px;
}
.modals-inner {
background: white;
border-radius: 10px;
color: #333;
}
.modals-inner .modal h2 {
border-bottom: 1px solid #DDD;
padding: 15px 15px;
margin: 0;
}
.modals-inner .modal h3 {
align-self: stretch;
border-bottom: 1px solid #DDD;
padding: 15px 15px;
margin: 0;
}
form {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
padding: 20px;
}
form .form-group {
margin: 10px 20px 5px 20px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
align-self: stretch;
flex: 1;
}
form .form-group label {
flex: 1;
padding: 10px;
text-align: right;
margin-right: 20px;
}
form .form-group .widget {
flex: 3;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
align-self: stretch;
}
form .form-group input,
form .form-group select,
form .form-group textarea {
flex: 1;
padding: 10px 5px 10px 5px;
border: 1px solid #EEE;
border-radius: 4px;
width: auto;
}
form .form-group input[type=checkbox] {
flex: 0;
}
form .form-group .trigger {
margin-right: 10px;
}
form .form-group select.trigger {
max-width: 120px;
}
form .form-group span {
margin-left: 10px;
}
form .actions {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin-top: 10px;
align-self: stretch;
}
form .actions button.green,
form .actions button {
font-size: 18px;
}
form .actions button.green:hover {
background: white;
color: rgb(14, 239, 95);
border-color: rgb(14, 239, 95);
}
form .actions button.btn-normal {
color: #999;
border-color: #999;
font-size: 18px;
margin: 0;
}
form .actions button.btn-normal:hover {
color: #555;
border-color: #555;
}
span.empty {
text-transform: uppercase;
opacity: 0.5;
color: #999;
}
footer {
align-self: stretch;
justify-content: center;
align-items: center;
flex-direction: column;
display: flex;
padding: 20px;
}
footer .version {
opacity: 0.3;
}
.login-page {
max-width: 600px;
padding-top: 50px;
}
.card {
background: white;
border-radius: 6px;
padding: 50px 50px;
color: #333;
}
.card form {
padding: 0;
}
.card form .form-group {
margin: 0 0 30px 0;
padding: 0;
}
.card form .form-group .widget {
flex: 1;
}
.card form .form-group label {
text-align: left;
}
.card button[type=submit] {
margin: 0 auto;
}
.card h3 {
text-align: center;
font-size: 36px;
margin: 0 0 40px 0;
}
a.badge,
.badge {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px 5px;
border-radius: 4px;
font-size: 12px;
background: rgba(255, 255, 255, .1);
border: 1px solid transparent;
color: #ffffff;
}
a.badge:hover {
color: #FFFFFF;
border: 1px solid rgba(255,255,255,.4);
}
.panel-inactive .badge {
background: rgba(200, 200, 200, .1);
color: #999999;
}
.panel-inactive a.badge:hover {
color: #999999;
border: 1px solid rgba(180,180,180,.4);
}
.badge.anonymous {
opacity: .2;
}

BIN
data/www/favicon.ico Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
data/www/favicon/apple-icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

BIN
data/www/favicon/favicon-16x16.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

BIN
data/www/favicon/favicon-32x32.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
data/www/favicon/favicon-96x96.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 913 B

Some files were not shown because too many files have changed in this diff Show More