From ae2e6a2142f01883bb7c7c2fdbb17db3035eb911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Thu, 22 May 2025 06:26:16 +0000 Subject: [PATCH] =?UTF-8?q?[mod]=20alles=20m=C3=B6gliche=20verbessert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notizen.md | 19 +- readme.md | 2 +- source/helpers.php | 268 ---------------------- source/helpers/cache.php | 30 +++ source/helpers/misc.php | 85 +++++++ source/helpers/storage.php | 128 +++++++++++ source/helpers/string.php | 18 ++ source/index.html.php | 222 +++++++++++------- source/logic.php | 146 ------------ source/services/doc.php | 246 ++++++++++++++++++++ source/strings.json | 14 ++ source/style.css | 18 +- source/templates/docs-edit.html.tpl | 27 +-- source/templates/docs-list-entry.html.tpl | 10 +- source/templates/docs-list.html.tpl | 6 +- tools/build | 1 + 16 files changed, 703 insertions(+), 537 deletions(-) delete mode 100644 source/helpers.php create mode 100644 source/helpers/cache.php create mode 100644 source/helpers/misc.php create mode 100644 source/helpers/storage.php create mode 100644 source/helpers/string.php delete mode 100644 source/logic.php create mode 100644 source/services/doc.php create mode 100644 source/strings.json diff --git a/notizen.md b/notizen.md index fe52be4..601cd0c 100644 --- a/notizen.md +++ b/notizen.md @@ -1,19 +1,10 @@ # Notizen -## Ziele - -- soll eine kleine Web-Anwendung werden -- einzige Domäne im Modell ist die der Dokumente -- Eigenschaften von Dokumenten: - - Autor : Zeichenkette - - Titel : Zeichenkette - - Formulierung : Zeichenkette - - Begründung (optional) : Zeichenkette -- dafür soll es ein schlichtes [CRUD](https://de.wikipedia.org/wiki/CRUD) geben -- für jedes bestehende Dokument soll es Funktionen zum Aufbereiten und Herunderladen geben in den Formaten pdf und ogg -- für die Erstellung der Audio-Variante soll nach Möglichkeit [Piper](https://github.com/rhasspy/piper) verwendet werden - - ## Zu erledigen - asynchrones Erstellen der Audio-Dateien (solange nicht fertig, eine Markierung in der Liste anzeigen) +- Persistenz mit SQLite +- Datum für Dokumente ergänzen +- eingebetter Media-Spieler? +- für jedes bestehende Dokument soll es Funktionen zum Aufbereiten und Herunderladen geben in den Formaten pdf/odt (pandoc nutzen) und ogg +- bei Löschung eines Dokuments auch die zugehörigen Dateien löschen diff --git a/readme.md b/readme.md index a40a398..e94faf7 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,7 @@ proof-of-concept für Partei-Arbeits-Dokumenten-Verwaltung, welche hörbare Vers ### Voraussetzungen -- curl +- curl (Debian-Paket-Name: `curl`) ### Anweisungen diff --git a/source/helpers.php b/source/helpers.php deleted file mode 100644 index 87ab5c2..0000000 --- a/source/helpers.php +++ /dev/null @@ -1,268 +0,0 @@ -query($query_template); - /* -$query = "SELECT * FROM books"; -$result = $db->query($query); - -while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - */ -} - - -/** - */ -function database_put(string $query_template, array $arguments) : int -{ - $connection = new \SQLite3('data.sqlite'); - $statement = $connection->prepare($query); - foreach ($arguments as $key => $value) - { - $statement->bindValue( - \sprintf(':%s', $key), - $value['value'], - database_map_type($value['type']) - ); - } - if ($statement->execute()) { - // SELECT last_insert_rowid() - echo "Buch erfolgreich hinzugefügt!"; - } - else - { - echo "Fehler beim Hinzufügen des Buches: " . $db->lastErrorMsg(); - } -} - - -/** - */ -function string_coin(string $template, array $arguments) : string -{ - $result = $template; - foreach ($arguments as $key => $value) - { - $result = \str_replace(\sprintf('{{%s}}', $key), $value, $result); - } - return $result; -} - - -/** - */ -class class_crud_jsonfile -{ - private string $path; - - private \Closure $id_encode; - - private \Closure $id_decode; - - public function __construct( - string $path, - \Closure $id_encode, - \Closure $id_decode - ) - { - $this->path = $path; - $this->id_encode = $id_encode; - $this->id_decode = $id_decode; - } - - private function get() : array - { - $content = (\file_exists($this->path) ? \file_get_contents($this->path) : null); - return ( - ($content === null) - ? - ['last_id' => 0, 'entries' => []] - : - \json_decode($content, true) - ); - } - - private function put(array $data) : void - { - $content = \json_encode($data, \JSON_PRETTY_PRINT); - \file_put_contents($this->path, $content); - } - - public function list_() : array - { - $data = $this->get(); - return \array_map( - fn ($id_encoded) => [ - 'id' => ($this->id_decode)($id_encoded), - 'value' => $data['entries'][$id_encoded], - ], - \array_keys($data['entries']) - ); - } - - public function read(int $id) - { - $data = $this->get(); - $id_encoded = ($this->id_encode)($id); - if (! \array_key_exists($id_encoded, $data['entries'])) - { - throw (new \Exception('not found')); - } - else - { - return $data['entries'][$id_encoded]; - } - } - - public function create($value) : int - { - $data = $this->get(); - $id = ($data['last_id'] + 1); - $id_encoded = ($this->id_encode)($id); - $data['last_id'] = $id; - $data['entries'][$id_encoded] = $value; - $this->put($data); - return $id; - } - - public function update(int $id, $value) : void - { - $data = $this->get(); - $id_encoded = ($this->id_encode)($id); - if (! \array_key_exists($id_encoded, $data['entries'])) - { - throw (new \Exception('not found')); - } - else - { - $data['entries'][$id_encoded] = $value; - $this->put($data); - } - } - - public function delete(int $id) : void - { - $data = $this->get(); - $id_encoded = ($this->id_encode)($id); - if (! \array_key_exists($id_encoded, $data['entries'])) - { - throw (new \Exception('not found')); - } - else - { - unset($data['entries'][$id_encoded]); - $this->put($data); - } - } -} - - -/** - */ -function render(string $template_name, array $arguments) : string -{ - return string_coin( - cache_get( - string_coin( - 'template.{{name}}', - [ - 'name' => $template_name, - ] - ), - fn() => \file_get_contents( - string_coin( - '{{directory}}/templates/{{name}}.html.tpl', - [ - 'directory' => __DIR__, - 'name' => $template_name, - ] - ) - ) - ), - $arguments - ); -} - - -/** - */ -function navigate(string $target) : void -{ - \header('Location: ' . $target); -} - - -/** - */ -function generate_audio(string $name, string $input) : string -{ - $path_wav = string_coin( - '/tmp/{{name}}.wav', - [ - 'name' => $name, - ] - ); - $path_ogg = string_coin( - '{{name}}.ogg', - [ - 'name' => $name, - ] - ); - $command = string_coin( - 'echo "{{input}}" | piper/piper --model piper/voice.onnx --output_file {{path_wav}} ; ffmpeg -y -i {{path_wav}} {{path_ogg}}', - [ - 'input' => $input, - 'path_wav' => $path_wav, - 'path_ogg' => $path_ogg, - ] - ); - exec($command); - return $path_ogg; -} - - ?> diff --git a/source/helpers/cache.php b/source/helpers/cache.php new file mode 100644 index 0000000..a501f52 --- /dev/null +++ b/source/helpers/cache.php @@ -0,0 +1,30 @@ + diff --git a/source/helpers/misc.php b/source/helpers/misc.php new file mode 100644 index 0000000..0ced4e5 --- /dev/null +++ b/source/helpers/misc.php @@ -0,0 +1,85 @@ + $template_name, + ] + ), + fn() => \file_get_contents( + \rosavox\helpers\string_\coin( + '{{directory}}/templates/{{name}}.html.tpl', + [ + 'directory' => /*__DIR__*/'.', + 'name' => $template_name, + ] + ) + ) + ), + $arguments + ); +} + + +/** + */ +function navigate(string $target) : void +{ + \header('Location: ' . $target); +} + + +/** + */ +function generate_audio(string $input, string $output_path) : void +{ + $key = \hash('sha256', $input); + $path_wav = \rosavox\helpers\string_\coin( + '/tmp/{{key}}.wav', + [ + 'key' => $key, + ] + ); + $path_ogg = $output_path; + $command = \rosavox\helpers\string_\coin( + 'echo "{{input}}" | piper/piper --model piper/voice.onnx --output_file {{path_wav}} && ffmpeg -y -i {{path_wav}} {{path_ogg}} ; rm -f {{path_wav}}', + [ + 'input' => $input, + 'path_wav' => $path_wav, + 'path_ogg' => $path_ogg, + ] + ); + \exec($command); +} + + +/** + */ +function translate(string $key, ?array $options = null) : string +{ + $strings = \rosavox\helpers\cache\get( + 'strings', + fn () => \json_decode(\file_get_contents('strings.json'), true) + ); + $options = \array_merge( + [ + 'language' => 'de', + ], + ($options ?? []) + ); + return ($strings[$options['language']][$key] ?? \sprintf('{%s}', $key)); +} + + ?> diff --git a/source/helpers/storage.php b/source/helpers/storage.php new file mode 100644 index 0000000..94149c9 --- /dev/null +++ b/source/helpers/storage.php @@ -0,0 +1,128 @@ +path = $path; + $this->id_encode = $id_encode; + $this->id_decode = $id_decode; + } + + private function get() : array + { + $content = (\file_exists($this->path) ? \file_get_contents($this->path) : null); + return ( + ($content === null) + ? + ['last_id' => 0, 'entries' => []] + : + \json_decode($content, true) + ); + } + + private function put(array $data) : void + { + $content = \json_encode($data, \JSON_PRETTY_PRINT); + \file_put_contents($this->path, $content); + } + + public function list_() : array + { + $data = $this->get(); + return \array_map( + fn ($id_encoded) => [ + 'id' => ($this->id_decode)($id_encoded), + 'value' => $data['entries'][$id_encoded], + ], + \array_keys($data['entries']) + ); + } + + public function read(int $id) + { + $data = $this->get(); + $id_encoded = ($this->id_encode)($id); + if (! \array_key_exists($id_encoded, $data['entries'])) + { + throw (new \Exception('not found')); + } + else + { + return $data['entries'][$id_encoded]; + } + } + + public function create($value) : int + { + $data = $this->get(); + $id = ($data['last_id'] + 1); + $id_encoded = ($this->id_encode)($id); + $data['last_id'] = $id; + $data['entries'][$id_encoded] = $value; + $this->put($data); + return $id; + } + + public function update(int $id, $value) : void + { + $data = $this->get(); + $id_encoded = ($this->id_encode)($id); + if (! \array_key_exists($id_encoded, $data['entries'])) + { + throw (new \Exception('not found')); + } + else + { + $data['entries'][$id_encoded] = $value; + $this->put($data); + } + } + + public function delete(int $id) : void + { + $data = $this->get(); + $id_encoded = ($this->id_encode)($id); + if (! \array_key_exists($id_encoded, $data['entries'])) + { + throw (new \Exception('not found')); + } + else + { + unset($data['entries'][$id_encoded]); + $this->put($data); + } + } +} + + ?> diff --git a/source/helpers/string.php b/source/helpers/string.php new file mode 100644 index 0000000..80daa97 --- /dev/null +++ b/source/helpers/string.php @@ -0,0 +1,18 @@ + $value) + { + $result = \str_replace(\sprintf('{{%s}}', $key), $value, $result); + } + return $result; +} + + ?> diff --git a/source/index.html.php b/source/index.html.php index 751d3f0..ac739e6 100644 --- a/source/index.html.php +++ b/source/index.html.php @@ -1,133 +1,181 @@ $mode]); - $target = \implode( - '&', - \array_map( - fn ($key) => \rosavox\helpers\string_coin( - '{{key}}={{value}}', - [ - 'key' => $key, - 'value' => $a[$key], - ] - ), - \array_keys($a) + return ( + '?' + . + \implode( + '&', + \array_map( + fn ($key) => \rosavox\helpers\string_\coin( + '{{key}}={{value}}', + [ + 'key' => $key, + 'value' => $a[$key], + ] + ), + \array_keys($a) + ) ) ); - \rosavox\helpers\navigate('?' . $target); } + +/** + */ +function nav(string $mode, array $args) : void +{ + \rosavox\helpers\misc\navigate(make_link($mode, $args)); +} + + +/** + */ +function render_list() : string +{ + return \rosavox\helpers\misc\render( + 'docs-list', + [ + 'label_make' => \rosavox\helpers\misc\translate('action.make'), + 'link_make' => make_link('make', []), + 'entries' => \implode( + "\n", + \array_map( + fn ($entry) => \rosavox\helpers\misc\render( + 'docs-list-entry', + [ + 'label_read' => \rosavox\helpers\misc\translate('action.read'), + 'label_hear' => \rosavox\helpers\misc\translate('action.hear'), + 'value_link_open' => make_link('edit', ['id' => \sprintf('%u', $entry['id'])]), + 'value_link_read' => \rosavox\services\doc\readable_path($entry['id']), + 'value_link_hear' => \rosavox\services\doc\audio_path($entry['id']), + 'value_name' => \rosavox\helpers\string_\coin( + '{{name}}.oga', + [ + 'name' => \rosavox\services\doc\name($entry['id']), + ] + ), + 'value_text' => $entry['value']['title'], + ] + ), + \rosavox\services\doc\list_() + ) + ), + ] + ); +} + + +/** + */ +function render_edit(?int $id) : string +{ + $doc = ( + ($id === null) + ? + \rosavox\services\doc\empty_() + : + \rosavox\services\doc\read($id) + ); + return \rosavox\helpers\misc\render( + 'docs-edit', + [ + 'label_action_back' => \rosavox\helpers\misc\translate('action.back'), + 'label_action_save' => \rosavox\helpers\misc\translate('action.save'), + 'label_action_delete' => \rosavox\helpers\misc\translate('action.delete'), + 'label_doc_title' => \rosavox\helpers\misc\translate('domain.doc.title'), + 'label_doc_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'), + 'label_doc_content' => \rosavox\helpers\misc\translate('domain.doc.content'), + 'label_doc_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'), + 'value_action_back' => make_link('list', []), + 'value_action_save' => make_link('save', (($id === null) ? [] : ['id' => \strval($id)])), + 'value_action_delete' => make_link('delete', (($id === null) ? [] : ['id' => \strval($id)])), + 'value_doc_title' => $doc['title'], + 'value_doc_authors' => \implode(', ', $doc['authors']), + 'value_doc_content' => $doc['content'], + 'value_doc_reasoning' => ($doc['reasoning'] ?? ''), + ] + ); +} + + ?> +

rosavox

\implode( - "\n", - \array_map( - fn ($entry) => \rosavox\helpers\render( - 'docs-list-entry', - [ - 'link_open' => \rosavox\helpers\string_coin( - '?mode=edit&id={{id}}', - [ - 'id' => $entry['id'], - ] - ), - 'link_read' => '#not_implemented', - 'link_hear' => \rosavox\logic\docs_audio_path($entry['id']), - 'text' => $entry['value']['title'], - ] - ), - \rosavox\logic\docs_list() - ) - ), - 'link_new' => '?mode=make', - ] - ) - ); - break; - } - case 'make': - { - echo( - \rosavox\helpers\render( - 'docs-edit', - [ - 'id' => '', - 'title' => '', - 'authors' => '', - 'content' => '', - 'reasoning' => '', - 'link_back' => '?mode=list', - ] - ) - ); - break; - } - case 'edit': - { - $doc = \rosavox\logic\docs_read($id); - echo( - \rosavox\helpers\render( - 'docs-edit', - [ - 'id' => $id_encoded, - 'title' => $doc['title'], - 'authors' => \implode(', ', $doc['authors']), - 'content' => $doc['content'], - 'reasoning' => $doc['reasoning'], - 'link_back' => '?mode=list', - ] - ) - ); + if ($id === null) + { + // do nothing + } + else + { + \rosavox\services\doc\delete($id); + } + nav('list', []); break; } case 'save': { $doc = [ - 'title' => $_GET['title'], - 'authors' => \explode(',', $_GET['authors']), - 'content' => $_GET['content'], - 'reasoning' => (empty($_GET['reasoning']) ? null : $_GET['reasoning']), + 'title' => $_POST['title'], + 'authors' => \explode(',', $_POST['authors']), + 'content' => $_POST['content'], + 'reasoning' => (empty($_POST['reasoning']) ? null : $_GET['reasoning']), ]; if ($id === null) { - $id = \rosavox\logic\docs_create($doc); + $id = \rosavox\services\doc\create($doc); } else { - \rosavox\logic\docs_update($id, $doc); + \rosavox\services\doc\update($id, $doc); } - // nav('edit', ['id' => \rosavox\logic\docs_id_encode($id)]); + // nav('edit', ['id' => \rosavox\services\doc\id_encode($id)]); nav('list', []); break; } + case 'list': + { + echo(render_list()); + break; + } + case 'make': + { + echo(render_edit(null)); + break; + } + case 'edit': + { + echo(render_edit($id)); + break; + } default: { throw (new \Exception(\sprintf('invalid mode: %s', $mode))); diff --git a/source/logic.php b/source/logic.php deleted file mode 100644 index b9390dc..0000000 --- a/source/logic.php +++ /dev/null @@ -1,146 +0,0 @@ - $pause, - 'title' => $doc['title'], - 'authors' => implode(', ', $doc['authors']), - 'content' => $doc['content'], - 'macro_reasoning' => ( - ($doc['reasoning'] === null) - ? - '' - : - \rosavox\helpers\string_coin( - "{{pause}}Begründung: {{reasoning}}", - [ - 'pause' => $pause, - 'reasoning' => $doc['reasoning'], - ] - ) - ) - ] - ) - ); -} - - -/** - */ -function docs_list() : array -{ - return docs_state::$crud->list_(); -} - - -/** - */ -function docs_read(int $id) : array -{ - return docs_state::$crud->read($id); -} - - -/** - * @todo async generating - */ -function docs_create(array $doc) : int -{ - $id = docs_state::$crud->create($doc); - docs_generate_audio($id, $doc); - return $id; -} - - -/** - */ -function docs_update(int $id, array $doc) : void -{ - docs_state::$crud->update($id, $doc); - docs_generate_audio($id, $doc); -} - - -/** - */ -function docs_delete(int $id) : void -{ - docs_state::$crud->delete($id); -} - - -/** - */ -function docs_add_examples() : void -{ - docs_create( - [ - 'title' => 'Freibier bei Parteitagen', - 'authors' => [ - 'Björn Biernot', - 'Doreen Dauerdurst', - ], - 'content' => 'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.', - 'reasoning' => 'Wir haben Durst!', - ] - ); -} - - -/** - */ -function docs_init() : void -{ - docs_state::$crud = new \rosavox\helpers\class_crud_jsonfile( - 'docs.json', - fn ($id) => \sprintf('%u', $id), - fn ($id_encoded) => \intval($id_encoded) - ); - if (empty(docs_state::$crud->list_())) - { - docs_add_examples(); - } - else - { - // do nothing - } -} - - ?> diff --git a/source/services/doc.php b/source/services/doc.php new file mode 100644 index 0000000..3c8116d --- /dev/null +++ b/source/services/doc.php @@ -0,0 +1,246 @@ + \rosavox\helpers\misc\translate('domain.doc.title'), + 'value_title' => $doc['title'], + 'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'), + 'value_authors' => \implode( + "\n", + \array_map( + fn ($author) => \rosavox\helpers\string_\coin( + '- {{author}}', + [ + 'author' => $author, + ] + ), + $doc['authors'] + ) + ), + 'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'), + 'value_content' => $doc['content'], + 'macro_reasoning' => ( + ($doc['reasoning'] === null) + ? + '' + : + \rosavox\helpers\string_\coin( + " +## {{label_reasoning}} + +{{value_reasoning}}", + [ + 'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'), + 'value_reasoning' => $doc['reasoning'], + ] + ) + ) + ] + ); + \file_put_contents( + readable_path($id), + $markdown + ); +} + + +/** + */ +function generate_audio(int $id, $doc) : void +{ + $pause = " .\n"; + $text = \rosavox\helpers\string_\coin( + "{{value_title}}{{pause}}{{label_authors}}: {{value_authors}}{{pause}}{{label_content}}: {{value_content}}{{macro_reasoning}}", + [ + 'pause' => $pause, + 'label_title' => \rosavox\helpers\misc\translate('domain.doc.title'), + 'value_title' => $doc['title'], + 'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'), + 'value_authors' => \implode($pause, $doc['authors']), + 'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'), + 'value_content' => $doc['content'], + 'macro_reasoning' => ( + ($doc['reasoning'] === null) + ? + '' + : + \rosavox\helpers\string_\coin( + "{{pause}}{{label_reasoning}}: {{value_reasoning}}", + [ + 'pause' => $pause, + 'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'), + 'value_reasoning' => $doc['reasoning'], + ] + ) + ) + ] + ); + \rosavox\helpers\misc\generate_audio( + $text, + audio_path($id) + ); +} + + +/** + */ +function empty_() : array +{ + return [ + 'title' => '', + 'authors' => [], + 'content' => '', + 'reasoning' => null, + ]; +} + + +/** + */ +function list_() : array +{ + return state::$storage->list_(); +} + + +/** + */ +function read(int $id) : array +{ + return state::$storage->read($id); +} + + +/** + * @todo async generating + */ +function create(array $doc) : int +{ + $id = state::$storage->create($doc); + generate_readable($id, $doc); + generate_audio($id, $doc); + return $id; +} + + +/** + */ +function update(int $id, array $doc) : void +{ + state::$storage->update($id, $doc); + generate_readable($id, $doc); + generate_audio($id, $doc); +} + + +/** + */ +function delete(int $id) : void +{ + state::$storage->delete($id); +} + + +/** + */ +function add_examples() : void +{ + create( + [ + 'title' => 'Freibier bei Parteitagen', + 'authors' => [ + 'Björn Biernot', + 'Doreen Dauerdurst', + ], + 'content' => 'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.', + 'reasoning' => 'Wir haben Durst!', + ] + ); + create( + [ + 'title' => 'Götterdämmerung', + 'authors' => [ + 'Fenriswolf', + ], + 'content' => 'Der Allvater hat mich betrogen. Ich werde ihn und seine elende Asenbrut verschlingen.', + 'reasoning' => null, + ] + ); +} + + +/** + */ +function init() : void +{ + state::$storage = new \rosavox\helpers\storage\class_jsonfile( + 'docs.json', + fn ($id) => \sprintf('%u', $id), + fn ($id_encoded) => \intval($id_encoded) + ); + if (empty(state::$storage->list_())) + { + add_examples(); + } + else + { + // do nothing + } +} + + ?> diff --git a/source/strings.json b/source/strings.json new file mode 100644 index 0000000..31fb4fe --- /dev/null +++ b/source/strings.json @@ -0,0 +1,14 @@ +{ + "de": { + "action.make": "neu", + "action.save": "speichern", + "action.back": "zurück", + "action.delete": "löschen", + "action.hear": "hören", + "action.read": "lesen", + "domain.doc.title": "Titel", + "domain.doc.authors": "Autoren", + "domain.doc.content": "Formulierung", + "domain.doc.reasoning": "Begründung" + } +} diff --git a/source/style.css b/source/style.css index 9ebd55d..8799cb5 100644 --- a/source/style.css +++ b/source/style.css @@ -9,6 +9,7 @@ html color: hsl(var(--hue), 0%, 100%); font-family: sans-serif; + font-size: 1.5em; } body @@ -48,7 +49,7 @@ label > span margin-bottom: 4px; } -input[type="text"] +input { min-width: 480px; padding: 4px; @@ -56,6 +57,8 @@ input[type="text"] background-color: hsl(var(--hue), 0%, 25%); color: hsl(var(--hue), 0%, 100%); + font-size: 1.0em; + border: none; } @@ -68,5 +71,18 @@ textarea background-color: hsl(var(--hue), 0%, 25%); color: hsl(var(--hue), 0%, 100%); + font-size: 1.0em; + border: none; } + +button +{ + text-transform: capitalize; + font-size: 1.0em; +} + +.docs-list-entry > * +{ + vertical-align: middle; +} diff --git a/source/templates/docs-edit.html.tpl b/source/templates/docs-edit.html.tpl index 856cd07..b28a95b 100644 --- a/source/templates/docs-edit.html.tpl +++ b/source/templates/docs-edit.html.tpl @@ -1,26 +1,23 @@
-
- - + - + + +
- zurück
diff --git a/source/templates/docs-list-entry.html.tpl b/source/templates/docs-list-entry.html.tpl index 58590b2..af17860 100644 --- a/source/templates/docs-list-entry.html.tpl +++ b/source/templates/docs-list-entry.html.tpl @@ -1,5 +1,9 @@
  • - {{text}} - | [lesen] - | [hören] + {{value_text}} + | + [{{label_read}}] + | + [{{label_hear}}] + | +
  • diff --git a/source/templates/docs-list.html.tpl b/source/templates/docs-list.html.tpl index 17fd3d9..8a3b60b 100644 --- a/source/templates/docs-list.html.tpl +++ b/source/templates/docs-list.html.tpl @@ -1,6 +1,8 @@
    - Neu +
    + +
    diff --git a/tools/build b/tools/build index 7e29a0b..0e215d7 100755 --- a/tools/build +++ b/tools/build @@ -12,3 +12,4 @@ mkdir -p ${dir_build} cp -r -u lib/* ${dir_build}/ cp -r -u -v ${dir_source}/* ${dir_build}/ cd ${dir_build} && ln -f -s index.html.php index.php ; cd - +mkdir -p ${dir_build}/docs