Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [unreleased]

### Added

- Add a graphical interface to download themes in the admin dashboard.

### Fixed

- Fix admin pannel's highlight preview overflow on mobile screens.
Expand Down
8 changes: 7 additions & 1 deletion assets/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ JSREV = 9-18-stable
REPO = https://github.com/highlightjs/cdn-release
THEMES = github github-dark base16/monokai

all: highlight.min.js $(THEMES:=.min.css)
all: highlight.min.js styles.min.js $(THEMES:=.min.css)

%.min.js: .FORCE
wget -q $(REPO)/raw/$(JSREV)/build/$(@F) -O $@

%.min.css: .FORCE
wget -q $(REPO)/raw/$(CSSREV)/build/styles/$*.min.css -O $@

styles.min.js: .FORCE
printf 'let hljsStyles = ' > $@
curl -s https://api.github.com/repos/highlightjs/cdn-release/git/trees/main?recursive=1 \
| jq -c '[.tree[].path|select(.|startswith("build/styles/") and endswith(".min.css"))|ltrimstr("build/styles/")|rtrimstr(".min.css")]' \
>> $@

.FORCE:;
.PHONY: .FORCE
1 change: 1 addition & 0 deletions assets/styles.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@
*/

use Club1\ServerSideHighlight\Console\DownloadCommand;
use Club1\ServerSideHighlight\Controller\DownloadController;
use Club1\ServerSideHighlight\Controller\PreviewController;
use Club1\ServerSideHighlight\Exception\InvalidArgumentException;
use Club1\ServerSideHighlight\Exception\IOException;
use Club1\ServerSideHighlight\Exception\KnownExceptionHandler;
use Club1\ServerSideHighlight\Formatter\Configurator;
use Club1\ServerSideHighlight\Formatter\Renderer;
use Club1\ServerSideHighlight\Frontend\Content;
use Club1\ServerSideHighlight\Frontend\Admin;
use Club1\ServerSideHighlight\Frontend\Forum;
use Club1\ServerSideHighlight\Serializer\HighlightThemeSerializer;
use Flarum\Extend;

Expand All @@ -35,17 +40,23 @@
->render(Renderer::class),

(new Extend\Frontend('forum'))
->content(Content::class)
->content(Forum::class)
->js(__DIR__.'/js/forum.js')
->css(__DIR__.'/css/forum.css'),

(new Extend\Frontend('admin'))
->content(Admin::class)
->js(__DIR__.'/js/admin.js')
->css(__DIR__.'/css/admin.css'),

(new Extend\Routes('api'))
->get('/highlight-download', 'club-1-server-side-highlight.download', DownloadController::class)
->get('/highlight-preview', 'club-1-server-side-highlight.preview', PreviewController::class),

(new Extend\ErrorHandling)
->handler(InvalidArgumentException::class, KnownExceptionHandler::class)
->handler(IOException::class, KnownExceptionHandler::class),

(new Extend\Settings())
->default('club-1-server-side-highlight.light_theme_bg_color', '#f7f7f7')
->default('club-1-server-side-highlight.light_theme_text_color', '#000000')
Expand Down
57 changes: 54 additions & 3 deletions js/admin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
let hljsStyle;
let themes;

app.initializers.add('server-side-highlight', function(app) {
const themes = JSON.parse(app.data.settings['club-1-server-side-highlight.available_themes']);
themes = JSON.parse(app.data.settings['club-1-server-side-highlight.available_themes']);
app.extensionData
.for('club-1-server-side-highlight')
.registerSetting(function () {
return [
m('div.Form-group', [
m('label', app.translator.trans('club-1-server-side-highlight.admin.download_theme')),
m('span.Select', {
onchange: e => hljsStyle = e.target.value,
value: hljsStyle,
}, [
m('select.Select-input.FormControl', [
m('option', {disabled: true, selected: !hljsStyle}, app.translator.trans('club-1-server-side-highlight.admin.choose_theme')),
hljsStyles.map(x => m('option', x)),
]),
m('i.icon.fas.fa-sort.Select-caret'),
]),
]),
m('button.Button.Button--primary', {
onclick: () => download.bind(this)(hljsStyle),
disabled: !hljsStyle,
}, app.translator.trans('club-1-server-side-highlight.admin.download')),
m('hr')
];
})
.registerSetting({
setting: 'club-1-server-side-highlight.light_theme_bg_color',
label: app.translator.trans('club-1-server-side-highlight.admin.light_theme_bg_color'),
Expand Down Expand Up @@ -46,10 +71,36 @@ function preview(mode) {
let bg = encodeURIComponent(this.setting(`club-1-server-side-highlight.${mode}_theme_bg_color`)());
let text = encodeURIComponent(this.setting(`club-1-server-side-highlight.${mode}_theme_text_color`)());
let theme = encodeURIComponent(this.setting(`club-1-server-side-highlight.${mode}_theme_highlight_theme`)());
return m('div.Form-group', m('iframe', {
return m('div.Form-group', m('iframe.highlight-preview', {
src: app.forum.attribute('baseUrl') + `/api/highlight-preview?bg=${bg}&text=${text}&theme=${theme}`,
class: 'highlight-preview',
}));
}

function download(style) {
hljsStyle = null;
app.request({
method: 'GET',
url: '/api/highlight-download',
params: {name: style},
errorHandler,
})
.then(res => {
for (const [key, value] of Object.entries(res)) {
themes[key] = value;
}
app.alerts.show({type: 'success'}, app.translator.trans('club-1-server-side-highlight.admin.download_success'));
m.redraw();
})
}

function errorHandler(err) {
let msgs = err.response.errors.filter(e => e.message).map(e => e.message);
if (msgs.length == 0) {
app.alerts.show({type: err.alert.type}, err.alert.content);
} else {
msgs.forEach(m => app.alerts.show({type: 'error'}, m));
}
}


module.exports = {}
4 changes: 4 additions & 0 deletions locale/en.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
club-1-server-side-highlight:
admin:
download_theme: 'Download a theme'
choose_theme: 'Choose a theme'
download: 'Download'
download_success: 'Theme downloaded successfully'
light_theme_bg_color: 'Light theme background color'
light_theme_text_color: 'Light theme text color'
light_theme_highlight_theme: 'Light theme highlight theme'
Expand Down
4 changes: 4 additions & 0 deletions locale/fr.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
club-1-server-side-highlight:
admin:
download_theme: 'Télécharger un thème'
choose_theme: 'Selectionner un thème'
download: 'Télécharger'
download_success: 'Thème téléchargé avec succes'
light_theme_bg_color: 'Couleur de fond pour le thème clair'
light_theme_text_color: 'Couleur du texte pour le thème clair'
light_theme_highlight_theme: 'Thème de couleur pour le thème clair'
Expand Down
8 changes: 7 additions & 1 deletion src/Console/DownloadCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
namespace Club1\ServerSideHighlight\Console;

use Club1\ServerSideHighlight\Consts;
use Club1\ServerSideHighlight\Exception\InvalidArgumentException;
use Club1\ServerSideHighlight\Exception\IOException;
use ErrorException;
use Flarum\Console\AbstractCommand;
use Flarum\Settings\SettingsRepositoryInterface;
Expand Down Expand Up @@ -69,10 +71,14 @@ protected function fire(): void
try {
$remote = fopen($remoteFile, 'r');
assert(is_resource($remote));
} catch (\Throwable $t) {
throw new InvalidArgumentException("Could not download theme $name", 1, $t);
}
try {
$this->assetsDisk->put($localFile, $remote);
} catch (\Throwable $t) {
$this->assetsDisk->delete($localFile);
throw $t;
throw new IOException("Could not write theme to assets", 2, $t);
}

$this->info("Updating available highlight themes...");
Expand Down
62 changes: 62 additions & 0 deletions src/Controller/DownloadController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/*
* This file is part of club-1/flarum-ext-server-side-highlight.
*
* Copyright (c) 2023 Nicolas Peugnet <nicolas@club1.fr>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace Club1\ServerSideHighlight\Controller;

use Club1\ServerSideHighlight\Console\DownloadCommand;
use Flarum\Http\RequestUtil;
use Flarum\Settings\SettingsRepositoryInterface;
use Laminas\Diactoros\Response\TextResponse;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;

class DownloadController implements RequestHandlerInterface
{
/** @var SettingsRepositoryInterface */
protected $settings;

/** @var DownloadCommand */
protected $command;

public function __construct(SettingsRepositoryInterface $settings, DownloadCommand $command)
{
$this->settings = $settings;
$this->command = $command;
}

public function handle(Request $request): Response
{
$actor = RequestUtil::getActor($request);
$actor->assertAdmin();
$name = $request->getQueryParams()['name'];
$this->command->run(new ArrayInput(['name' => $name]), new NullOutput);
return new TextResponse(
$this->settings->get('club-1-server-side-highlight.available_themes'),
200,
['Content-Type' => ['application/json']]
);
}
}
39 changes: 39 additions & 0 deletions src/Exception/IOException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/*
* This file is part of club-1/flarum-ext-server-side-highlight.
*
* Copyright (c) 2023 Nicolas Peugnet <nicolas@club1.fr>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace Club1\ServerSideHighlight\Exception;

use RuntimeException;

class IOException extends RuntimeException implements KnownException
{
public function getType(): string
{
return 'io_error';
}

public function getStatusCode(): int
{
return 409;
}
}
37 changes: 37 additions & 0 deletions src/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of club-1/flarum-ext-server-side-highlight.
*
* Copyright (c) 2023 Nicolas Peugnet <nicolas@club1.fr>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace Club1\ServerSideHighlight\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements KnownException
{
public function getType(): string
{
return 'invalid_parameter';
}

public function getStatusCode(): int
{
return 400;
}
}
52 changes: 52 additions & 0 deletions src/Exception/KnownException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/*
* This file is part of club-1/flarum-ext-server-side-highlight.
*
* Copyright (c) 2023 Nicolas Peugnet <nicolas@club1.fr>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace Club1\ServerSideHighlight\Exception;

use Throwable;

interface KnownException extends Throwable
{
/**
* Determine the exception's type.
*
* This should be a short, precise identifier for the error that can be
* exposed to users as an error code. Furthermore, it can be used to find
* appropriate error messages in translations or views to render pretty
* error pages.
*
* Different exception classes are allowed to return the same status code,
* e.g. when they have similar semantic meaning to the end user, but are
* thrown by different subsystems.
*
* @return string
*/
public function getType(): string;

/**
* Determine the HTTP status code to use with this exception.
*
* @return int The HTTP status code to use.
*/
public function getStatusCode(): int;
}
Loading