Просмотр исходного кода

Version 1.0.4 optimized author panel and refactoring

Sebastian 7 лет назад
Родитель
Сommit
7bf12c6fa0
59 измененных файлов с 898 добавлено и 651 удалено
  1. 1 1
      cache/lastCache.txt
  2. 10 10
      composer.lock
  3. 10 9
      content/0_typemill/01-use-cases.md
  4. 11 11
      content/0_typemill/03-features.md
  5. 3 3
      content/0_typemill/09-roadmap.md
  6. 1 1
      content/0_typemill/index.md
  7. 1 1
      content/1_getting-started/00-system-requirements.md
  8. 2 3
      content/1_getting-started/01-installation.md
  9. 1 1
      content/1_getting-started/02-settings.md
  10. 20 4
      content/1_getting-started/03-update.md
  11. 5 3
      content/2_for-writers/00-quick-start.md
  12. 18 0
      content/2_for-writers/03-author-panel.md
  13. 12 6
      content/2_for-writers/05-mardown.md
  14. 13 9
      content/2_for-writers/10-naming-files-and-folders.md
  15. 1 1
      content/2_for-writers/15-folder-structure.md
  16. 1 1
      content/2_for-writers/20-google-sitemap.md
  17. 5 11
      content/2_for-writers/25-themes.md
  18. 6 6
      content/2_for-writers/30-plugins.md
  19. 47 12
      content/3_for-theme-developers/01-quick-start.md
  20. 16 5
      content/3_for-theme-developers/02-theme-structure.md
  21. 55 7
      content/3_for-theme-developers/03-theme-meta.md
  22. 3 4
      content/3_for-theme-developers/04-asset-tags.md
  23. 19 14
      content/3_for-theme-developers/05-twig.md
  24. 1 2
      content/3_for-theme-developers/06-theme-variables/02-content.md
  25. 21 0
      content/3_for-theme-developers/06-theme-variables/03-title.md
  26. 21 0
      content/3_for-theme-developers/06-theme-variables/04-description.md
  27. 16 0
      content/3_for-theme-developers/06-theme-variables/06-image.md
  28. 14 0
      content/3_for-theme-developers/06-theme-variables/08-base-url.md
  29. 0 9
      content/3_for-theme-developers/06-theme-variables/08-description.md
  30. 12 5
      content/3_for-theme-developers/06-theme-variables/10-item.md
  31. 1 1
      content/3_for-theme-developers/06-theme-variables/15-breadcrumb.md
  32. 2 2
      content/3_for-theme-developers/06-theme-variables/25-navigation.md
  33. 24 1
      content/3_for-theme-developers/06-theme-variables/30-settings.md
  34. 1 1
      content/3_for-theme-developers/06-theme-variables/index.md
  35. 19 0
      content/5_info/01-release-notes.md
  36. 1 1
      content/index.md
  37. 12 36
      system/Controllers/PageController.php
  38. 170 198
      system/Controllers/SettingsController.php
  39. 11 7
      system/Controllers/SetupController.php
  40. 6 1
      system/Models/Field.php
  41. 1 1
      system/Models/Folder.php
  42. 6 1
      system/Models/Validation.php
  43. 1 1
      system/Models/VersionCheck.php
  44. 9 1
      system/Routes/Web.php
  45. 24 19
      system/Settings.php
  46. 1 1
      system/author/auth/welcome.twig
  47. 114 39
      system/author/css/style.css
  48. 28 55
      system/author/js/author.js
  49. 1 1
      system/author/partials/aside.twig
  50. 66 0
      system/author/partials/forms.twig
  51. 10 68
      system/author/settings/plugins.twig
  52. 6 3
      system/author/settings/system.twig
  53. 7 68
      system/author/settings/themes.twig
  54. 1 1
      themes/typemill/chapter.twig
  55. 1 1
      themes/typemill/cover.twig
  56. 4 0
      themes/typemill/page.twig
  57. 1 1
      themes/typemill/partials/layout.twig
  58. 24 3
      themes/typemill/typemill.yaml
  59. BIN
      typemill-1.1.4.zip

+ 1 - 1
cache/lastCache.txt

@@ -1 +1 @@
-1524081096
+1525092553

+ 10 - 10
composer.lock

@@ -530,16 +530,16 @@
         },
         {
             "name": "slim/slim",
-            "version": "3.9.2",
+            "version": "3.10.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim.git",
-                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
+                "reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
-                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
+                "reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
                 "shasum": ""
             },
             "require": {
@@ -597,7 +597,7 @@
                 "micro",
                 "router"
             ],
-            "time": "2017-11-26T19:13:09+00:00"
+            "time": "2018-04-19T19:29:08+00:00"
         },
         {
             "name": "slim/twig-view",
@@ -714,16 +714,16 @@
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.8.38",
+            "version": "v2.8.39",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "be720fcfae4614df204190d57795351059946a77"
+                "reference": "d20bd2bdee063863e426297af41eda45ccad6f7e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77",
-                "reference": "be720fcfae4614df204190d57795351059946a77",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/d20bd2bdee063863e426297af41eda45ccad6f7e",
+                "reference": "d20bd2bdee063863e426297af41eda45ccad6f7e",
                 "shasum": ""
             },
             "require": {
@@ -759,7 +759,7 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2018-01-03T07:36:31+00:00"
+            "time": "2018-04-08T07:53:13+00:00"
         },
         {
             "name": "twig/twig",

+ 10 - 9
content/0_typemill/01-use-cases.md

@@ -1,20 +1,21 @@
 # Use Cases
 
-Whenever you want to publish a finished text work as a website, then TYPEMILL is a smart and lightweight solution. Possible use cases are ...
+Whenever you want to publish a finished text work as a website and if you like writing with Markdown, then TYPEMILL is a smart and lightweight solution. Possible use cases are ...
 
-- a book
-- a drama
-- a lyric collection
-- a whitepaper
 - a documentation
-- a manual or user guide
+- a manual
+- a user guide
+- a whitepaper
 - a handbook
 - a tutorial
 - a study
+- a book
+- a drama
+- a lyric collection
 - a collection of articles
 
-TYPEMILL is not a full blown Content Management System (CMS). It has no admin panel and it does not support any content creation right now. Instead, it takes some existing markdown files and generates a beautiful website. 
+If you want to create a blog, a wiki or a classic corporate website, please use a specialized CMS for that instead of TYPEMILL.
 
-Use your favourite text or markdown editor (e.g. Typora) to create markdown files and upload them with a FTP software (e.g. FileZilla) to your server.
+TYPEMILL is under heavy developement and not finished right now. It has an admin panel for settings, but it does not provide an online content editor at the moment. An online editor and different output formats like mobi and ePup are on the roadmap, so stay tuned.
 
-TYPEMILL is not the right solution, if you want to create a blog, a wiki or any website with an author interface. But it is a smart solution to publish any text work based on markdown files.
+For time being, you can use an offline markdown-editor like Typora and upload your content-files with a FTP software like FileZilla.

+ 11 - 11
content/0_typemill/03-features.md

@@ -4,20 +4,20 @@ TYPEMILL has a limited set of features right now. It transforms a bunch of **mar
 
 This is what you can **do with TYPEMILL**:
 
-- Create a website content with simple folders and files (markdown).
-- Use an author panel to configure your site, choose themes and activate plugins.
+- Create a website with simple files and folders.
+- Use markdown for your content files.
+- Use an admin panel to configure your site.
+- Choose themes and activate plugins.
 - Create your own theme with HTML, CSS and Twig (a template language for PHP).
-- Create your own plugins.
+- Create your own plugins with PHP.
 
 This is, what **TYPEMILL does** for you:
 
-- It creates a website based on your folders and files.
-- It generates a navigation according to the structure of your folders and files.
-- It adds a paging.
-- It adds a breadcrumb.
+- It creates a website based on your files and folders.
+- It generates a navigation according to the structure of your files and folders.
+- It adds a paging for navigation.
+- It adds a breadcrumb for navigation.
 - It adds hierarchic numbers to your chapters and pages.
-- It makes everything responsive for mobile devices.
+- It generates a google sitemap, a last modified date and much more.
 
-Right now there is no content editor, so you have to create and edit your content offline with a markdown editor and upload the files with an FTP software. 
-
-But a content editor will follow soon and we have a great roadmap for TYPEMILL.
+Right now there is no content editor, so you have to create and edit your content offline with your favourite markdown editor (e.g. Typora) and upload the files with an FTP software. But a content editor will follow soon and we have a great roadmap for TYPEMILL.

+ 3 - 3
content/0_typemill/09-roadmap.md

@@ -2,18 +2,18 @@
 
 There are a lot of plans for future releases of TYPEMILL, but it also follows the concept of simplicity. To prevent TYPEMILL from becomming a feature soup, it will strictly focus on the writers needs. 
 
-Here are some milestones of the past:
+Here are some **milestones** of the past:
 
 - Introduction of TYPEMILL version 1.0.0
 - Added a table of contents tag (TOC) with version 1.0.5
 - Introduced plugins with version 1.1.0
 - Added an author panel to configure the system with version 1.1.3
 
-And here is the roadmap for the future:
+And here is the **roadmap** for the future:
 
+- Support mathematical formulars for scientific text works.
 - Add a content editor to create and edit your pages online.
 - Add an Image- and media-management.
-- Support mathematical formulars for scientific text works.
 - Create additional output formats like mobi, epub and pdf.
 - Create a clean API.
 - More themes for special publications like documentations, books or lyrics.

+ 1 - 1
content/0_typemill/index.md

@@ -1,3 +1,3 @@
 #About TYPEMILL
 
-TYPEMILL is a simple tool to create a website like this. It transforms a bunch of **text files** (Markdown) into a **website** and generates a **navigation**. TYPEMILL is a perfect tool for web books, documentations or manuals.
+TYPEMILL is a simple flat file CMS to create a website like this. It transforms a bunch of **text files** (Markdown) into a **website** and generates a **navigation**. TYPEMILL is under construction and provides a simple admin area for settings right now. An online editor and different output formats for e-books like mobi and epub are on their way. If you are a developer: TYPEMILL already supports themes and plugins.

+ 1 - 1
content/1_getting-started/00-system-requirements.md

@@ -12,4 +12,4 @@ What you don't need:
 - **A database** (TYPEMILL uses files, not a database)
 - **Technical skills** (TYPEMILL is easy to use for non-technical people)
 
-Almost any hosting package provides a webserver with php. If you ever hosted a website with WordPress, then chances are high, that you can run TYPEMILL there without any problems.
+Almost any hosting package provides a webserver with php. If you ever hosted your own website, then chances are high, that you can run TYPEMILL there without any problems.

+ 2 - 3
content/1_getting-started/01-installation.md

@@ -15,7 +15,7 @@ Don't forget to make some folders and files writable (set permission to `774`):
 
 All settings and users are stored in the folder `settings`. You can manually edit these files, but it is not recommended because it can crash the system if done wrong.
 
-You can configure your system online, but there is no content editor yet. So for time beeing, you have to edit your content offline with a markdown editor and upload the files with an FTP software. If your changes are not visible at once, press `F5` to refresh the cache.
+You can configure your system online, but there is no content editor yet. So for time beeing, you have to edit your content offline with a markdown editor and upload the files with an FTP software. If your changes are not immediately visible, press `F5` to refresh the cache.
 
 If you need more detailed instructions, please read on.
 
@@ -54,9 +54,8 @@ To make the folders and files writable, use your ftp programm, click on the fold
 
 ## htaccess 
 
-If you run your website with https (recommended) or if you want to redirect www-urls to non-www urls, then please check the htaccess file in the root folder. There are several use cases already prepared and you only have to uncomment them. 
+If you run your website with https (recommended) or if you want to redirect www-urls to non-www urls, then please check the htaccess file in the root folder. There are several use cases already prepared and you can simply uncomment them, if needed. 
 
 ## Run Locally
 
 If you are a developer and if you want to run TYPEMILL locally, then simply download TYPEMILL (zip or git) and visit your local folder like `localhost/typemill`. No additional work is required.
-

+ 1 - 1
content/1_getting-started/02-settings.md

@@ -1,6 +1,6 @@
 # Settings
 
-As of Version 1.1.3 you can edit all settings in the new authoring panel of TYPEMILL. Just login and go to settings. There you can edit:
+As of Version 1.1.3 you can edit all settings in the new authoring panel of TYPEMILL. Just login to your typemill installation and go to settings. There you can edit:
 
 * The system (basic settings).
 * Themes (choose themes and configure it).

+ 20 - 4
content/1_getting-started/03-update.md

@@ -1,14 +1,16 @@
 # Update
 
-If your TYPEMILL version or any plugin or theme is not up to date, you will find update notices in the author panel. 
+If your TYPEMILL version or any plugin or theme is not up to date, you will find individual update banners in the author panel. 
 
 ## Simple Update
 
-To update your TYPEMILL version, simply download the latest version of TYPEMILL on [the TYPEMILL website](http://typemill.net). Then delete the old `system` folder on your server and upload the new system folder. 
+To update your TYPEMILL version, simply download the latest version of TYPEMILL on [the TYPEMILL website](http://typemill.net). Then delete the old `system` folder on your server and upload the new system folder. All other files and folders can usually stay untouched. 
+
+After you updated your installation, please login to your website and check the settings. Sometimes, there are additional features that you can find there.
 
 ## Major Update
 
-TYPEMILL is in early stage and there are a lot of basic changes right now. When there are basic changes, then you should update everything like this:
+TYPEMILL is in early stage and there are a lot of basic changes right now. When there are basic changes, then you should update the whole installation like this:
 
 * Backup your settings folder
 * Keep your content folder
@@ -22,4 +24,18 @@ TYPEMILL is in early stage and there are a lot of basic changes right now. When
 * Go to `your-typemill-website.com/setup` and create a new user.
 * Setup your website again in the author panel.
 
-In most cases you can also user your old settings-file from your backup, but if it does not work, simply setup the system again.
+In many cases you can also use your old settings folder, so it is highly recommended to create a backup and test it. But sometimes, the new version requires a new setup of the system, so if you want to do it the clean way, just start and setup your system again.
+
+## GitHub and Composer
+
+If you work with GitHub and Composer, then make sure that you **always** make a `composer update` after you uploaded the new system-folder from GitHub. This is essential, because the GitHub-folder does NOT include the vendor folder with all the dependencies that TYPEMILL uses. If you don't update these dependencies with composer, then the system will not run. 
+
+If you download the TYPEMILL from http://typemill.net, then you don't have to worry about this, because the vendor folder with all dependencies is included there.
+
+We decided to skip the vendor folder in the GitHub version because it constantly caused errors due to some missing libraries.
+
+## Old Settings File
+
+Please do not rename or leave the old settings file in the settings folder, because any files in that folder will cause errors and problems. Instead, backup your old settings file in another folder or on your local machine.
+
+If it is only a minor update, you can leave your settings folder untouched and change everything in the author-panel after the update.

+ 5 - 3
content/2_for-writers/00-quick-start.md

@@ -2,10 +2,12 @@
 
 You are a pro and don't want to read the whole manual? No problem, this is a quick overview:
 
-- **Folders and files**: Organize your content in folders and markdown files and put them in the `\content` folder of TYPEMILL. 
-- **Naming conventions**: Use prefixes like `01-` or `aa_` to sort your folders and files.
+- **Setup**: Login to your system and setup the system, the themes and the plugins in the author panel.
+- **Content**: Organize your content in folders and markdown files and put them in the `\content` folder of TYPEMILL. 
 - **Markdown**: Use the Markdown syntax for your content files. Markdown Extra (e.g. tables, footnotes) is supported, too.
+- **Naming conventions**: Use prefixes like `01-` or `aa_` to sort your folders and files.
 - **Index files**: Add an `index.md` file to a folder to create content for the folder itself.
 - **F5**: After some changes, use the `F5` key to refresh the navigation manually.
-- **Settings**: Use the file `settings.yaml` in the root folder to change the theme or other settings.
 - **Lean back** and let TYPEMILL create a nice website for you.
+
+The TYPEMILL system ships with this user manual in the content folder. So you can check folder and look how the files are written and the folders are organized.

+ 18 - 0
content/2_for-writers/03-author-panel.md

@@ -0,0 +1,18 @@
+# The Author Panel
+
+After you have setup your TYPEMILL website, you can login to the author panel. The login url is 
+
+````
+https://yourwebsite.net/tm-author/login
+````
+
+You can also use the url `https://yourwebsite.net/setup` that redirects to the login screen.
+
+In the **settings area** of the author panel you can:
+
+* Configure your **system**.
+* Choose and configure a **theme**.
+* Activate and configure **plugins**.
+* Manage **users**.
+
+the **content area** of the author-panel is not ready yet, but it is on it's way and will be published in near future. Then you can create and manage all the content of your website online. For time being you have to create your content offline e.g. with a markdown editor and upload your content files with a FTP software.

+ 12 - 6
content/2_for-writers/05-mardown.md

@@ -8,7 +8,7 @@ Never heard of Markdown? Markdown is  very similar to the markup used by Wikiped
 
 Today, Markdown is a standard formatting language used by a lot of technology platforms like GitHub or StackOverflow. And Markdown is also entering the non technical mainstream. The press releases of dpa are written in Markdown, for example.
 
-Markdown uses some special chars like `#` or `-` to format a text. A short example: 
+Markdown uses some special characters like `#` or `-` to format a text. A short example: 
 
 ````
 # My first level headline
@@ -27,7 +27,7 @@ There are some good reasons for the rise of Markdown:
 - Different to proprietary formats like word.docx, the Markdown syntax is universal and not bound to a special text software.
 - You can use the most simple text editor (e.g. the "editor" of microsoft office) or a special Markdown editor like Typora to create Markdown files.
 - Markdown can be transformed into a valid HTML document easily.
-- Compared to the well known WISYWIG HTML editors (e.g. used by WordPress), Markdown is less hacky and the content is more reusable.
+- Compared to the well known WISYWIG HTML editors (e.g. used by WordPress), Markdown is less hacky, more secure and the content is more reusable.
 
 There are also some disadvantages:
 
@@ -76,7 +76,7 @@ Just use the character `#` for headlines like this:
 
 ### Lists
 
-To create an unordered `-` or ordered `1.` list, just follow your intuition:
+To create an unordered `-` / `*`or ordered `1.` list, just follow your intuition:
 
 ````
 This is an unordered list: 
@@ -85,7 +85,13 @@ This is an unordered list:
 - Another item
 - Last item
 
-And this is an ordred list: 
+You can write it this way:
+
+* Item
+* Another item
+* Last item
+
+And this is an ordered list: 
 
 1. Item 1
 2. Item 2
@@ -134,7 +140,7 @@ Images look similar to links, simply add an ! like this:
 
 ### Code (inline)
 
-To create a inline code, just use the ` sign like this:
+To create inline code, just use the ` sign like this:
 
 ````
 Inline code `<?php echo 'hello world!'; ?>` within a sentence.
@@ -161,4 +167,4 @@ As of version 1.0.5 you can use the tag `[TOC]` to create a table of contents. S
 
 ### Advanced Formats
 
-With enhancements like Markdown Extra you can also create more complex formats like tables, abbreviations, footnotes and special attributes. TYPEMILL supports Markdown Extra, so just check the [specification of Markdown Extra](https://michelf.ca/projects/php-markdown/extra/) if you want to use these kind of formats.
+You can also create more complex formats like tables, abbreviations, footnotes and special attributes.  Just check the [specification of Markdown Extra](https://michelf.ca/projects/php-markdown/extra/) if you want to use these kind of formats.

+ 13 - 9
content/2_for-writers/10-naming-files-and-folders.md

@@ -2,18 +2,22 @@
 
 To create a clean website with TYPEMILL, you have to follow some naming conventions for your files and folders. A typcial structure for folders and file looks like this:
 
-- 01_content_folder
-  - 01_markdown_file.md
-  - 02_another_markdown_file.md
-  - index.md
+````
+/01_content_folder
+  01_markdown_file.md
+  02_another_markdown_file.md
+  index.md
+/02_another_folder
+  01_another_content_file.md
+````
 
 The rules are simple: 
 
-- **Keep it short**: The names of the files and folders are used to create the navigation, so it is essential to keep them really short!!
+- **Keep it short**: The names of the files and folders are used to create the navigation, so it is essential to keep them really short and descriptive!!
 - **Use prefixes**: Please use some kind of sorting-prefix for your files and folders. You can use numbers `01-` or letters `aa-`. The part before the first separator (the prefix) is striped out by TYPEMILL.
-- **Use Separators**: Please use separators like dashes `-` or underscores `_` to separate words or prefixes in your file names and folder names. Do not use space!!!
-- **Use index.md**: You can use a file named `index.md` to create content for the folder itself. This is optional.
-- **Avoid Language Specific Characters**: As of version 1.0.5. the character encoding has been improved. You can try to use german, french or other character sets to name your files and folders now. If you see some errors in the Navigation of the website, please use english characters instead. In the content itself you can use all character sets of course.
+- **Use Separators**: Please use separators like dashes `-` or underscores `_` to separate words or prefixes in your file names and folder names. **Do not use space**!!!
+- **Use index.md**: TYPEMILL creates websites for the folders and users can click on folder-names exactly like they click on file-names in the navigation. Folder pages are empty by default, but you can use a file named `index.md` to create content for the folder page.
+- **Avoid Language Specific Characters**: As of version 1.0.5 the character encoding has been improved, but it is still not perfect. You can try to use german, french or other character sets to name your files and folders. But if you see some errors in the navigation of the website, please use english characters instead. In the content files itself you can use all character sets of course.
 
-When you name your files and folders, then always keep in mind, that the names are used to generate the navigation and the table of contents. So keep it short to keep the layout and design healthy.
+When you name your files and folders, then always keep in mind, that the names are used to generate the navigation and the table of contents. So keep it short. Otherwise it might break the layout and the design.
 

+ 1 - 1
content/2_for-writers/15-folder-structure.md

@@ -1,5 +1,5 @@
 # Folder Structure
 
-You can create any kind of folder structer with TYPEMILL. As long as you follow the naming conventions for folders and files, it will work.
+You can create any kind of folder structure with TYPEMILL, as long as you follow the naming conventions for folders and files.
 
 However, if you create a very deep structure, then it might result in an odd design or even in usability errors. Similar to real live, it is always a good idea to keep the hierarchy as flat as possible.

+ 1 - 1
content/2_for-writers/20-google-sitemap.md

@@ -1,3 +1,3 @@
 # Google Sitemap
 
-As of version 1.0.1, TYPEMILL creates a google sitemap in the cache folder. You can reach the sitemap with the url `http:yourwebsite.net/cache/sitemap.xml` and add the sitemap to the google search console. The sitemap will update once a day. You can also trigger a manual update with a refresh of your browser (F5).
+As of version 1.0.1, TYPEMILL creates a google sitemap in the cache folder. You can reach the sitemap with the url `https://yourwebsite.net/cache/sitemap.xml` and add the sitemap to the google search console. The sitemap will update once a day. You can also trigger a manual update with the F5 key (Windows) that refreshs the cache of your browser and the cache of TYPEMILL.

+ 5 - 11
content/2_for-writers/25-themes.md

@@ -1,15 +1,9 @@
-# Plugins
+# Themes
 
-As of version 1.1.0, TYPEMILL supports plugins. Right now all plugins are delivered with TYPEMILL by default. But as the number of plugins grows, there will probably be a central place to download and install the plugins in the future.
+TYPEMILL ships with the standard theme called "Typemill". Typemill is a univeral theme the fits for documentations as well as for any other kind of text-work. There are plans to add a lot more themes for specific need s in the future.
 
-For now, you can simply activate and setup the plugins in the TYPEMILL setup. If you want to change the settings for the plugins after the setup, then you can edit everything in the file `/settings/settings.yaml`.
+You can configure the theme in the settings of the author panel. You will see an update banner, if there is a new version of the theme available.
 
-Plugins are right now:
+To update a theme, simply go to the theme folder of your typemill installation, delete the old folder of your theme (e.g. `/typemill`) and upload the new folder.
 
-* **Cookie Consent**: This plugin adds a cookie consent banner to your website. You can change the colors and the text in the plugin-settings.
-* **Analytics**: This plugin adds an analytics-script for Matomo (Piwik) and Google Analytics.
-* **Disqus**: This plugin adds the comment system discuss to your content pages. It does not add the script to folder-pages, but only to real content pages.
-
-You can always activate and deactivate a plugin. But you can also delete a plugin from the plugin-folder, if you care about your webspace.
-
-Plugins have versions. If a plugin is outdated, then it is visible in the TYPEMILL setup. This is not too helpful right now because you can only visit the public setup page one time. But in near future, you will have access to the setup in the admin area with a login.
+If you are a developer or web-designer, you can easily create your own theme with the template language Twig. Please read the [theme documentation](/theme-developers) for more details.

+ 6 - 6
content/2_for-writers/30-plugins.md

@@ -1,15 +1,15 @@
 # Plugins
 
-As of version 1.1.0, TYPEMILL supports plugins. Right now all plugins are delivered with TYPEMILL by default. But as the number of plugins grows, there will probably be a central place to download and install the plugins in the future.
+As of version 1.1.0, TYPEMILL supports plugins. You can activate and configure all plugins in the author panel of TYPEMILL. You will see a small update banner if there exists a new version of the plugin.
 
-For now, you can simply activate and setup the plugins in the TYPEMILL setup. If you want to change the settings for the plugins after the setup, then you can edit everything in the file `/settings/settings.yaml`.
+To update a plugin, simply go to the plugin folder of TYPEMILL, delete the plugin and upload the new version of the plugin. Then check the plugin configuration in the settings of the author panel. 
 
-Plugins are right now:
+Right now all plugins are delivered with the core version of TYPEMILL. But as the number of plugins grows, there will probably be a central place to download and install the plugins in the future.
+
+The core version ships with two plugins:
 
 * **Cookie Consent**: This plugin adds a cookie consent banner to your website. You can change the colors and the text in the plugin-settings.
 * **Analytics**: This plugin adds an analytics-script for Matomo (Piwik) and Google Analytics.
-* **Disqus**: This plugin adds the comment system discuss to your content pages. It does not add the script to folder-pages, but only to real content pages.
 
-You can always activate and deactivate a plugin. But you can also delete a plugin from the plugin-folder, if you care about your webspace.
+If you are a developer and if you want to create your own plugins, please refer to the [plugin documentation](/plugin-developers).
 
-Plugins have versions. If a plugin is outdated, then it is visible in the TYPEMILL setup. This is not too helpful right now because you can only visit the public setup page one time. But in near future, you will have access to the setup in the admin area with a login.

+ 47 - 12
content/3_for-theme-developers/01-quick-start.md

@@ -1,6 +1,6 @@
 # Quick Start for Theme-Developers
 
-You are a professional and don't want to read the whole documentation? No problem, this is all you need to know to create your own theme for TYPEMILL. 
+You are a professional web developer and don't want to read the whole documentation? No problem, this is all you need to know to create your own theme for TYPEMILL. 
 
 ## Theme Folder
 
@@ -8,7 +8,7 @@ You will find all themes in the `theme` folder of TYPEMILL. You can add a new fo
 
 ## Change Theme
 
-You can change the theme for typemill in the `settings.yaml`, that you will find in the settings-folder. Simply add the name of the theme there.
+You can choose the theme in author panel of TYPEMILL.
 
 ## Theme Structure
 
@@ -19,9 +19,9 @@ There is no theme structure. There are only two files that are required:
 
 There is another optional template:
 
-- `cover.twig`: Use this name to create a template for a static startpage.
+- `cover.twig`: Use this name to create a template for a special startpage with a different design.
 
-And there are two other files your theme should have:
+There are two other files that are optional, but it is strongly recommended to add them:
 
 * `themeName.jpg`: A preview picture of your theme with a minimal width of 800px;
 * `themeName.yaml`: A configuration file with the version, the author name, licence and other informations.
@@ -30,7 +30,7 @@ It is always a good idea to structure your files a bit more. For example, you ca
 
 ## Theme-YAML
 
-The `themeName.yaml` must have the same name as your theme folder. It should look like this:
+The `themeName.yaml` must have the same name as your theme folder. A basic file looks like this:
 
 ````
 name: My Theme Name
@@ -41,6 +41,41 @@ homepage: http://an-info-website-for-the-theme.com
 licence: MIT
 ````
 
+You can also add settings for your themesi in the YAML-file like this:
+
+````
+settings:
+  chapter: Chapter
+  start: Start
+````
+
+The settings are automatically merged with all other TYPEMILL settings and are available on all pages, so you can access your theme variables like this:
+
+````
+{{ settings.themes.typemill.chapter }} // prints out "Chapter".
+````
+
+Finally you can make your theme variables editable for the user in the author panel. Just add a form definition in your yaml like this:
+
+````
+forms:
+  fields:
+
+    chapter:
+      type: text
+      label: chapter
+      placeholder: Add Name for Chapter
+      required: true
+
+    start:
+      type: text
+      label: Start-Button
+      placeholder: Add Label for Start-Button
+      required: true
+````
+
+This will create input forms in the author panel. The input forms will be prefilled with the settings-values of your YAML-file.
+
 ## Twig
 
 TYPEMILL uses Twig as a template language. You are probably familiar with it. If not: Twig is a widespread template language, that is very easy to learn. It is shorter and safer to use than pure PHP.
@@ -49,30 +84,30 @@ TYPEMILL uses Twig as a template language. You are probably familiar with it. If
 
 There are exactly six template variables to fill your templates with dynamic content:
 
-- `navigation`: This variable is a multidimensional array of objects. Each object represents a file or a folder. You can use this variable to create a navigation with a Twig-macro. A macro in TWIG is the same as a recursive function in PHP. 
-- `item`: This variable is an object of the actual page. It contains all the details like name, url, path, chapter as well as the next and previous items for a pagination. And guess what? The `navigation` variable is just an array, that hold many of these item-objects (with a bit less informations).
+- `navigation`: This variable is a multidimensional array of objects. Each object represents a file or a folder. You can use this variable to create a navigation with a Twig-macro. A macro in Twig is the same as a recursive function in PHP. 
+- `item`: This variable is an object of the actual page. It contains all the details like the name, the url, the path, the chapter as well as the next and the previous items for a pagination. And guess what? The `navigation` variable mentioned above is just an array, that holds many of these item-objects.
 - `content`: This variable holds the HTML content of the markdown file. Just print it out.
-- `description`: This are the first 150 characters of the content of a page. You can use this for the meta description.
+- `description`: This are the first lines of the content of a page. You can use this for the meta description.
 
 
 - `breadcrumb`: This variable is an one dimensional array. It contains the breadcrumb of the page. Just use a loop like  `{% for element in breadcrumb %}` to print it out.
-- `settings`: In this varialbe, you will find all the settings like the navigation-title, the author, the theme or the copyright.
+- `settings`: In this variable you will find all the settings like the navigation-title, the author, the theme, the theme variables or the copyright.
 
 You can print out each variable with the twig-tag `{{ dump(navigation) }}` and inspect the content. This is probably the easiest way to familiarize with the possibilities for themes.
 
 ## Asset Tags
 
-Plugin-Developers want to add CSS and JavaScript into your theme. You should enable plugin-developers to do so with two Twig-tags:
+Plugin-developers want to add their own CSS and JavaScript to your theme. You should enable plugin-developers to do so with two Twig-tags:
 
 * `{{ assets.renderCSS() }}`: Put this before the closing `</head>`-tag of your theme.
 * `{{ assets.renderJS() }}`: Put this before the closing `</body>`-tag of your theme. 
 
 ## Content-Styling
 
-If you create a theme, make sure that all content types are styled correctly. You can use the [markdown-test-page](/info/markdown-test) to check the styling of all content-elements.
+If you create a theme, make sure that all content types (headlines, paragraphs, tables) are styled properly. You can use the [markdown-test-page](/info/markdown-test) to check the styling of all content-elements.
 
 ## Read more
 
-If you are not ready to start with these information, then please read the full developer manual. In less than one hour you can develop with TYPEMILL like a pro.
+If you are not ready to start with these information, then please read the full developer manual. In less than one hour you can develop your own themes for TYPEMILL like a pro.
 
 Happy coding!

+ 16 - 5
content/3_for-theme-developers/02-theme-structure.md

@@ -2,12 +2,23 @@
 
 TYPEMILL requires a minimal structure and a small set of mandatory files:
 
+````
+/myTheme
+- 404.twig
+- index.twig
+- cover.twig
+- myTheme.jpg
+- myTheme.yaml
+````
+
+Some Details:
+
 - **/myTheme**: A theme folder. The name of the folder is the name of the theme.
-  - **404.twig**: The template for a not found page. It is mandatory.
-  - **index.twig**: The template for all other pages. It is mandatory.
-  - **cover.twig**: The template for a different startpage-design. It is optional.
-  - **myTheme.jpg**: A preview picture of your theme. It is mandatory. The file must be named exactly like the theme folder. Minimum width is 800px.
-  - **myTheme.yaml**: A configuration file for your theme with author, version number and others. This is not mandatory, but highly recommended. The file must be named exactly like the theme folder.
+- **404.twig**: The template for a not found page. It is mandatory.
+- **index.twig**: The template for all other pages. It is mandatory.
+- **cover.twig**: The template for a different startpage-design. It is optional.
+- **myTheme.jpg**: A preview picture of your theme. It is mandatory. The file must be named exactly like the theme folder. Minimum width is 800px.
+- **myTheme.yaml**: A configuration file for your theme with author, version number and others. This is not mandatory, but highly recommended. The file must be named exactly like the theme folder.
 
 That's it.
 

+ 55 - 7
content/3_for-theme-developers/03-theme-meta.md

@@ -1,6 +1,14 @@
 # Theme Meta with YAML
 
-You can add some meta-information to your theme with a small YAML-file. The YAML-file must have the same name as your theme folder. The yaml-file has some useful standard-information and looks like this:
+It is highly recommendet to add some meta-information to your theme. This is quickly done with a small YAML-file. The YAML-file must have the same name as your theme folder. The YAML-file has up to three parts and is used for this:
+
+* Display basic informations in the author-panel and generate update notifications.
+* Use settings (variables) for your theme if you want.
+* Let users edit the settings and customize the theme in the author-panel.
+
+## Add Basic Informations 
+
+The basic informations in the YAML-file look like this: 
 
 ```
 name: My Theme Name
@@ -11,11 +19,51 @@ homepage: http://an-info-website-for-the-theme.com
 licence: MIT
 ```
 
-Why is this useful? Some reasons:
+As you can see the YAML-syntax is simple and readable even for non-technicians. Inside TYPEMILL the YAML-files are converted to one-dimensional or multi-dimensional arrays, so you can think about YAML as a simplified array language, if that helps. 
+
+## Use Settings
+
+Sometimes you want to use variables in your theme, for example to change the text of a button. With YAML you can easily do this: Just create a new block that starts with `settings` and write all your settings as simple key-value-pairs. Indent them with two spaces like this: 
+
+```
+settings:
+  chapter: Chapter
+  start: Start
+```
+
+The settings are automatically merged with all other TYPEMILL settings and are available in your themes with a simple Twig tag like this:
+
+```
+{{ settings.themes.typemill.chapter }} // prints out "Chapter".
+```
+
+Replace  `typemill` with the name of your theme like this:
+
+````
+{{ settings.themes.mytheme.chapter }}
+````
+
+## Make Settings Editable
+
+Finally you can make your theme variables editable for the user in the author panel. To do this, just add another block that starts with `forms` and `fields`. After that, you can define a wide range of input fields with YAML. It starts with the name of the field followed by the field definition. 
+
+```
+forms:
+  fields:
+
+    chapter:
+      type: text
+      label: chapter
+      placeholder: Add Name for Chapter
+      required: true
+
+    start:
+      type: text
+      label: Start-Button
+      placeholder: Add Label for Start-Button
+      required: true
+```
 
-* The user can see, if his version is outdated and then update his theme to a actual version.
-* You can add a licence, that is displayed in the setup.
-* You can add your name as an author-name. This is also displayed in the setup.
-* You can add a homepage with further informations and theme-updates, that is also displayed in the setup.
+TYPEMILL will use these definitions and generate input fields for the author panel on the fly, so that the user can edit the values and customize the theme. If you have defined settings with the same name as the field name (e.g. `chapter`), then the input field in the author panel will automatically be prefilled with your settings from the YAML-file. 
 
-A YAML-file with meta-informations is not mandatory, so your theme will work without it. But it is highly recommended.
+If you read the YAML-definition for input fields carefully, then you will notice that the definitions are pretty similar HTML: You simply define types and attributes like input-type, labels and placeholders. Nearly all valid field-types and field attributes are supported. You can find a detailed list in the [documentation for plugins](/plugin-developers/documentation/field-overview).

+ 3 - 4
content/3_for-theme-developers/04-asset-tags.md

@@ -2,12 +2,12 @@
 
 Sometimes, a plugin wants to add some CSS and JavaScript to your theme. For example, the cookieconsent-plugin. It adds a cookie-consent popup to all pages, so that users can agree to the cookie policy of your website.
 
-There are two Twig-tags, that allow plugins to add JavaScript and CSS. And you should add them to your theme. Otherwise, those plugins won't work:
+There are two Twig-tags, that allow plugins to add JavaScript and CSS. Please make sure that you add these tags to your theme, because otherwise, the plugins won't work:
 
 - `{{ assets.renderCSS() }}`
 - `{{ assets.renderJS() }}`
 
-You should follow best practice and add the CSS-tag after all your css-files and before the closing head-tag. It is also a good practice in Twig, to wrap your ressources in a block-tag. You can read more about this in the Twig-chapter.
+It is recommended to add the CSS tag after all your css-files and before the closing head-tag. It is also a good practice in Twig, to wrap your ressources in a block-tag. You can read more about this in the Twig-chapter.
 
 ````
 <html>
@@ -24,7 +24,7 @@ You should follow best practice and add the CSS-tag after all your css-files and
  </head>
 ````
 
-The same for JavaScript: It is a good practice to place all JavaScript at the end of the page before the closing body-tag. And you should wrap all your JavaScript in a block-element, too:
+The same for JavaScript: It is recommended to place all JavaScript at the end of the page before the closing body-tag. And you should wrap all your JavaScript in a block-element, too:
 
 ````
 <body>
@@ -42,4 +42,3 @@ The same for JavaScript: It is a good practice to place all JavaScript at the en
  {% endblock %}		
 </body>   
 ````
-

+ 19 - 14
content/3_for-theme-developers/05-twig.md

@@ -1,10 +1,10 @@
 # Templates with Twig
 
-Twig is a flexible, fast and secure template engine for PHP. If you have never used a template language before, then there are some good reasons to start with it today:
+Twig is a flexible, fast and secure template engine for PHP. Twig is used by many modern software projects and content management systems like CraftCMS, Statamic and even Drupal. If you have never used a template language before, then there are some good reasons to start with it today:
 
 - The Twig syntax is **much shorter**, so your templates look cleaner and are easier to maintain.
-- Twig produces **less errors**. An unknown variable produces an error in PHP, but it does not in Twig. Twig handles most of these cases, so you don't have to care about it.
-- Twig is very **widespread**. Even Drupal switched to Twig in version 8.
+- Twig produces **less errors**. An unknown variable produces an error in PHP, but it does not in Twig. Twig handles most of these cases, so you skip a lot of ugly logic in your theme.
+- Twig is very **widespread**, so you can work with Twig in many other cms.
 
 The full Twig documentation for template designers is just one page long, so just head [over to Twig](http://twig.sensiolabs.org/doc/2.x/templates.html) and read it. You can learn the most important essentials for TYPEMILL in the following list.
 
@@ -30,7 +30,7 @@ Twig uses one curly bracket with a procent sign **to execute** statements such a
 </ul>
 ````
 
-As you can see, the Twig syntax is a cleaner and easier than pure PHP:
+As you can see, the Twig syntax is cleaner and easier than pure PHP:
 
 - You don't need the long `<?php echo something; ?>` introduction.
 - You don't need the `$` to mark a variable.
@@ -58,7 +58,8 @@ Set an array and print out a value:
 
 ````
 {% set content = ['first' => 'one value', 'second' => 'another value'] %}
-{{ content.first }}
+
+{{ content.first }} // prints out 'one value'
 ````
 
 ### Object
@@ -67,7 +68,8 @@ Set an object and print out a value:
 
 ````
 {% set content = {'first' : 'first value', 'second' : 'another value'} %}
-{{ content.first }}
+
+{{ content.first }} // prints out 'first value'
 ````
 
 ### Loop
@@ -102,7 +104,7 @@ Output:
 - First Value
 - Another Value
 
-You can manipulate variables with filters. Fiters are used after a pipe notation. See a list of all filters in the [Twig documentation](http://twig.sensiolabs.org/doc/2.x/filters/index.html).
+You can manipulate variables with filters. Filters are used after a pipe notation. See a list of all filters in the [Twig documentation](http://twig.sensiolabs.org/doc/2.x/filters/index.html).
 
 ### Functions
 
@@ -124,7 +126,7 @@ To include a template, just write:
 {{ include(sidebar.twig) }}
 ````
 
-**Example usage**: Your layout-template includes other templates like header.twig, footer.twig or sidebar.twig.
+**Example usage**: Your layout-template **includes** other templates like header.twig, footer.twig or sidebar.twig.
 
 ### Extend Template
 
@@ -134,7 +136,7 @@ To extend a template, just write:
 {% extends "partials/layout.twig" %}
 ````
 
-**Example usage:** Your content template (e.g. index.twig) extends your layout template. This means, index.twig is rendered within the layout.twig, and the layout.twig includes a header.twig, a footer.twig and a sidebar.twig.
+**Example usage:** Your content template (e.g. index.twig) **extends** your layout template. This means, index.twig is rendered within the layout.twig, and the layout.twig includes a header.twig, a footer.twig and a sidebar.twig.
 
 ### Example: Include and Extend
 
@@ -180,14 +182,16 @@ Now, your template `index.twig` extends your template `layout.twig` and the `blo
 
 ### Macros
 
-Macros in Twig are like functions in PHP: You can use them for repeating tasks. A typical example is a navigation, where you loop over a complex array recursively. But you can also use macros to render forms and input fields.
+Macros in Twig are like functions in PHP: You can use them for repeating tasks. A typical example is a navigation, where you loop over a comlex and multi-dimensional array recursively. But you can also use macros to render forms and input fields.
 
-This is an example for a navigation:
+Macros are usually the most complex parts of your theme and they are mostly used for generating a navigation. You can use the macro for the navigation used in the typemill theme as a starting point. In most cases, you won't even touch it, but if you read the code in detail, it will probably pretty easy for you to costumize it for your needs.
 
-    {% macro loop_over(navigation) %}
+A typical macro code for a navigation looks like this: 
 
+    {% macro loop_over(navigation) %}
+    
       {% import _self as macros %}
-
+    
       {% for element in navigation %} 
         <li>
           {% if element.elementType == 'folder' %}
@@ -207,4 +211,5 @@ This is an example for a navigation:
     <ul class="main-menu">
       {{ macros.loop_over(navigation) }}
     </ul>
-These are only some small examples, how you can use Twig to create templates and themes for TYPEMILL. In fact, you can do a lot more complex stuff with Twig. Just read the [official documentation](https://twig.sensiolabs.org/doc).
+These are only some small examples, how you can use Twig to create templates and themes for TYPEMILL. In fact, you can do a lot more complex stuff with Twig. Just read the [official documentation](https://twig.sensiolabs.org/doc).
+

+ 1 - 2
content/3_for-theme-developers/06-theme-variables/05-content.md → content/3_for-theme-developers/06-theme-variables/02-content.md

@@ -3,5 +3,4 @@
 The content-variable holds the whole content of your Markdown file in HTML. To print out the content of the Markdown file, simply write:
 
     {{ content }}
-You can only use Twig filters to manipulate the content, but the possibilities are limited.
-
+You can only use Twig filters to manipulate the content, but the possibilities are limited. Usually you should not hack into the content, but if you really need it (e.g. to display adds or to show a subscription form), then you have to create a plugin for this.

+ 21 - 0
content/3_for-theme-developers/06-theme-variables/03-title.md

@@ -0,0 +1,21 @@
+# Title
+
+The title tag returns the first `<h1>` headline used in the content file. If ther is no headline, it uses the file name. 
+
+````
+{{ title }}
+````
+
+You can use the title for the HTML-title like this: 
+
+````
+<title>{{ title }}</title>
+````
+
+And you can of course manipulate the title with a Twig filter like this: 
+
+````
+{{ title|title }}
+````
+
+This will display the first character of each word in uppercase.

+ 21 - 0
content/3_for-theme-developers/06-theme-variables/04-description.md

@@ -0,0 +1,21 @@
+# Description
+
+The description variable extracts the first lines out of the content. It is usually about 300 characters long and you can use this for the meta-description, for teasers and for snippets.
+
+    {{ description }}
+
+Use it for the description meta-tag like this: 
+
+````
+<meta name="description" content="{{ description }}" />
+````
+
+You can also manipulate the description with Twig-filters, if you want. For example the filter...
+
+````
+{{ description|slice(0,100) }}
+````
+
+... will output the first 100 characters of the description.
+
+

+ 16 - 0
content/3_for-theme-developers/06-theme-variables/06-image.md

@@ -0,0 +1,16 @@
+# Image
+
+If present, the image tag will return the url and the alt-tag of the first image used in the article: 
+
+````
+{{ image.img_url }}
+{{ image.img_alt }}
+````
+
+This can be pretty handy if you want to use an header image or if you want to add meta-tags for social media networks. The Typemill standard themes uses meta-tags for twitter and facebook, so that the image get's displayed in the social media posts. It can look like this: 
+
+````
+<meta property="og:image" content="{{ image.img_url }}">
+<meta name="twitter:image:alt" content="{{ image.img_alt }}">
+````
+

+ 14 - 0
content/3_for-theme-developers/06-theme-variables/08-base-url.md

@@ -0,0 +1,14 @@
+# Base Url
+
+Whenever you want to create some urls in your theme, you can build them with the base_url tag. The base url always returns the basic url to your application. Usually this is the domain-name, but if you develop on localhost, it can also be something like `http://localhost/your-project-folder`.
+
+````
+{{ base_url }}
+````
+
+If you develop your theme, the base url is pretty useful if you want to include some assets like CSS or JavaScript. You can reference to these files like this: 
+
+````
+<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/style.css" />
+````
+

+ 0 - 9
content/3_for-theme-developers/06-theme-variables/08-description.md

@@ -1,9 +0,0 @@
-# Description
-
-The description variable extracts the first 150 characters of the content. You can print the description out with:
-
-    {{ description }}
-
-You can use the description for the meta-tag in your HTML head, for example.
-
-

+ 12 - 5
content/3_for-theme-developers/06-theme-variables/10-item.md

@@ -1,6 +1,6 @@
 # Item
 
-The item variable is an object. It provides informations about the actual page, like the page title,  the url, the slug or the next and the previous page. 
+The item variable is an object. It provides informations about the actual page like the page title,  the url, the slug or the next and the previous page. 
 
 Some informations are only available for the type `folder` while some other informations are specific to the type `file`. But most informations are shared by both.
 
@@ -32,6 +32,7 @@ stdClass Object
     [urlRel] => /typemill/developers/theme-variables/navigation
     [urlAbs] => http://localhost/typemill/developers/theme-variables/navigation
     [active] => 1
+    [modified] => 1525088781
     [thisChapter] => stdClass Object
         (
             [originalName] => 05-theme-variables
@@ -110,9 +111,9 @@ stdClass Object
 The following informations (properties) are shared by folders and files. The examples are based on a simple file and folder structure like this: 
 
 - content
-  - 1.my-folder
+  - 01-my-folder
     - index.md
-    - 04.my-content-file.md
+    - 04-my-content-file.md
 
 ### {{ item.elementType }}
 
@@ -223,6 +224,12 @@ The `item.prevItem` is an item object again, so you have access to all the infor
 
 Example: `<a href="{{ item.prevItem.urlRel }}">{{ item.prevItem.name }}</a>`
 
+### {{ item.modified }}
+
+Returns the last modified date of the file as a number. You can use this to print out the last modified date in your theme. Use the date-function of Twig to format the date.
+
+Example: `Last modified: {{ item.modified|date(m/d/Y) }}`
+
 ## Specific to Folders or Files
 
 The following informations are specific to files or folders
@@ -252,11 +259,11 @@ The whole usecase might look like this:
 
 ### {{ item.folderContent }}
 
-This information is only available for **folders**. It contains the whole content of that folder, again as an multidimensional array of item objects. You can use it to list the content of a folder.
+This information is only available for **folders**. It contains the whole content of that folder as a multidimensional array of item objects. You can use it to list the content of a folder.
 
 To do so, you have two options:
 
-1. Display only the first level items in the current folder. This can be done with a simple for loop.
+1. Display only the first level items in the current folder. This can be done with a simple `for` loop.
 2. Display all nested items and folders within the current folder recursively. You have to write a Twig macro for that.
 
 The simple solution with all first level items of the current folder looks like this:

+ 1 - 1
content/3_for-theme-developers/06-theme-variables/15-breadcrumb.md

@@ -1,6 +1,6 @@
 # Breadcrumb
 
-The `{{ breadcrumb }}` variable contains the breadcrumb for the page as an one dimensional array. The array contains item objects. You can loop over the breadcrumb and print the elements out like this: 
+The `{{ breadcrumb }}` variable contains the breadcrumb for the page. It is a simple one dimensional array of item objects. You can loop over the breadcrumb and print the elements out like this: 
 
     <ul class="breadcrumb">
     {% for element in breadcrumb %}

+ 2 - 2
content/3_for-theme-developers/06-theme-variables/25-navigation.md

@@ -2,7 +2,7 @@
 
 The variable `{{ navigation }}` represents the structure of the whole content folder and can be used to create a navigation. 
 
-The `{{ navigation }}` variable is a multidimensional array of item objects. So you have access to nearly all informations, that an item object provides. Only the following informations for the paging is not part of the item objects within the navigation variable:
+The `{{ navigation }}` variable is a multi dimensional array of item objects. With that array you have access to nearly all informations, that an item object provides. Only the following informations for the paging is not part of the item objects within the navigation variable:
 
 - thisChapter
 - nextItem
@@ -93,7 +93,7 @@ The whole usecase with the macro and the navigation in one template looks like t
             {{ macros.loop_over(navigation) }}
         </ul>
     </nav>
-Just as a recommendation for your theme-structure: Typically you create a separate file like `navigation.twig`  with all the code above. Then you place this template in a folder like `partials`. You can include this navigation.twig-file in a `layout.twig` file, so that the navigation is included in all websites of your theme. So the structure might look like this:
+Just as a recommendation for your theme-structure: Typically you create a separate file like `navigation.twig`  with all the code above. Then you place this template in a folder like `partials`. You can include this navigation-file in a `layout.twig` file, so that the navigation is included in all pages of your theme. So the structure might look like this:
 
 - theme
   - partials

+ 24 - 1
content/3_for-theme-developers/06-theme-variables/30-settings.md

@@ -1,6 +1,12 @@
 # Settings
 
-The `{{ settings }}` variable is a simple array. It combines the default settings and the user specific settings of the `settings.yaml` file.
+The `{{ settings }}` variable is a simple array. It contains all settings throughout the TYPEMILL system, in detail: 
+
+* The user settings for the system.
+* The user settings for the themes.
+* The user settings for the plugins.
+
+All these settings are merged and managed by TYPEMILL in the background. This is pretty handy because you can use all settings within one variable. 
 
 ## Useful Settings
 
@@ -60,3 +66,20 @@ If the error display is off or on. Default value is `false`.
 
 Some more informations are provided by the Slim framework, that runs under the hood of TYPEMILL. You will probably never use them.
 
+## Settings for Themes and Plugins
+
+You have also access to all plugins- and theme-settings. Simply use them like this: 
+
+````
+{{ settings.themes.mytheme.mythemesetting }}
+{{ settings.plugins.myplugin.mypluginsetting}}
+````
+
+You have to replace `mytheme` and `myplugin` with the name of the theme or plugin and the `mythemesettings` and `mypluginsettings` with the name of the settings. you can find the name of the settings in the YAML-file of the plugin or theme. 
+
+For example: The standard theme of TYPEMILL is called `typemill`. And there you can edit the label of the start button displayed on the startpage. The name of the variable is `start`. So you can simply print it out like this: 
+
+````
+<button>{{ settings.themes.typemill.start }}</button>
+````
+

+ 1 - 1
content/3_for-theme-developers/06-theme-variables/index.md

@@ -1,3 +1,3 @@
 # Theme Variables
 
-TYPEMILL provides **six variables** for your theme. They are easy to understand and simple to use.  
+TYPEMILL provides **9 variables** for your theme right now. They are easy to understand and simple to use.  

+ 19 - 0
content/5_info/01-release-notes.md

@@ -2,6 +2,25 @@
 
 This is the version history with some release notes.
 
+## Version 1.1.4 (30.04.2018)
+
+**Please follow the instructions for minor updates** in the [documentation](/gettings-started/update). Please update the Typemill theme, too.
+
+Version 1.1.4 is mainly an optimization and refactoring of the author panel released in version 1.1.3. Some details of the changes:
+
+* Length of description is optimized for SEO now.
+* You can display a last modified date on each page now (update the TYPEMILL theme for that).
+* Optimized mobile version of the author-panel navigation.
+* Form rendering is now done in a seperate form template.
+* SettingsController is deeply refactored and some bugs are fixed.
+* FormModel partly fixed and refactored.
+* ValidationModel fixed.
+* Update notifications for system, themes and plugins are completely refactored and unified.
+* Welcome page is fixed, so that the linked themes- and plugin settings show the initial values now.
+* Settings functions for plugins and themes are cleaned up and unified.
+* Design is partly fixed and unified (open-close icons and more).
+* User documentation has been enhanced and corrected.
+
 ## Version 1.1.3 (19.04.2018)
 
 **Please follow the instructions for major updates** in the [documentation](/gettings-started/update).

+ 1 - 1
content/index.md

@@ -1 +1 @@
-TYPEMILL is a content management system for **writers** and their **text-work** (markdown). TYPEMILL is simple, lightweight (< 1mb) and open source. Just download and start.
+TYPEMIL is a content management system for **writers** and their **text-work**. It plublishes markdown files as a website and it will help you to create online-based e-books in future. TYPEMILL is simple, lightweight and open source. Just download and start.

+ 12 - 36
system/Controllers/PageController.php

@@ -40,14 +40,11 @@ class PageController extends Controller
 			if($cache->validate('cache', 'lastCache.txt',600))
 			{
 				$structure	= $this->getCachedStructure($cache);
-				$cached 	= true;
 			}
 			else
 			{
 				/* if not, get a fresh structure of the content folder */
 				$structure 	= $this->getFreshStructure($pathToContent, $cache, $uri);
-				
-				$cached		= false;
 
 				/* if there is no structure at all, the content folder is probably empty */
 				if(!$structure)
@@ -89,15 +86,7 @@ class PageController extends Controller
 			
 			/* find the url in the content-item-tree and return the item-object for the file */
 			$item = Folder::getItemForUrl($structure, $urlRel);
-			
-			/* if structure is cached and there is no item 
-			if($cached && !$item)
-			{
-				/* get a fresh structure and search for the item again 
-				$structure = $this->getFreshStructure($pathToContent, $cache, $uri); 
-				$item = Folder::getItemForUrl($structure, $urlRel);
-			}
-			
+						
 			/* if there is still no item, return a 404-page */
 			if(!$item)
 			{
@@ -122,8 +111,11 @@ class PageController extends Controller
 				$filePath = $pathToContent . $item->path;
 			}
 			
+			/* add the modified date for the file */
+			$item->modified	= isset($filePath) ? filemtime($filePath) : false;
+						
 			/* read the content of the file */
-			$contentMD = isset($filePath) ? file_get_contents($filePath) : false;
+			$contentMD 		= isset($filePath) ? file_get_contents($filePath) : false;			
 		}
 		
 		$contentMD = $this->c->dispatcher->dispatch('onMarkdownLoaded', new OnMarkdownLoaded($contentMD))->getData();
@@ -143,7 +135,7 @@ class PageController extends Controller
 		$contentHTML 	= $this->c->dispatcher->dispatch('onHtmlLoaded', new OnHtmlLoaded($contentHTML))->getData();
 		
 		/* create excerpt from content */
-		$excerpt		= substr($contentHTML,0,320);
+		$excerpt		= substr($contentHTML,0,500);
 		$excerpt		= explode("</h1>", $excerpt);
 		
 		/* extract title from excerpt */
@@ -154,13 +146,14 @@ class PageController extends Controller
 		if($description)
 		{
 			$description 	= trim(preg_replace('/\s+/', ' ', $description));
+			$description	= substr($description, 0, 300);		
 			$lastSpace 		= strrpos($description, ' ');
 			$description 	= substr($description, 0, $lastSpace);
 		}
-		
+				
 		/* get url and alt-tag for first image, if exists */
 		if($firstImage)
-		{	
+		{
 			preg_match('#\((.*?)\)#', $firstImage, $img_url);
 			if($img_url[1])
 			{
@@ -169,13 +162,7 @@ class PageController extends Controller
 				$firstImage = array('img_url' => $base_url . $img_url[1], 'img_alt' => $img_alt[1]);
 			}
 		}
-		
-		/* 
-			$timer['topiccontroller']=microtime(true);
-			$timer['end topiccontroller']=microtime(true);
-			Helpers::printTimer($timer);
-		*/
-		
+
 		$route = empty($args) && $settings['startpage'] ? '/cover.twig' : '/index.twig';
 		
 		$this->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url, 'image' => $firstImage ));
@@ -214,19 +201,8 @@ class PageController extends Controller
 
 		if($latestVersion)
 		{
-			/* check, if user-settings exist */
-			$yaml 			= new WriteYaml();
-			$userSettings 	= $yaml->getYaml('settings', 'settings.yaml');
-			if($userSettings)
-			{
-				/* if there is no version info in the settings or if the version info is outdated */
-				if(!isset($userSettings['latestVersion']) || $userSettings['latestVersion'] != $latestVersion)
-				{
-					/* write the latest version into the user-settings */
-					$userSettings['latestVersion'] = $latestVersion;
-					$yaml->updateYaml('settings', 'settings.yaml', $userSettings);									
-				}
-			}
+			/* store latest version */
+			\Typemill\Settings::updateSettings(array('latestVersion' => $latestVersion));			
 		}
 	}
 	

+ 170 - 198
system/Controllers/SettingsController.php

@@ -8,8 +8,7 @@ use Typemill\Models\Validation;
 use Typemill\Models\User;
 
 class SettingsController extends Controller
-{
-	
+{	
 	/*********************
 	**	BASIC SETTINGS	**
 	*********************/
@@ -65,14 +64,14 @@ class SettingsController extends Controller
 	
 	public function showThemes($request, $response, $args)
 	{
-		$settings 	= $this->c->get('settings');
-		$themes 	= $this->getThemes();
-		$themedata	= array();
-			
+		$userSettings 	= $this->c->get('settings');
+		$themes 		= $this->getThemes();
+		$themedata		= array();
+
 		foreach($themes as $themeName)
-		{	
+		{
 			/* if theme is active, list it first */
-			if($settings['theme'] == $themeName)
+			if($userSettings['theme'] == $themeName)
 			{
 				$themedata = array_merge(array($themeName => null), $themedata);
 			}
@@ -80,60 +79,20 @@ class SettingsController extends Controller
 			{
 				$themedata[$themeName] = null;
 			}
-			
-			$themeSettings = \Typemill\Settings::getThemeSettings($themeName);
+
+			$themeSettings = \Typemill\Settings::getObjectSettings('themes', $themeName);
 			if($themeSettings)
 			{
 				/* store them as default theme data with author, year, default settings and field-definitions */
 				$themedata[$themeName] = $themeSettings;
 			}
 			
-			if(isset($themeSettings['forms']))
+			if(isset($themeSettings['forms']['fields']))
 			{
-				$fields = array();
-				
-				/* then iterate through the fields */
-				foreach($themeSettings['forms']['fields'] as $fieldName => $fieldConfigs)
-				{
-					/* and create a new field object with the field name and the field configurations. */
-					$field = new Field($fieldName, $fieldConfigs);
-
-					$userValue = false;
+				$fields = $this->getFields($userSettings, 'themes', $themeName, $themeSettings);
 
-					/* add value from stored usersettings */
-					if($settings['theme'] == $themeName && isset($settings['themesettings'][$fieldName]))
-					{
-						$userValue = $settings['themesettings'][$fieldName];
-					}
-					/* alternatively add value from original theme settings */
-					elseif(isset($themeSettings['settings'][$fieldName]))
-					{
-						$userValue = $themeSettings['settings'][$fieldName];
-					}
-					/* overwrite it with old input in form, if exists */
-					if(isset($_SESSION['old'][$themeName][$fieldName]))
-					{
-						$userValue = $_SESSION['old'][$themeName][$fieldName];
-					}
-										
-					if($field->getType() == "textarea")
-					{
-						if($userValue)
-						{
-							$field->setContent($userValue);
-						}
-					}
-					elseIf($field->getType() != "checkbox")
-					{
-						$field->setAttributeValue('value', $userValue);	
-					}
-
-					/* add the field to the field-List with the plugin-name as key */
-					$fields[] = $field;					
-				}
-								
 				/* overwrite original theme form definitions with enhanced form objects */
-				$themedata[$themeName]['forms']['fields'] = $fields;				
+				$themedata[$themeName]['forms']['fields'] = $fields;
 			}
 			
 			/* add the preview image */
@@ -148,81 +107,21 @@ class SettingsController extends Controller
 		$users		= $user->getUsers();
 		$route 		= $request->getAttribute('route');
 	
-		$this->render($response, 'settings/themes.twig', array('settings' => $settings, 'themes' => $themedata, 'users' => $users, 'route' => $route->getName() ));
+		$this->render($response, 'settings/themes.twig', array('settings' => $userSettings, 'themes' => $themedata, 'users' => $users, 'route' => $route->getName() ));
 	}
 	
-	public function saveThemes($request, $response, $args)
-	{
-		if($request->isPost())
-		{
-			$settings 		= \Typemill\Settings::getUserSettings();
-			$params 		= $request->getParams();
-			$theme			= isset($params['theme']) ? $params['theme'] : false;
-			$themeSettings	= isset($params[$theme]) ? $params[$theme] : false;
-			$validate		= new Validation();
-			
-			/* set theme name and delete theme settings from user settings for the case, that the new theme has no settings */
-
-			$settings['theme'] = $theme;
-			unset($settings['themesettings']);
-						
-			if($themeSettings)
-			{
-				// load theme definitions by theme name
-				$themeOriginalSettings = \Typemill\Settings::getThemeSettings($theme);
-
-				// validate input with field definitions				
-				if($themeOriginalSettings)
-				{
-					foreach($themeSettings as $fieldName => $fieldValue)
-					{
-						$fieldDefinition = isset($themeOriginalSettings['forms']['fields'][$fieldName]) ? $themeOriginalSettings['forms']['fields'][$fieldName] : false;
-						if($fieldDefinition)
-						{
-							/* validate user input for this field */
-							$validate->pluginField($fieldName, $fieldValue, $theme, $fieldDefinition);
-						}
-						else
-						{
-							$_SESSION['errors'][$themeName][$fieldName] = 'This field is not defined for the theme!';
-						}
-					}
-				}
-				$settings['themesettings'] 	= $themeSettings;
-			}
-						
-			/* check for errors and redirect to path, if errors found */
-			if(isset($_SESSION['errors']))
-			{
-				$this->c->flash->addMessage('error', 'Please correct the errors');
-				return $response->withRedirect($this->c->router->pathFor('themes.show'));
-			}
-
-			/* store updated settings */
-			\Typemill\Settings::updateSettings($settings);
-			
-			$this->c->flash->addMessage('info', 'Settings are stored');
-			return $response->withRedirect($this->c->router->pathFor('themes.show'));
-		}
-	}
-
-
-	/*********************
-	**	Plugin SETTINGS	**
-	*********************/
-	
 	public function showPlugins($request, $response, $args)
 	{
-		$settings 	= $this->c->get('settings');
-		$plugins	= array();
-		$fields 	= array();
+		$userSettings 	= $this->c->get('settings');
+		$plugins		= array();
+		$fields 		= array();
 
 		/* iterate through the plugins in the stored user settings */
-		foreach($settings['plugins'] as $pluginName => $pluginUserSettings)
-		{
+		foreach($userSettings['plugins'] as $pluginName => $pluginUserSettings)
+		{		
 			/* add plugin to plugin Data, if active, set it first */
-			/* if theme is active, list it first */
-			if($settings['plugins'][$pluginName]['active'] == true)
+			/* if plugin is active, list it first */
+			if($userSettings['plugins'][$pluginName]['active'] == true)
 			{
 				$plugins = array_merge(array($pluginName => null), $plugins);
 			}
@@ -230,71 +129,35 @@ class SettingsController extends Controller
 			{
 				$plugins[$pluginName] = Null;
 			}
-						
+			
 			/* Check if the user has deleted a plugin. Then delete it in the settings and store the updated settings. */
-			if(!is_dir($settings['rootPath'] . 'plugins' . DIRECTORY_SEPARATOR . $pluginName))
+			if(!is_dir($userSettings['rootPath'] . 'plugins' . DIRECTORY_SEPARATOR . $pluginName))
 			{
 				/* remove the plugin settings and store updated settings */
 				\Typemill\Settings::removePluginSettings($pluginName);
 				continue;
 			}
-
+			
 			/* load the original plugin definitions from the plugin folder (author, version and stuff) */
-			$pluginOriginalSettings = \Typemill\Settings::getPluginSettings($pluginName);
+			$pluginOriginalSettings = \Typemill\Settings::getObjectSettings('plugins', $pluginName);
 			if($pluginOriginalSettings)
 			{
 				/* store them as default plugin data with plugin author, plugin year, default settings and field-definitions */
 				$plugins[$pluginName] = $pluginOriginalSettings;
 			}
-
-			/* overwrite the original plugin settings with the stored user settings, if they exist */
-			if($pluginUserSettings)
-			{
-				$plugins[$pluginName]['settings'] = $pluginUserSettings;
-			}
 			
 			/* check, if the plugin has been disabled in the form-session-data */
-			/* TODO: Works only, if there is at least one plugin with settings */
 			if(isset($_SESSION['old']) && !isset($_SESSION['old'][$pluginName]['active']))
 			{
 				$plugins[$pluginName]['settings']['active'] = false;
 			}
 			
 			/* if the plugin defines forms and fields, so that the user can edit the plugin settings in the frontend */
-			if(isset($pluginOriginalSettings['forms']))
+			if(isset($pluginOriginalSettings['forms']['fields']))
 			{
-				$fields = array();
+				/* get all the fields and prefill them with the dafault-data, the user-data or old input data */
+				$fields = $this->getFields($userSettings, 'plugins', $pluginName, $pluginOriginalSettings);
 				
-				/* then iterate through the fields */
-				foreach($pluginOriginalSettings['forms']['fields'] as $fieldName => $fieldConfigs)
-				{
-					/* and create a new field object with the field name and the field configurations. */
-					$field = new Field($fieldName, $fieldConfigs);
-					
-					/* now you have the configurations of the field. Time to set the values */
-					
-					/* At first, get the value for the field from the stored user settings */
-					// $userValue = isset($pluginUserSettings[$fieldName]) ? $pluginUserSettings[$fieldName] : NULL;
-					$userValue = isset($plugins[$pluginName]['settings'][$fieldName]) ? $plugins[$pluginName]['settings'][$fieldName] : NULL;
-					
-					/* Then overwrite the value, if there are old input values for the field in the session */
-					$userValue = isset($_SESSION['old'][$pluginName][$fieldName]) ? $_SESSION['old'][$pluginName][$fieldName] : $userValue;
-					
-					if($field->getType() == "textarea")
-					{
-						if($userValue)
-						{
-							$field->setContent($userValue);
-						}
-					}
-					elseIf($field->getType() != "checkbox")
-					{
-						$field->setAttributeValue('value', $userValue);	
-					}
-
-					/* add the field to the field-List with the plugin-name as key */
-					$fields[] = $field;
-				}
 				/* overwrite original plugin form definitions with enhanced form objects */
 				$plugins[$pluginName]['forms']['fields'] = $fields;
 			}
@@ -304,61 +167,146 @@ class SettingsController extends Controller
 		$users 	= $user->getUsers();
 		$route 	= $request->getAttribute('route');
 		
-		$this->render($response, 'settings/plugins.twig', array('settings' => $settings, 'plugins' => $plugins, 'users' => $users, 'route' => $route->getName() ));
+		$this->render($response, 'settings/plugins.twig', array('settings' => $userSettings, 'plugins' => $plugins, 'users' => $users, 'route' => $route->getName() ));
 	}
 
+	private function getFields($userSettings, $objectType, $objectName, $objectSettings)
+	{
+		$fields = array();
+
+		/* then iterate through the fields */
+		foreach($objectSettings['forms']['fields'] as $fieldName => $fieldConfigs)
+		{
+			/* and create a new field object with the field name and the field configurations. */
+			$field = new Field($fieldName, $fieldConfigs);
+			
+			/* you have to prefil the value for the field with default settings, user settings or old user-input from form */
+			$userValue = false;
+
+			/* first, add the default values from the original plugin or theme settings. Ignore checkboxes, otherwiese they might be always checked */
+			if(isset($objectSettings['settings'][$fieldName]))
+			{
+				$userValue = $objectSettings['settings'][$fieldName];
+			}
+						
+			/* now overwrite them with the local stored user settings */
+			if(isset($userSettings[$objectType][$objectName][$fieldName]))
+			{
+				$userValue = $userSettings[$objectType][$objectName][$fieldName];
+			}
+
+			/* overwrite it with old input in form, if exists */
+			if(isset($_SESSION['old'][$objectName][$fieldName]))
+			{
+				$userValue = $_SESSION['old'][$objectName][$fieldName];
+			}
+		
+			/* now we have set the uservalue for the field. Prepopulate the field object with it now */
+			if($field->getType() == "textarea")
+			{
+				if($userValue)
+				{
+					$field->setContent($userValue);
+				}
+			}
+			elseif($field->getType() == "checkbox")
+			{
+				/* needs special treatment, because field does not exist in settings if unchecked by user */
+				if(isset($userSettings[$objectType][$objectName][$fieldName]))
+				{
+					$field->setAttribute('checked', 'checked');
+				}
+				else
+				{
+					$field->unsetAttribute('checked');
+				}
+			}
+			else
+			{
+				$field->setAttributeValue('value', $userValue);	
+			}
+
+			/* add the field to the field-List with the plugin-name as key */
+			$fields[] = $field;
+		}
+		
+		return $fields;
+	}	
+
+	/*************************************
+	**	SAVE THEME- AND PLUGIN-SETTINGS	**
+	*************************************/
+
+	public function saveThemes($request, $response, $args)
+	{
+		if($request->isPost())
+		{	
+			$userSettings 	= \Typemill\Settings::getUserSettings();
+			$params 		= $request->getParams();
+			$themeName		= isset($params['theme']) ? $params['theme'] : false;
+			$userInput		= isset($params[$themeName]) ? $params[$themeName] : false;
+			$validate		= new Validation();
+			
+			/* set theme name and delete theme settings from user settings for the case, that the new theme has no settings */
+			$userSettings['theme'] = $themeName;
+
+			if($userInput)
+			{
+				/* validate the user-input */
+				$this->validateInput('themes', $themeName, $userInput, $validate);
+				
+				/* set user input as theme settings */
+				$userSettings['themes'][$themeName] = $userInput;
+			}
+			
+			/* check for errors and redirect to path, if errors found */
+			if(isset($_SESSION['errors']))
+			{
+				$this->c->flash->addMessage('error', 'Please correct the errors');
+				return $response->withRedirect($this->c->router->pathFor('themes.show'));
+			}
+			
+			/* store updated settings */
+			\Typemill\Settings::updateSettings($userSettings);
+			
+			$this->c->flash->addMessage('info', 'Settings are stored');
+			return $response->withRedirect($this->c->router->pathFor('themes.show'));
+		}
+	}
+		
 	public function savePlugins($request, $response, $args)
 	{
 		if($request->isPost())
 		{
-			$settings 		= \Typemill\Settings::getUserSettings();
+			$userSettings 	= \Typemill\Settings::getUserSettings();
 			$pluginSettings	= array();
-			$params 		= $request->getParams();
+			$userInput 		= $request->getParams();
 			$validate		= new Validation();
-					
+
 			/* use the stored user settings and iterate over all original plugin settings, so we do not forget any... */
-			foreach($settings['plugins'] as $pluginName => $pluginUserSettings)
+			foreach($userSettings['plugins'] as $pluginName => $pluginUserSettings)
 			{
 				/* if there are no input-data for this plugin, then use the stored plugin settings */
-				if(!isset($params[$pluginName]))
+				if(!isset($userInput[$pluginName]))
 				{
 					$pluginSettings[$pluginName] = $pluginUserSettings;
 				}
 				else
 				{
-					/* now fetch the original plugin settings from the plugin folder to get the field definitions */
-					$pluginOriginalSettings = \Typemill\Settings::getPluginSettings($pluginName);
-					
-					if($pluginOriginalSettings)
-					{
-						/* take the user input data and iterate over all fields and values */
-						foreach($params[$pluginName] as $fieldName => $fieldValue)
-						{
-							/* get the corresponding field definition from original plugin settings */
-							$fieldDefinition = isset($pluginOriginalSettings['forms']['fields'][$fieldName]) ? $pluginOriginalSettings['forms']['fields'][$fieldName] : false;
-							if($fieldDefinition)
-							{
-								/* validate user input for this field */
-								$validate->pluginField($fieldName, $fieldValue, $pluginName, $fieldDefinition);
-							}
-							if(!$fieldDefinition && $fieldName != 'active')
-							{
-								$_SESSION['errors'][$pluginName][$fieldName] = 'This field is not defined in the plugin!';
-							}
-						}
-					}
-					
+					/* validate the user-input */
+					$this->validateInput('plugins', $pluginName, $userInput[$pluginName], $validate);
+										
 					/* use the input data */
-					$pluginSettings[$pluginName] = $params[$pluginName];
+					$pluginSettings[$pluginName] = $userInput[$pluginName];
 				}
 				
 				/* deactivate the plugin, if there is no active flag */
-				if(!isset($params[$pluginName]['active']))
+				if(!isset($userInput[$pluginName]['active']))
 				{
 					$pluginSettings[$pluginName]['active'] = false;
 				}
 			}
-						
+
 			if(isset($_SESSION['errors']))
 			{
 				$this->c->flash->addMessage('error', 'Please correct the errors below');
@@ -366,10 +314,10 @@ class SettingsController extends Controller
 			else
 			{
 				/* if everything is valid, add plugin settings to base settings again */
-				$settings['plugins'] = $pluginSettings;
+				$userSettings['plugins'] = $pluginSettings;
 				
 				/* store updated settings */
-				\Typemill\Settings::updateSettings($settings);
+				\Typemill\Settings::updateSettings($userSettings);
 
 				$this->c->flash->addMessage('info', 'Settings are stored');
 			}
@@ -378,7 +326,31 @@ class SettingsController extends Controller
 		}
 	}
 
-	
+	private function validateInput($objectType, $objectName, $userInput, $validate)
+	{
+		/* fetch the original settings from the folder (plugin or theme) to get the field definitions */
+		$originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
+
+		if($originalSettings)
+		{
+			/* take the user input data and iterate over all fields and values */
+			foreach($userInput as $fieldName => $fieldValue)
+			{
+				/* get the corresponding field definition from original plugin settings */
+				$fieldDefinition = isset($originalSettings['forms']['fields'][$fieldName]) ? $originalSettings['forms']['fields'][$fieldName] : false;
+				if($fieldDefinition)
+				{
+					/* validate user input for this field */
+					$validate->objectField($fieldName, $fieldValue, $objectName, $fieldDefinition);
+				}
+				if(!$fieldDefinition && $fieldName != 'active')
+				{
+					$_SESSION['errors'][$objectName][$fieldName] = 'This field is not defined!';
+				}				
+			}
+		}
+	}
+		
 	/***********************
 	**   USER MANAGEMENT  **
 	***********************/

+ 11 - 7
system/Controllers/SetupController.php

@@ -54,13 +54,9 @@ class SetupController extends Controller
 					$user->login($username);
 
 					/* store updated settings */
-					$settings = $this->c->get('settings');
-					$settings->replace(['setup' => false]);
-									
-					/* store updated settings */
-					\Typemill\Settings::updateSettings(array('setup' => false));
-
-					return $this->render($response, 'auth/welcome.twig', array());
+					\Typemill\Settings::createSettings(array('setup' => false));
+					
+					return $response->withRedirect($this->c->router->pathFor('setup.welcome'));
 				}
 			}
 			
@@ -68,4 +64,12 @@ class SetupController extends Controller
 			return $response->withRedirect($this->c->router->pathFor('setup.show'));
 		}
 	}
+	
+	public function welcome($request, $response, $args)
+	{
+		/* store updated settings */
+		\Typemill\Settings::updateSettings(array('welcome' => false));
+		
+		return $this->render($response, 'auth/welcome.twig', array());		
+	}
 }

+ 6 - 1
system/Models/Field.php

@@ -192,6 +192,11 @@ class Field
 		$this->attributes[$key] = $value;
 	}
 	
+	public function unsetAttribute($key)
+	{
+		unset($this->attributes[$key]);
+	}
+	
 	/* get a single attribute, if it is defined. For usage in templates like getAttribute('required') */
 	public function getAttribute($key)
 	{
@@ -238,7 +243,7 @@ class Field
 		$this->attributeValues[$key] = $value;
 	}
 	
-	private function getAttributeValue($key)
+	public function getAttributeValue($key)
 	{
 		if(isset($this->attributeValues[$key]))
 		{

+ 1 - 1
system/Models/Folder.php

@@ -119,7 +119,7 @@ class Folder
 			}
 		}
 		return $result;
-	}	
+	}
 
 	public static function getPagingForItem($content, $item)
 	{

+ 6 - 1
system/Models/Validation.php

@@ -173,7 +173,7 @@ class Validation
 		return $this->validationResult($v, $name);
 	}
 	
-	public function pluginField($fieldName, $fieldValue, $pluginName, $fieldDefinitions)
+	public function objectField($fieldName, $fieldValue, $pluginName, $fieldDefinitions)
 	{	
 		$v = new Validator(array($fieldName => $fieldValue));
 
@@ -186,6 +186,11 @@ class Validation
 		switch($fieldDefinitions['type'])
 		{
 			case "select":
+				/* create array with option keys as value */
+				$options = array();
+				foreach($fieldDefinitions['options'] as $key => $value){ $options[] = $key; }
+				$v->rule('in', $fieldName, $options);
+				break;
 			case "radio":
 			case "checkboxlist":
 				$v->rule('in', $fieldName, $fieldDefinitions['options']);

+ 1 - 1
system/Models/VersionCheck.php

@@ -20,6 +20,6 @@ class VersionCheck
 			return false;
 		}
 		$version = json_decode($version);
-		return $version->version;		
+		return $version->system->typemill;		
 	}
 }

+ 9 - 1
system/Routes/Web.php

@@ -15,7 +15,15 @@ if($settings['settings']['setup'])
 }
 else
 {
-	$app->get('/setup', AuthController::class . ':redirect');
+	$app->get('/setup', AuthController::class . ':redirect');	
+}
+if($settings['settings']['welcome'])
+{
+	$app->get('/setup/welcome', SetupController::class . ':welcome')->setName('setup.welcome')->add(new RedirectIfUnauthenticated($container['router'], $container['flash']));
+}
+else
+{
+	$app->get('/setup/welcome', AuthController::class . ':redirect')->setName('setup.welcome');	
 }
 
 $app->get('/tm-author', AuthController::class . ':redirect');

+ 24 - 19
system/Settings.php

@@ -41,8 +41,9 @@ class Settings
 			'userPath'								=> $rootPath . 'settings' . DIRECTORY_SEPARATOR . 'users',
 			'authorPath'							=> __DIR__ . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR,
 			'contentFolder'							=> 'content',
-			'version'								=> '1.1.3',
-			'setup'									=> true
+			'version'								=> '1.1.4',
+			'setup'									=> true,
+			'welcome'								=> true
 		];
 	}
 	
@@ -54,35 +55,39 @@ class Settings
 		
 		return $userSettings;
 	}
-	
-	public static function getPluginSettings($pluginName)
+
+	public static function getObjectSettings($objectType, $objectName)
 	{
 		$yaml = new Models\WriteYaml();
 		
-		$pluginFolder 	= 'plugins' . DIRECTORY_SEPARATOR . $pluginName;
-		$pluginFile		= $pluginName . '.yaml';
-		$pluginSettings = $yaml->getYaml($pluginFolder, $pluginFile);
+		$objectFolder 	= $objectType . DIRECTORY_SEPARATOR . $objectName;
+		$objectFile		= $objectName . '.yaml';
+		$objectSettings = $yaml->getYaml($objectFolder, $objectFile);
 
-		return $pluginSettings;
+		return $objectSettings;
 	}
-
-	public static function getThemeSettings($themeName)
+	
+	public static function createSettings($settings)
 	{
 		$yaml = new Models\WriteYaml();
 		
-		$themeFolder 	= 'themes' . DIRECTORY_SEPARATOR . $themeName;
-		$themeFile		= $themeName . '.yaml';
-		$themeSettings = $yaml->getYaml($themeFolder, $themeFile);
-
-		return $themeSettings;
+		/* write settings to yaml */
+		$yaml->updateYaml('settings', 'settings.yaml', $settings);
 	}
 	
 	public static function updateSettings($settings)
 	{
-		$yaml = new Models\WriteYaml();
+		$userSettings 	= self::getUserSettings();
 		
-		/* write settings to yaml */
-		$yaml->updateYaml('settings', 'settings.yaml', $settings);
+		if($userSettings)
+		{
+			
+			$yaml 		= new Models\WriteYaml();
+			$settings 	= array_merge($userSettings, $settings);
+
+			/* write settings to yaml */
+			$yaml->updateYaml('settings', 'settings.yaml', $settings);					
+		}
 	}
 	
 	public static function removePluginSettings($pluginName)
@@ -111,7 +116,7 @@ class Settings
 		{
 			$yaml = new Models\WriteYaml();
 			
-			$pluginSettings = self::getPluginSettings($pluginName);
+			$pluginSettings = self::getObjectSettings('plugins', $pluginName);
 			if(isset($pluginSettings['settings']))
 			{
 				$userSettings['plugins'][$pluginName] = $pluginSettings['settings'];

+ 1 - 1
system/author/auth/welcome.twig

@@ -14,7 +14,7 @@
 				<p><strong>Coming soon:</strong> You will probably miss a content editor in the author panel, but it will follow very soon. For time beeing you can write your content offline and upload the markdown files via FTP.</p>
 				<p><strong>Get help:</strong> If you have any questions, please consult the <a target="_blank" href="http://typemill.net/typemill"><i class="icon-link-ext"></i> docs</a> or open a new issue on <a target="_blank" href="https://github.com/trendschau/typemill"><i class="icon-link-ext"></i> github</a>.</p>
 			</div>
-			<a class="button" href="{{ path_for('settings.show') }}">Setup your website</a>
+			<a class="button" href="{{ path_for('settings.show') }}">Configure your website</a>
  		</div>
 		
 		<div class="small">

+ 114 - 39
system/author/css/style.css

@@ -2,7 +2,7 @@
 *  		HELPERS		  *
 **********************/
 
-a, a:link, a:visited, a:focus, a:hover, a:active, button, .button, input, .control-group, .sidebar-menu, .menu-action{
+a, a:link, a:visited, a:focus, a:hover, a:active, button, .button, input, .control-group, .sidebar-menu, .menu-action, .button-arrow{
 	-webkit-transition: all 0.2s ease;
 	-moz-transition: all 0.2s ease;
 	-o-transition: all 0.2s ease;
@@ -196,7 +196,8 @@ aside.sidebar{
 	padding: 0px 20px;
 	overflow: hidden;
 	box-sizing: border-box;
-	font-size: 0.9em;	
+	font-size: 0.9em;
+	text-align: center;
 }
 .sidebar-menu.expand{
 	max-height: 500px;
@@ -209,28 +210,32 @@ aside.sidebar{
 	line-height: 40px;
 	text-transform: uppercase;
 	font-weight: 300;
-	
-	background-image:
-		linear-gradient(45deg, transparent 50%, #444 50%),
-		linear-gradient(135deg, #444 50%, transparent 50%),
-		linear-gradient(to right, #fff, #fff);
-	background-position:
-		calc(50% + 30px) calc(1em + 2px),
-		calc(50% + 35px) calc(1em + 2px),
-		100% 0;
-	background-size: 
-		5px 5px,
-		5px 5px,
-		2.8em 2.8em;
-	background-repeat: no-repeat;
 	cursor: pointer;	
 }
-.expand .menu-action{
-	background-image:
-		linear-gradient(135deg, transparent 50%, #444 50%),
-		linear-gradient(45deg, #444 50%, transparent 50%),
-		linear-gradient(to right, #fff, #fff);	
+
+.button-arrow{
+  width: 0; 
+  height: 0;
+  border-left: 5px solid transparent;
+  border-right: 5px solid transparent;
+  border-bottom: 5px solid transparent;
+  border-top: 5px solid #000;
+  display:inline-block;
+  margin-left: 5px;
+}
+.active .button-arrow{
+	border-top: 5px solid #fff;
+}
+.expand .button-arrow{
+  border-bottom: 5px solid #000;
+  border-top: 0px solid transparent;
+  margin-bottom: 5px;
+}
+.expand.active .button-arrow{	
+	border-bottom: 5px solid #fff;
 }
+
+
 ul.menu-list{
 	list-style: none;
 	margin:5px 0 30px;
@@ -241,23 +246,28 @@ li.menu-item{
 	margin: 8px 0;	
 }
 .menu-item a, .menu-item a:link, .menu-item a:visited{
+	background: #f9f8f6;
+	width: 100%;
+	box-sizing: border-box;
+	display: inline-block;	
 	text-decoration: none;
 	color: #444;
-	padding: 0px 10px;
-	display: inline-block;
-	line-height: 2px;
-	width: auto;
-	height: 0; 
-	border-top: 8px solid transparent;
-	border-bottom: 8px solid transparent; 
-	border-left: 10px solid white;
+	border: 1px solid #eee;
 	border-radius: 3px;
+	line-height: 2.3em;
+	
+//	padding: 0px 10px;
+//	line-height: 2px;
+//	width: auto;
+//	height: 0; 
+//	border-top: 8px solid transparent;
+//	border-bottom: 8px solid transparent; 
+//	border-left: 10px solid white;
 }
 .menu-item a:hover, .menu-item a:focus, .menu-item a:active, .menu-item a.active{
-	border-left: 10px solid #e0474c;
-}
-.menu-item a.active{
-	color: #e0474c;
+	color: #fff;
+	background: #e0474c;
+//	border-left: 10px solid #e0474c;
 }
 
 /*************
@@ -328,11 +338,11 @@ ul.userlist{
 li.row{
 	display: inline-block;
 	width: 100%;
-	background: #f9f8f6;
 	box-sizing: border-box;
 }
 li.row ul{
-	margin: 0px;
+	background: #f9f8f6;
+	margin: 5px 0;
 	padding: 0px;
 	width: 100%;
 }
@@ -462,7 +472,7 @@ fieldset{
 	padding: 0;	
 }
 .large, .medium, .small{
-	padding: 18px 20px;
+	padding: 18px 0px;
 	box-sizing:border-box;
 	vertical-align: top;
 }
@@ -529,9 +539,9 @@ button,input[type="submit"]:hover{
 ** CARDS		**
 *****************/
 
-.settings header
+header.headline
 {
-	padding: 0px 20px;
+	padding: 0px 0px;
 }
 .userlist a, .userlist a:link, .userlist a:visited{
 	color: #e0474c;
@@ -547,7 +557,7 @@ a.button{
 fieldset.card{
 	width: 100%;
 	display: inline-block;
-	padding: 15px 20px;
+	padding: 15px 0px;
 	box-sizing: border-box;
 	vertical-align: top;
 }
@@ -556,6 +566,7 @@ fieldset.card{
 }
 .cardInner{
 	box-sizing: border-box;
+	position: relative;
 }
 .cardHead h2{
 	padding: 5px 20px 0;
@@ -566,6 +577,7 @@ fieldset.card{
 }
 .cardHead header{
 	width: 100%;
+	height: 52px;
 	display: inline-block;
 	box-sizing: border-box;
 }
@@ -669,6 +681,40 @@ ul.cardInfo{
 .card img{
 	width: 100%;
 }
+.update-banner{
+	display: none;
+	position: absolute;
+	right: 0;
+	width: 0; 
+	height: 0; 
+	border-top: 100px solid #e0474c;
+	border-bottom: 100px solid transparent;
+	border-left: 100px solid transparent;	
+}
+.settings .update-banner{
+	top: 0px;
+}
+.plugins .update-banner{
+	top: 52px;	
+}
+.update-banner.show-banner{
+	display: block;
+}
+.update-banner span{
+	position: absolute;
+	top: -85px;
+	left: -55px;
+	text-align: center;
+	font-size: 0.9em;
+	transform: rotate(45deg);
+	display: block;
+	color: #fff;	
+}
+.update-banner a{
+	color: #fff;
+	text-decoration: none;
+}
+
 
 /*
 ** SELECT BUTTON
@@ -990,6 +1036,12 @@ span.error{
 }	
 
 @media only screen and (min-width: 600px) {
+	header.headline{
+		padding: 0px 20px;
+	}
+	.large, .medium, .small{
+		padding: 18px 20px;
+	}
 	form .medium{
 		width: 49.5%;
 		display: inline-block;
@@ -998,6 +1050,9 @@ span.error{
 		width: 33.3%;
 		display: inline-block;
 	}
+	fieldset.card{
+		padding: 15px 20px;
+	}
 	.settings .medium a.button{
 		display: inline-block;
 		width: auto;
@@ -1041,6 +1096,7 @@ span.error{
 		overflow: hidden;
 		box-sizing: border-box;
 		font-size: 1em;
+		text-align: left;
 	}
 	.menu-action{
 		display: none;
@@ -1050,6 +1106,22 @@ span.error{
 	ul.menu-list{
 		margin:5px 0 50px;
 	}
+	.menu-item a, .menu-item a:link, .menu-item a:visited{
+		background: transparent;
+		width: auto;		
+		height: 0; 
+		padding: 0px 10px;
+		line-height: 2px;
+		border-top: 8px solid transparent;
+		border-bottom: 8px solid transparent; 
+		border-left: 10px solid white;
+	}
+	.menu-item a:hover, .menu-item a:focus, .menu-item a:active, .menu-item a.active{
+		color: #fff;
+		color: #e0474c;
+		background: transparent;
+		border-left: 10px solid #e0474c;
+	}
 	.card .medium{
 		padding: 0px 20px;
 	}
@@ -1061,6 +1133,9 @@ span.error{
 		margin-top: 10px;
 		margin-bottom: 40px;
 	}
+	li.row ul{
+		margin: 0px;
+	}
 	.col.username,.col.email,.col.userrole{
 		width: 30%;
 	}

+ 28 - 55
system/author/js/author.js

@@ -116,12 +116,12 @@
 	}
 	
 	/**********************************
-	** 		START THEMESWITCH	 	 **
+	** 		START VERSION CHECK	 	 **
 	**********************************/
 		
-	if(document.getElementById("baseapp"))
+	if(document.getElementById("system"))
 	{
-		getVersions('app', false);
+		getVersions('system', document.getElementsByClassName("fc-system-version"));
 	}
 	
 	if(document.getElementById("plugins"))
@@ -131,13 +131,9 @@
 	
 	if(document.getElementById("themes"))
 	{
-		// getVersions('theme', themeSwitch.value);
+		getVersions('theme', document.getElementsByClassName("fc-theme-version"));
 	}
-	
-	/**********************************
-	** 		START VERSIONING	 	 **
-	**********************************/
-			
+				
 	function getVersions(name, value)
 	{
 		var getPost 	= 'GET';
@@ -156,7 +152,13 @@
 
 		if(name == 'theme')
 		{
-			url += '&themes=' + value; 
+			var themeList = '&themes=';
+			for (var i = 0, len = value.length; i < len; i++)
+			{
+				themeList += value[i].id + ',';
+			}
+			
+			url += themeList;
 		}
 
 		sendJson(function(response)
@@ -165,17 +167,17 @@
 			{
 				var versions = JSON.parse(response);
 				
-				if(name == 'app' && versions.version)
+				if(name == 'system' && versions.system)
 				{
-					updateTypemillVersion(versions.version);
+					updateVersions(versions.system);
 				}
 				if(name == 'plugins' && versions.plugins)
 				{
-					updatePluginVersions(versions.plugins);
+					updateVersions(versions.plugins);
 				}
-				if(name == 'theme' && versions.themes[value])
+				if(name == 'theme' && versions.themes)
 				{
-					updateThemeVersion(versions.themes[value]);					
+					updateVersions(versions.themes);					
 				}
 			}
 			else
@@ -184,54 +186,24 @@
 			}
 		}, getPost, url, false, true);
 	}
-
-	function updatePluginVersions(pluginVersions)
-	{		
-		for (var key in pluginVersions)
+	
+	function updateVersions(elementVersions)
+	{
+		for (var key in elementVersions)
 		{
-			if (pluginVersions.hasOwnProperty(key))
+			if (elementVersions.hasOwnProperty(key))
 			{
-				pluginElement = document.getElementById(key);
-				if(pluginVersions[key] && pluginElement && cmpVersions(pluginVersions[key], pluginElement.innerHTML) > 0)
+				singleElement = document.getElementById(key);
+				
+				if(elementVersions[key] && singleElement && cmpVersions(elementVersions[key], singleElement.innerHTML) > 0)
 				{
-					pluginElement.innerHTML = "update to " + pluginVersions[key];
+					singleElement.innerHTML = "<span>update<br/>to " + elementVersions[key] + "</span>";
+					singleElement.classList.add("show-banner");
 				}
 			}
 		}
 	}
 	
-	function updateTypemillVersion(typemillVersion)
-	{
-		if(!document.getElementById('app-banner'))
-		{
-			var localTypemillVersion = document.getElementById('baseapp').dataset.version;
-			if(localTypemillVersion && cmpVersions(typemillVersion,localTypemillVersion) > 0)
-			{
-				addUpdateNotice('baseapp', 'app-banner', typemillVersion, 'http://typemill.net');
-			}			
-		}
-	}
-	
-	function updateThemeVersion(themeVersion)
-	{
-		var localThemeVersion = document.getElementById('themeVersion').innerHTML;
-		var themeUrl = document.getElementById('themeLink').href;
-		if(localThemeVersion && themeUrl && cmpVersions(themeVersion,localThemeVersion) > 0)
-		{
-			addUpdateNotice('themes', 'theme-banner', themeVersion, themeUrl);
-		}
-	}
-	
-	function addUpdateNotice(elementID, bannerID, version, url)
-	{
-		var updateElement 	= document.getElementById(elementID);
-		var banner 			= document.createElement('div');
-		banner.id 			= bannerID;
-		banner.className 	= 'version-banner';
-		banner.innerHTML 	= '<a href="' + url + '">update to ' + version + '</a>';
-		updateElement.appendChild(banner);
-	}
-	
 	/* credit: https://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number */
 	function cmpVersions (a, b) 
 	{
@@ -271,6 +243,7 @@
 				if(e.target.classList.contains("fc-settings"))
 				{
 					this.getElementsByClassName("cardFields")[0].classList.toggle("open");
+					this.getElementsByClassName("fc-settings")[0].classList.toggle("expand");
 				}
 			});
 		}

+ 1 - 1
system/author/partials/aside.twig

@@ -1,5 +1,5 @@
 <nav id="sidebar-menu" class="sidebar-menu">
-	<div id="mobile-menu" class="menu-action">Menu</div>
+	<div id="mobile-menu" class="menu-action">Menu <span class="button-arrow"></span></div>
 	<h3>Settings</h3>
 	<ul class="menu-list">
 		<li class="menu-item"><a href="{{ path_for('settings.show') }}"{{ (route == 'settings.show') ? 'class="active"' : '' }}>System</a></li>

+ 66 - 0
system/author/partials/forms.twig

@@ -0,0 +1,66 @@
+
+	<div class="cardField{{ errors[itemName][field.name] ? ' error' : '' }}">
+		
+		<label for="{{ itemName }}[{{ field.name }}]">{{ field.getLabel() }}
+			{% if field.getAttribute('required') %}<strong><abbr title="required">*</abbr></strong>{% endif %}
+			{% if field.help %}<div class="help">?<span class="tooltip">{{field.help|slice(0,100)}}</span></div>{% endif %}
+		</label>
+
+		{% if field.type == 'textarea' %}
+
+			<textarea name="{{ itemName }}[{{ field.name }}]"{{field.getAttributeValues() }}{{ field.getAttributes() }}>{{ field.getContent() }}</textarea>
+
+		{% elseif field.type == 'checkbox' %}
+			
+			<label class="control-group">{{ field.description }}
+				<input type="checkbox" name="{{ itemName}}[{{ field.name }}]"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
+				<span class="checkmark"></span>
+			</label>							
+
+		{% elseif field.type == 'checkboxlist' %}
+
+			{% set options = field.getOptions() %}
+
+			{% for value,label in options %}
+				
+				<label class="control-group">{{ label }}
+					<input type="checkbox" name="{{ itemName }}[{{ field.name }}]" value="{{value}}" {{ (value == settings.plugins[itemName][field.name]) ? ' checked' : '' }}>
+					<span class="checkmark"></span>
+				</label>
+
+			{% endfor %}
+
+		{% elseif field.type == 'select' %}
+
+			{% set options = field.getOptions() %}
+						
+			<select name="{{ itemName }}[{{ field.name }}]"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
+				{% for value,label in options %}
+					<option value="{{ value }}" {{ (value == field.getAttributeValue('value')) ? ' selected' : '' }}>{{ label }}</option>
+				{% endfor %}
+			</select>
+
+		{% elseif field.type == 'radio' %}
+
+			{% set options = field.getOptions() %}
+
+			{% for value,label in options %}
+				
+				<label class="control-group">{{ label }} 
+					<input type="radio" name="{{ itemName }}[{{ field.name }}]" value="{{ value }}" {{ (value == settings.plugins[itemName][field.name]) ? ' checked' : '' }}>
+					<span class="radiomark"></span>
+				</label>
+
+			{% endfor %}
+
+		{% else %}
+
+			<input name="{{itemName}}[{{ field.name }}]" type="{{ field.type }}"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
+
+		{% endif %}
+
+		{% if errors[itemName][field.name] %}
+			<span class="error">{{ errors[itemName][field.name] | first }}</span>
+		{% endif %}
+
+	</div>

+ 10 - 68
system/author/settings/plugins.twig

@@ -8,9 +8,9 @@
 
 		<form method="POST" action="{{ path_for('plugins.save') }}">
 
-			<section id="plugins" class="settings">
+			<section id="plugins" class="plugins">
 			
-				<header>
+				<header class="headline">
 					<h1>Plugins</h1>
 				</header>
 				
@@ -22,91 +22,33 @@
 								<legend>{{ pluginName }}</legend>							
 								<div class="cardActive">
 									<label class="control-group">Active
-										<input type="checkbox" class="fc-active" name="{{pluginName}}[active]"{% if plugin.settings.active %} checked {% endif %}>
+										<input type="checkbox" class="fc-active" name="{{pluginName}}[active]"{% if settings.plugins[pluginName].active %} checked {% endif %}>
 										<span class="checkmark"></span>
 									</label>
 								</div>
 							</header>
+							<div id="{{ pluginName }}" class="fc-plugin-version update-banner">{{ plugin.version ? plugin.version : 'Unknown' }}</div>
 
 							<p>{{ plugin.description ? plugin.description : 'No description' }}</p>
 							
 							<ul class="cardInfo">
-								<li id="{{ pluginName }}" class="fc-plugin-version">{{ plugin.version ? plugin.version : 'Unknown' }}</li><li>
+								<li>{{ plugin.version ? plugin.version : 'Unknown' }}</li><li>
 								{{ plugin.licence ? plugin.licence : 'Unkown' }}</li><li>
 								by {{ plugin.author ? plugin.author : 'Unknown' }}</li>{% if plugin.homepage %}<li>
 								<a href="{{ plugin.homepage}}" target="blank">Web</a></li>{% endif %}
 							</ul>
 						<div class="cardInner cardFields{{ errors[pluginName] ? ' open' : '' }}">
+						
 							{% for field in plugin.forms.fields %}
-													
-							<div class="cardField{{ errors[pluginName][field.name] ? ' error' : '' }}">
-								<label for="{{ pluginName }}[{{ field.name }}]">{{ field.getLabel() }}
-									{% if field.getAttribute('required') %}<strong><abbr title="required">*</abbr></strong>{% endif %}
-									{% if field.help %}<div class="help">?<span class="tooltip">{{field.help|slice(0,100)}}</span></div>{% endif %}
-								</label>
 								
-								{% if field.type == 'textarea' %}
+								{% include '/partials/forms.twig' with {'itemName' : pluginName } %}
 								
-									<textarea name="{{ pluginName }}[{{ field.name }}]"{{field.getAttributeValues() }}{{ field.getAttributes() }}>{{ field.getContent() }}</textarea>
-								
-								{% elseif field.type == 'checkbox' %}
-												
-									<label class="control-group">{{ field.description }}
-										<input type="checkbox" name="{{pluginName}}[{{ field.name }}]"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
-										<span class="checkmark"></span>
-									</label>							
-								
-								{% elseif field.type == 'checkboxlist' %}
-
-									{% set options = field.getOptions() %}
-									
-									{% for value,label in options %}
-												
-										<label class="control-group">{{ label }}
-											<input type="checkbox" name="{{pluginName}}[{{ field.name }}]" value="{{value}}">
-											<span class="checkmark"></span>
-										</label>
-												
-									{% endfor %}
-								
-								{% elseif field.type == 'select' %}
-								
-									{% set options = field.getOptions() %}
-									
-									<select name="{{pluginName}}[{{ field.name }}]"{{field.getAttributeValues() }}{{ field.getAttributes() }}>
-										{% for value,label in options %}
-											<option value="{{ value }}">{{ label }}</option>
-										{% endfor %}
-									</select>
-
-								{% elseif field.type == 'radio' %}
-									
-									{% set options = field.getOptions() %}
-
-									{% for value,label in options %}
-
-										<label class="control-group">{{ label }}
-											<input type="radio" name="{{pluginName}}[{{ field.name }}]" value="{{value}}">
-											<span class="radiomark"></span>
-										</label>
-									
-									{% endfor %}
-									
-								{% else %}
-								
-									<input name="{{pluginName}}[{{ field.name }}]" type="{{ field.type }}"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
-								
-								{% endif %}
-								
-								{% if errors[pluginName][field.name] %}
-									<span class="error">{{ errors[pluginName][field.name] | first }}</span>
-								{% endif %}
-								
-							</div>
 							{% endfor %}
+							
 						</div>
-							<button type="button" class="plugin-button fc-settings{{ plugin.settings.active ? ' active' : '' }}{{ plugin.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ plugin.forms.fields|length > 0 ? 'Settings' : 'No Settings'}}</button>
+							<button type="button" class="plugin-button fc-settings{{ settings.plugins[pluginName].active ? ' active' : '' }}{{ plugin.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ plugin.forms.fields|length > 0 ? 'Settings <span class="button-arrow"></span>' : '&nbsp;'}}</button>
 						</div>
+						
 					</fieldset>
 					
 				{% endfor %}

+ 6 - 3
system/author/settings/system.twig

@@ -1,6 +1,7 @@
 {% extends 'layouts/layout.twig' %}
 {% block title %}Setup{% endblock %}
 {% set startpage = old.settings.startpage ? old.settings.startpage : settings.startpage %}
+{% set year = settings.year ? settings.year : "now"|date("Y") %}
 
 {% block content %}
 	
@@ -8,12 +9,14 @@
 
 		<form method="POST" action="{{ path_for('settings.save') }}">
 		
-			<section id="baseapp" class="settings" data-version="{{ settings.version }}">
+			<section id="system" class="settings">
 
-				<header>
+				<header class="headline">
 					<h1>System</h1>
 				</header>
 				
+				<div id="typemill" class="fc-system-version update-banner">{{ settings.version ? settings.version : 'Unknown' }}</div>
+				
 				<fieldset>
 				
 					<div class="medium{{ errors.settings.title ? ' error' : '' }}">
@@ -40,7 +43,7 @@
 						{% endif %}
 					</div><div class="medium{{ errors.settings.year ? ' error' : '' }}">
 						<label for="settings[year]">Year *</label>
-						<input type="text" name="settings[year]" id="year" value="{{ old.settings.year ? old.settings.year : "now"|date("Y") }}" pattern="[0-9]{4}" required title="Use a valid year, e.g. 2017" />
+						<input type="text" name="settings[year]" id="year" value="{{ old.settings.year ? old.settings.year : year }}" pattern="[0-9]{4}" required title="Use a valid year, e.g. 2017" />
 						{% if errors.settings.year %}
 							<span class="error">{{ errors.settings.year | first }}</span>
 						{% endif %}

+ 7 - 68
system/author/settings/themes.twig

@@ -6,9 +6,9 @@
 	
 	<div class="formWrapper">
 
-			<section id="themes" class="settings">
+			<section id="themes" class="themes">
 			
-				<header>
+				<header class="headline">
 					<h1>Themes</h1>
 				</header>
 				
@@ -25,11 +25,13 @@
 									<div class="no-preview">No Preview</div>
 								{% endif %}
 
+								<div id="{{ themeName }}" class="fc-theme-version update-banner">{{ theme.version ? theme.version : 'Unknown' }}</div>
+								
 								<div class="cardContent">
 									<h2>{{ themeName }}</h2>
 									<p>{{ theme.description }}</p>
 									<ul class="cardInfo">
-										<li id="{{ themeName }}">{{ theme.version ? theme.version : 'Unknown' }}</li><li>
+										<li>{{ theme.version ? theme.version : 'Unknown' }}</li><li>
 										{{ theme.licence ? theme.licence : 'Unkown' }}</li><li>
 										by {{ theme.author ? theme.author : 'Unknown' }}</li>{% if theme.homepage %}<li>
 										<a href="{{ theme.homepage}}" target="blank">Web</a></li>{% endif %}
@@ -39,71 +41,8 @@
 								<div class="cardInner cardFields{{ errors[themeName] ? ' open' : '' }}">
 								
 									{% for field in theme.forms.fields %}
-															
-										<div class="cardField{{ errors[themeName][field.name] ? ' error' : '' }}">
-											<label for="{{ themeName }}[{{ field.name }}]">{{ field.getLabel() }}
-												{% if field.getAttribute('required') %}<strong><abbr title="required">*</abbr></strong>{% endif %}
-												{% if field.help %}<div class="help">?<span class="tooltip">{{field.help|slice(0,100)}}</span></div>{% endif %}
-											</label>
-										
-											{% if field.type == 'textarea' %}
-										
-												<textarea name="{{ themeName }}[{{ field.name }}]"{{field.getAttributeValues() }}{{ field.getAttributes() }}>{{ field.getContent() }}</textarea>
-										
-											{% elseif field.type == 'checkbox' %}
-														
-												<label class="control-group">{{ field.description }}
-													<input type="checkbox" name="{{themeName}}[{{ field.name }}]"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
-													<span class="checkmark"></span>
-												</label>							
-										
-											{% elseif field.type == 'checkboxlist' %}
-
-												{% set options = field.getOptions() %}
-											
-												{% for value,label in options %}
-												
-													<label class="control-group">{{ label }}
-														<input type="checkbox" name="{{fieldName}}[{{ field.name }}]" value="{{value}}">
-														<span class="checkmark"></span>
-													</label>
-														
-												{% endfor %}
-										
-											{% elseif field.type == 'select' %}
-										
-												{% set options = field.getOptions() %}
-											
-												<select name="{{themeName}}[{{ field.name }}]"{{field.getAttributeValues() }}{{ field.getAttributes() }}>
-													{% for value,label in options %}
-														<option value="{{ value }}">{{ label }}</option>
-													{% endfor %}
-												</select>
-
-											{% elseif field.type == 'radio' %}
-											
-												{% set options = field.getOptions() %}
-
-												{% for value,label in options %}
 
-													<label class="control-group">{{ label }}
-														<input type="radio" name="{{ themeName }}[{{ field.name }}]" value="{{value}}">
-														<span class="radiomark"></span>
-													</label>
-											
-												{% endfor %}
-											
-											{% else %}
-										
-												<input name="{{themeName}}[{{ field.name }}]" type="{{ field.type }}"{{ field.getAttributeValues() }}{{ field.getAttributes() }}>
-										
-											{% endif %}
-										
-											{% if errors[themeName][field.name] %}
-												<span class="error">{{ errors[themeName][field.name] | first }}</span>
-											{% endif %}
-										
-										</div>
+										{% include '/partials/forms.twig' with {'itemName' : themeName } %}
 								
 									{% endfor %}
 								
@@ -112,7 +51,7 @@
 								<input type="hidden" name="theme" value="{{ themeName }}">
 								
 								<div class="medium">
-									<button type="button" class="theme-button fc-settings{{ (settings.theme == themeName) ? ' active' : '' }}{{ theme.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ theme.forms.fields|length > 0 ? 'Settings' : 'No Settings'}}</button>
+									<button type="button" class="theme-button fc-settings{{ (settings.theme == themeName) ? ' active' : '' }}{{ theme.forms.fields|length > 0 ? ' has-settings' : ' no-settings'}}">{{ theme.forms.fields|length > 0 ? 'Settings <span class="button-arrow"></span>' : 'No Settings'}}</button>
 								</div>
 								<div class="medium">
 									<input type="submit" value="Save Theme" />								

+ 1 - 1
themes/typemill/chapter.twig

@@ -1,6 +1,6 @@
 <div class="chapter">
 	
-	<div class="chapterNumber">{{ settings.themesettings.chapter ? settings.themesettings.chapter : 'Chapter'}} {{ item.chapter }}</div>
+	<div class="chapterNumber">{{ settings.themes.typemill.chapter ? settings.themes.typemill.chapter : 'Chapter'}} {{ item.chapter }}</div>
 
 	{% if content is empty %}
 	

+ 1 - 1
themes/typemill/cover.twig

@@ -8,7 +8,7 @@
 
 		{{ content }}
 
-		<a href="{{ navigation[0].urlRel }}">{{ settings.themesettings.start ? settings.themesettings.start : 'Start'}}</a>
+		<a href="{{ navigation[0].urlRel }}">{{ settings.themes.typemill.start ? settings.themes.typemill.start : 'Start'}}</a>
 		
 		{% if settings.setup  %}
 			<a href="{{ base_url }}/setup">Setup</a>

+ 4 - 0
themes/typemill/page.twig

@@ -6,6 +6,10 @@
 	
 {{ content }}
 
+{% if settings.themes.typemill.modified %}	
+	<small>{{ settings.themes.typemill.modifiedText }}: {{ item.modified|date(settings.themes.typemill.modifiedFormat) }}</small>
+{% endif %}
+	
 {% if item.prevItem or item.nextItem %}
 
 	<div class="paging">

+ 1 - 1
themes/typemill/partials/layout.twig

@@ -24,7 +24,7 @@
 		<meta property="og:type" content="article">
 		<meta property="og:url" content="{{ item.urlAbs }}">
 		<meta property="og:image" content="{{ image.img_url }}">
-		<meta name="twitter:image:alt" content="{{ image.img_alt }}">		
+		<meta name="twitter:image:alt" content="{{ image.img_alt }}">
 		<meta name="twitter:card" content="summary_large_image">		
 
 		{% block stylesheets %}

+ 24 - 3
themes/typemill/typemill.yaml

@@ -1,6 +1,6 @@
 name: Typemill Theme
-version: 1.0.4
-description: The Standard Theme For Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. Only JavaScript is for code highlighting, skip it, if you don't need it. 
+version: 1.0.5
+description: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. JavaScript is only used for code highlighting. Skip it, if you don't need it. 
 author: Sebastian Schürmanns
 homepage: http://typemill.net
 licence: MIT
@@ -8,6 +8,9 @@ licence: MIT
 settings:
   chapter: Chapter
   start: Start
+  modified: true
+  modifiedText: 'Last updated'
+  modifiedFormat: 'd.m.Y'
 
 forms:
   fields:
@@ -22,4 +25,22 @@ forms:
       type: text
       label: Start-Button
       placeholder: Add Label for Start-Button
-      required: true
+      required: true
+
+    modified:
+      type: checkbox
+      label: Last Updated
+      description: Show last updated note at the end of each page?
+
+    modifiedText:
+      type: text
+      label: Last Updated Text
+      placeholder: Last Updated
+
+    modifiedFormat:
+      type: select
+      label: Last Updated Format
+      placeholder: 'Add name of theme'
+      options:
+        'm/d/Y': 01/20/2020
+        'd.m.Y': 20.01.2020

BIN
typemill-1.1.4.zip