First version of the theme system
This commit is contained in:
parent
7f039fc427
commit
a30c21dd50
@ -172,3 +172,29 @@ Actually, the following constants can be overrided:
|
|||||||
- `DB_FILENAME` => default value is `data/db.sqlite`
|
- `DB_FILENAME` => default value is `data/db.sqlite`
|
||||||
- `DEBUG` => default is false (enable logs dump of picoFeed)
|
- `DEBUG` => default is false (enable logs dump of picoFeed)
|
||||||
- `DEBUG_DIRECTORY` => default is /tmp (place to store log files)
|
- `DEBUG_DIRECTORY` => default is /tmp (place to store log files)
|
||||||
|
- `THEME_DIRECTORY` => default is themes
|
||||||
|
|
||||||
|
### How to create a theme for Miniflux?
|
||||||
|
|
||||||
|
It's very easy to write a custom theme for Miniflux.
|
||||||
|
|
||||||
|
A theme is just a CSS file, images and fonts.
|
||||||
|
A theme doesn't change the behaviour of the application but only the page design.
|
||||||
|
|
||||||
|
The first step is to create a new directory structure for your theme:
|
||||||
|
|
||||||
|
mkdir -p themes/mysuperskin/{css,img,fonts}
|
||||||
|
|
||||||
|
The name of your theme should be only alphanumeric.
|
||||||
|
There is the following directories inside your theme:
|
||||||
|
|
||||||
|
- `css`: Your stylesheet, the file must be named `app.css` (required)
|
||||||
|
- `img`: Theme images (not required)
|
||||||
|
- `fonts`: Theme fonts (not required)
|
||||||
|
|
||||||
|
For a very basic theme example, have a look to the directory `examples\mytheme`.
|
||||||
|
|
||||||
|
Miniflux use responsive design, so it's better if your theme can handle mobile devices.
|
||||||
|
|
||||||
|
If you write a very cool theme for Miniflux, **send me your code to be available in the default installation!**
|
||||||
|
It would be awesome for everybody :)
|
@ -16,6 +16,7 @@ defined('HTTP_TIMEOUT') or define('HTTP_TIMEOUT', 10);
|
|||||||
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
||||||
defined('DEBUG') or define('DEBUG', false);
|
defined('DEBUG') or define('DEBUG', false);
|
||||||
defined('DEBUG_DIRECTORY') or define('DEBUG_DIRECTORY', '/tmp');
|
defined('DEBUG_DIRECTORY') or define('DEBUG_DIRECTORY', '/tmp');
|
||||||
|
defined('THEME_DIRECTORY') or define('THEME_DIRECTORY', 'themes');
|
||||||
|
|
||||||
PicoTools\container('db', function() {
|
PicoTools\container('db', function() {
|
||||||
|
|
||||||
|
11
examples/mytheme/css/app.css
Normal file
11
examples/mytheme/css/app.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: Inconsolata;
|
||||||
|
src: url(../fonts/Inconsolata-Regular.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-left: 300px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 5px solid #000;
|
||||||
|
font-family: 'Inconsolata', sans-serif;
|
||||||
|
}
|
BIN
examples/mytheme/fonts/Inconsolata-Bold.ttf
Executable file
BIN
examples/mytheme/fonts/Inconsolata-Bold.ttf
Executable file
Binary file not shown.
BIN
examples/mytheme/fonts/Inconsolata-Regular.ttf
Executable file
BIN
examples/mytheme/fonts/Inconsolata-Regular.ttf
Executable file
Binary file not shown.
20
helpers.php
Normal file
20
helpers.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Helper;
|
||||||
|
|
||||||
|
|
||||||
|
function css()
|
||||||
|
{
|
||||||
|
$theme = \Model\get_config_value('theme');
|
||||||
|
|
||||||
|
if ($theme !== 'original') {
|
||||||
|
|
||||||
|
$css_file = THEME_DIRECTORY.'/'.$theme.'/css/app.css';
|
||||||
|
|
||||||
|
if (file_exists($css_file)) {
|
||||||
|
return $css_file.'?version='.filemtime($css_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'assets/css/app.css?version='.filemtime('assets/css/app.css');
|
||||||
|
}
|
@ -7,6 +7,7 @@ require 'vendor/PicoFarad/Response.php';
|
|||||||
require 'vendor/PicoFarad/Request.php';
|
require 'vendor/PicoFarad/Request.php';
|
||||||
require 'vendor/PicoFarad/Session.php';
|
require 'vendor/PicoFarad/Session.php';
|
||||||
require 'vendor/PicoFarad/Router.php';
|
require 'vendor/PicoFarad/Router.php';
|
||||||
|
require 'helpers.php';
|
||||||
|
|
||||||
use PicoFarad\Router;
|
use PicoFarad\Router;
|
||||||
use PicoFarad\Response;
|
use PicoFarad\Response;
|
||||||
@ -492,6 +493,7 @@ Router\get_action('config', function() {
|
|||||||
'languages' => Model\get_languages(),
|
'languages' => Model\get_languages(),
|
||||||
'autoflush_options' => Model\get_autoflush_options(),
|
'autoflush_options' => Model\get_autoflush_options(),
|
||||||
'paging_options' => Model\get_paging_options(),
|
'paging_options' => Model\get_paging_options(),
|
||||||
|
'theme_options' => Model\get_themes(),
|
||||||
'menu' => 'config',
|
'menu' => 'config',
|
||||||
'title' => t('Preferences')
|
'title' => t('Preferences')
|
||||||
)));
|
)));
|
||||||
@ -525,6 +527,7 @@ Router\post_action('config', function() {
|
|||||||
'languages' => Model\get_languages(),
|
'languages' => Model\get_languages(),
|
||||||
'autoflush_options' => Model\get_autoflush_options(),
|
'autoflush_options' => Model\get_autoflush_options(),
|
||||||
'paging_options' => Model\get_paging_options(),
|
'paging_options' => Model\get_paging_options(),
|
||||||
|
'theme_options' => Model\get_themes(),
|
||||||
'menu' => 'config',
|
'menu' => 'config',
|
||||||
'title' => t('Preferences')
|
'title' => t('Preferences')
|
||||||
)));
|
)));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
'Theme' => 'Thème',
|
||||||
'No item' => 'Aucun élément',
|
'No item' => 'Aucun élément',
|
||||||
'items' => 'éléments',
|
'items' => 'éléments',
|
||||||
'There is %d empty feeds, there is maybe an error: %s...' =>
|
'There is %d empty feeds, there is maybe an error: %s...' =>
|
||||||
|
31
model.php
31
model.php
@ -22,7 +22,7 @@ use PicoFeed\Reader;
|
|||||||
use PicoFeed\Export;
|
use PicoFeed\Export;
|
||||||
|
|
||||||
|
|
||||||
const DB_VERSION = 9;
|
const DB_VERSION = 10;
|
||||||
const HTTP_USERAGENT = 'Miniflux - http://miniflux.net';
|
const HTTP_USERAGENT = 'Miniflux - http://miniflux.net';
|
||||||
const LIMIT_ALL = -1;
|
const LIMIT_ALL = -1;
|
||||||
|
|
||||||
@ -40,6 +40,28 @@ function get_languages()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_themes()
|
||||||
|
{
|
||||||
|
$themes = array(
|
||||||
|
'original' => t('Original')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file_exists(THEME_DIRECTORY)) {
|
||||||
|
|
||||||
|
$dir = new \DirectoryIterator(THEME_DIRECTORY);
|
||||||
|
|
||||||
|
foreach ($dir as $fileinfo) {
|
||||||
|
|
||||||
|
if (! $fileinfo->isDot() && $fileinfo->isDir()) {
|
||||||
|
$themes[$dir->getFilename()] = ucfirst($dir->getFilename());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function get_autoflush_options()
|
function get_autoflush_options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
@ -622,7 +644,7 @@ function get_config()
|
|||||||
{
|
{
|
||||||
return \PicoTools\singleton('db')
|
return \PicoTools\singleton('db')
|
||||||
->table('config')
|
->table('config')
|
||||||
->columns('username', 'language', 'autoflush', 'nocontent', 'items_per_page')
|
->columns('username', 'language', 'autoflush', 'nocontent', 'items_per_page', 'theme')
|
||||||
->findOne();
|
->findOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,6 +709,7 @@ function validate_config_update(array $values)
|
|||||||
new Validators\Required('autoflush', t('Value required')),
|
new Validators\Required('autoflush', t('Value required')),
|
||||||
new Validators\Required('items_per_page', t('Value required')),
|
new Validators\Required('items_per_page', t('Value required')),
|
||||||
new Validators\Integer('items_per_page', t('Must be an integer')),
|
new Validators\Integer('items_per_page', t('Must be an integer')),
|
||||||
|
new Validators\Required('theme', t('Value required')),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -710,8 +733,8 @@ function save_config(array $values)
|
|||||||
if (! empty($values['password'])) {
|
if (! empty($values['password'])) {
|
||||||
|
|
||||||
$values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT);
|
$values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT);
|
||||||
}
|
|
||||||
else {
|
} else {
|
||||||
|
|
||||||
unset($values['password']);
|
unset($values['password']);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
|
||||||
|
function version_10($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec('ALTER TABLE config ADD COLUMN theme TEXT DEFAULT "original"');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function version_9($pdo)
|
function version_9($pdo)
|
||||||
{
|
{
|
||||||
$pdo->exec('ALTER TABLE config ADD COLUMN items_per_page INTEGER DEFAULT 100');
|
$pdo->exec('ALTER TABLE config ADD COLUMN items_per_page INTEGER DEFAULT 100');
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<link rel="apple-touch-icon" sizes="114x114" href="./assets/img/touch-icon-iphone-retina.png">
|
<link rel="apple-touch-icon" sizes="114x114" href="./assets/img/touch-icon-iphone-retina.png">
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="./assets/img/touch-icon-ipad-retina.png">
|
<link rel="apple-touch-icon" sizes="144x144" href="./assets/img/touch-icon-ipad-retina.png">
|
||||||
<title><?= isset($title) ? Helper\escape($title) : 'miniflux' ?></title>
|
<title><?= isset($title) ? Helper\escape($title) : 'miniflux' ?></title>
|
||||||
<link href="./assets/css/app.css?v<?= filemtime('assets/css/app.css') ?>" rel="stylesheet" media="screen">
|
<link href="<?= Helper\css() ?>" rel="stylesheet" media="screen">
|
||||||
<script type="text/javascript" src="./assets/js/app.js?v<?= filemtime('assets/js/app.js') ?>" defer></script>
|
<script type="text/javascript" src="./assets/js/app.js?v<?= filemtime('assets/js/app.js') ?>" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
<?= Helper\form_label(t('Items per page'), 'items_per_page') ?>
|
<?= Helper\form_label(t('Items per page'), 'items_per_page') ?>
|
||||||
<?= Helper\form_select('items_per_page', $paging_options, $values, $errors) ?><br/>
|
<?= Helper\form_select('items_per_page', $paging_options, $values, $errors) ?><br/>
|
||||||
|
|
||||||
|
<?= Helper\form_label(t('Theme'), 'theme') ?>
|
||||||
|
<?= Helper\form_select('theme', $theme_options, $values, $errors) ?><br/>
|
||||||
|
|
||||||
<?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, isset($values['nocontent']) ? $values['nocontent'] : false) ?><br />
|
<?= Helper\form_checkbox('nocontent', t('Do not fetch the content of articles'), 1, isset($values['nocontent']) ? $values['nocontent'] : false) ?><br />
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
Loading…
Reference in New Issue
Block a user