├── .gitignore ├── LICENSE ├── Lipi.iml ├── META-INF └── MANIFEST.MF ├── README.md ├── pom.xml ├── res ├── custom.css ├── hugo-res │ ├── default-config.toml │ ├── exampleBlog │ │ └── content │ │ │ └── post │ │ │ ├── lipi-te-sagotom.md │ │ │ └── welcome-to-lipi.md │ └── themes │ │ ├── anybodyhome │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── archetypes │ │ │ └── default.md │ │ ├── images │ │ │ ├── screenshot.png │ │ │ └── tn.png │ │ ├── layouts │ │ │ ├── 404.html │ │ │ ├── _default │ │ │ │ ├── paginator.html │ │ │ │ ├── single.html │ │ │ │ └── summary.html │ │ │ ├── index.html │ │ │ ├── partials │ │ │ │ ├── footer.html │ │ │ │ ├── head.html │ │ │ │ ├── header.html │ │ │ │ └── paginator.html │ │ │ └── summary.html │ │ ├── static │ │ │ └── css │ │ │ │ └── styles.css │ │ └── theme.toml │ │ └── robust │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── images │ │ ├── screenshot.png │ │ └── tn.png │ │ ├── layouts │ │ ├── _default │ │ │ ├── grid.html │ │ │ ├── li.html │ │ │ ├── list.html │ │ │ ├── single.html │ │ │ └── terms.html │ │ ├── index.html │ │ ├── partials │ │ │ ├── footer.html │ │ │ ├── header_after.html │ │ │ ├── header_before.html │ │ │ ├── pagination.html │ │ │ └── sidebar.html │ │ └── rss.xml │ │ ├── static │ │ ├── css │ │ │ ├── custom.css │ │ │ └── styles.css │ │ └── images │ │ │ └── default.jpg │ │ └── theme.toml ├── kalpurush.ttf ├── lipi-hmdeditor-icon.png ├── lipi-icon.png └── material.css ├── src ├── Lipi.java ├── META-INF │ └── MANIFEST.MF ├── model │ ├── hugo │ │ ├── HMDFileCreator.java │ │ ├── HMDFileProcessor.java │ │ └── Hugo.java │ ├── toml │ │ ├── TomlConfig.java │ │ ├── TomlParser.java │ │ ├── TomlString.java │ │ └── TomlUtils.java │ └── utility │ │ ├── .directory │ │ ├── CallbackVisitor.java │ │ ├── FileHandler.java │ │ ├── Ipc.java │ │ ├── MarkdownFileUtils.java │ │ └── Pandoc.java ├── tests │ ├── RunTests.java │ └── RunTestsJavaFX.java └── view │ ├── dashboard │ ├── DashboardMain.java │ └── dashboard_main.fxml │ ├── filetree │ ├── FileTreeTable.java │ └── file_tree_table.fxml │ ├── hugo │ ├── hmd │ │ ├── HMDPostEditor.fxml │ │ ├── HMDPostEditorControl.java │ │ ├── TabbedHMDPostEditor.fxml │ │ └── TabbedHMDPostEditor.java │ ├── markdown │ │ └── MarkdownEditorControl.java │ └── pane │ │ ├── HostServicesProviderUtil.java │ │ ├── HugoPane.java │ │ └── hugo_pane.fxml │ ├── toml │ ├── TomlConfigEditor.java │ ├── TomlEditorControl.java │ └── TomlEntryEditor.java │ ├── utils │ ├── ExceptionAlerter.java │ ├── TakeTwoInputsDialog.java │ └── TimedUpdaterUtil.java │ └── wizard │ ├── BasicConfig.java │ ├── WelcomeWizard.java │ ├── basic_config.fxml │ └── welcome_wizard.fxml └── tests-res ├── a.html ├── a.md ├── test.html ├── test.md ├── tomlConfigTest.toml └── tomlParserTest.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Package Files # 2 | *.directory 3 | 4 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 5 | #ide 6 | .idea/ 7 | 8 | exec/ 9 | lib/ 10 | out/ 11 | 12 | #maven output folder 13 | target/ 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Sohan Chowdhury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lipi.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Lipi 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Welcome to Lipi, a simple click and type static blog creator 2 | ------- 3 | > Hugo is one of the most popular open-source static site generators. 4 | With its amazing speed and flexibility, Hugo makes building websites fun again. 5 | 6 | Lipi brings the the awesomeness of Hugo wrapped in a GUI, and tries make Hugo more easy to use day to day without having to remember any pesky commands. 7 | 8 | #### Notice October 2020 9 | > - I no longer maintain this project 10 | > - If you are interested in extending or helping out please reach out 11 | > - I have distant plans to completely rebuild Lipi as an Electron App(ReactJs based), if there is interest please let me know. 12 | 13 | #### Changelog 14 | > - Now images can be added to post using the Insert Image button on the editor. 15 | > - An option to auto open last opened blog has been added as well. 16 | 17 | #### Why #### 18 | - No need to remember or type commands so no distractions. 19 | - Just click buttons, write thoughts, and your blog is ready. 20 | - Upload anywhere that supports HTML (web server, github, even dropbox, etc) and the world can see it! 21 | - All the awesome benefits of static sites with dynamicity handled using Hugo. 22 | 23 | #### How #### 24 | Created with JavaFX8, using: 25 | 26 | - Hugo : https://github.com/gohugoio/hugo 27 | - Pandoc : https://github.com/jgm/pandoc 28 | - Toml4j : https://github.com/mwanji/toml4j 29 | - Gson : https://github.com/google/gson 30 | 31 | This is the second public beta release of Lipi, so there might be bugs! 32 | If you find a bug or need a feature, feel free to open an issue or email me sifat3d@gmail.com. 33 | 34 | #### Download #### 35 | For download and install instructions, visit the releases page: 36 | [https://github.com/SohanChy/Lipi/releases](https://github.com/SohanChy/Lipi/releases) 37 | 38 | Screenshots 39 | ------- 40 | ![1](https://i.imgur.com/XIQLKcT.png) 41 | 42 | ![2](https://i.imgur.com/rxpNgdr.png) 43 | 44 | ![3](https://i.imgur.com/8Tu9bI1.png) 45 | 46 | ![4](https://i.imgur.com/uD4aPyf.png) 47 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.github.sohanchy 5 | lipi 6 | 0.7.0-beta 7 | 8 | 9 | Lipi 10 | https://github.com/SohanChy/Lipi 11 | Lipi brings the the awesomeness of Hugo wrapped in a GUI. 12 | 13 | 14 | scm:git:git@github.com:sohanChy/Lipi 15 | scm:git:git@github.com:sohanChy/Lipi 16 | scm:git:git@github.com:sohanChy/Lipi 17 | HEAD 18 | 19 | 20 | 21 | 1.8 22 | 1.8 23 | UTF-8 24 | UTF-8 25 | 26 | 27 | 28 | 29 | MIT 30 | https://github.com/SohanChy/Lipi/blob/master/LICENSE 31 | 32 | 33 | 34 | 35 | GitHub issues 36 | https://github.com/SohanChy/Lipi/issues 37 | 38 | 39 | 40 | 41 | com.moandjiezana.toml 42 | toml4j 43 | 0.7.1 44 | 45 | 46 | com.guigarage 47 | flatter 48 | 0.7 49 | 50 | 51 | com.google.code.gson 52 | gson 53 | 2.8.1 54 | 55 | 56 | commons-io 57 | commons-io 58 | 2.5 59 | 60 | 61 | 62 | 63 | src 64 | src 65 | 66 | 67 | src 68 | 69 | 70 | res 71 | 72 | 73 | 74 | 75 | tests-res 76 | 77 | 78 | 79 | 80 | org.codehaus.mojo 81 | exec-maven-plugin 82 | 1.2.1 83 | 84 | Lipi 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /res/custom.css: -------------------------------------------------------------------------------- 1 | //Customize Material.css BASE COLOR 2 | .root { 3 | -fx-basic-color: #00352C !important; 4 | -fx-control-inner-background: #f0f0f0 !important; 5 | } 6 | 7 | .split-pane:horizontal > .split-pane-divider { 8 | -fx-background-color: transparent; 9 | } 10 | .split-pane:vertical > .split-pane-divider { 11 | -fx-background-color: transparent; 12 | } 13 | 14 | .split-pane, .anchor-pane, .tool-bar, .html-editor, .scroll-pane, .v-box, .h-box, .tab-pane, .tab-header-background, .toml-entry { 15 | -fx-background-color: #607D8B; 16 | -fx-padding: 0 0 0 0; 17 | } 18 | 19 | .bg-theme-dark { 20 | -fx-background-color: #607D8B !important; 21 | } 22 | 23 | .bg-theme-dark .label { 24 | -fx-text-fill: #F5F5F5; 25 | } 26 | 27 | .bg-theme-dark .choice-box .label { 28 | -fx-text-fill: -fx-text-color; 29 | } 30 | 31 | 32 | .anchor-pane > .tool-bar{ 33 | -fx-padding: 0 0 9 9; 34 | } 35 | 36 | .text, .html-editor { 37 | -fx-font-family: "Siyam Rupali" !important; 38 | 39 | } 40 | 41 | .toml-entry { 42 | -fx-border-color: #607D8B; 43 | -fx-border-width: 0 0 2 0; 44 | -fx-padding: 5 0 5 0; 45 | } 46 | 47 | .toml-entry > .label { 48 | -fx-padding: 0 0 0 0; 49 | -fx-font-size:12px; 50 | -fx-text-fill: #F5F5F5; 51 | } 52 | 53 | .scroll-bar .track { 54 | -fx-background-color: -fx-lighter-color !important; 55 | } 56 | 57 | //TOML Editor 58 | .save-button-vbox .button { 59 | -fx-padding: 10 60 10 60; 60 | -fx-border-insets: 5; 61 | -fx-background-insets: 5; 62 | } 63 | 64 | .list-cell { 65 | -fx-alignment: center; 66 | } 67 | 68 | .hyperlink { 69 | 70 | } -------------------------------------------------------------------------------- /res/hugo-res/default-config.toml: -------------------------------------------------------------------------------- 1 | canonifyurls = "true" 2 | SectionPagesMenu = "main" 3 | paginate = "10" 4 | Title = "Hello Lipi" 5 | LanguageCode = "en-us" 6 | pluralizeListTitles = "false" 7 | theme = "sohan-light-cards" 8 | BaseURL = "/" 9 | 10 | [Taxonomies] 11 | tags = "tags" 12 | 13 | [Params] 14 | SyntaxHighlightTheme = "default.min.css" 15 | ShowTagCloud = "true" 16 | Author = "Sohan Chowdhury" 17 | ShowRelatedPost = "true" 18 | -------------------------------------------------------------------------------- /res/hugo-res/exampleBlog/content/post/lipi-te-sagotom.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "লিপি তে স্বাগতম" 3 | date = "2016-09-26" 4 | description = "লিপি একটি সহজ সরল স্টাটিক ব্লগ তৈরির গ্রাফিকাল ইন্টারফেসযুক্ত প্রোগ্রাম।" 5 | +++ 6 | 7 | স্বাগতম! 8 | -------- 9 | 10 | লিপিতে আপনার নতুন ব্লগটি তৈরি হয়েছে, 11 | এটা সেই ব্লগের একটি উদাহরন পোস্ট। 12 | লিপি একটি সহজ সরল স্টাটিক ব্লগ তৈরির গ্রাফিকাল ইন্টারফেসযুক্ত প্রোগ্রাম। 13 | 14 | শুরু করতে চাইলেঃ  15 | 16 | - এই পোস্টটি ডিলেট করুন। 17 | - নতুন পোস্ট লিখুন। 18 | - প্রয়োজনে পোস্টের নতুন টাইপ তৈরি করুন। 19 | 20 | ব্যাপারটা এতটাই সহজ! 21 | 22 | > এই যে এতসব বাটন আর বাক্স, এগুলো কোনটা দিলে কি হয় পরীক্ষা করে দেখুন, আর দেখুন কি থেকে কি হয়। 23 | > :) 24 | -------------------------------------------------------------------------------- /res/hugo-res/exampleBlog/content/post/welcome-to-lipi.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Welcome To Lipi" 3 | date = "2016-09-26" 4 | description = "Lipi is a simple gui to make static blogs." 5 | +++ 6 | 7 | Hello! 8 | ------ 9 | 10 | This an example post on your new Blog on Lipi. 11 | Lipi is a simple software to make awesome static blogs. 12 | To get started: 13 | 14 | - Delete this post. 15 | - Write new posts.  16 | - Create new post types if you want. 17 | 18 | Its that simple! 19 | 20 | > Play around with all these boxes and buttons & see where that takes you. 21 | > :) 22 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 YOUR_NAME_HERE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/README.md: -------------------------------------------------------------------------------- 1 | # Anybody Home? 2 | 3 | ![anybodyhome](https://github.com/lasseborly/anybodyhome/blob/master/images/screenshot.png "Anybody Home?") 4 | 5 | A simple theme for simple people with simple needs. 6 | 7 | The focus of the theme is to use as few dependencies as possible to keep the layout simple and bloat free. 8 | 9 | ## Features 10 | * __Blog only__ - Only a list of the 10 most recent posts and added pagination. There is no other pages than the main page and the post page. 11 | * [__Highlight.js__](https://highlightjs.org/) - For all of you code needs. 12 | 13 | ## Getting Started 14 | From the root of you Hugo site clone the theme into `themes/anybodyhome` by running: 15 | 16 | `git clone https://github.com/lasseborly/anybodyhome.git themes/anybodyhome` 17 | 18 | ## Usage 19 | To use Anybody Home? you must first, from the root of your Hugo site, run either: 20 | 21 | `hugo -t anybodyhome` 22 | 23 | or set in you `config.toml`. 24 | 25 | `theme = "anybodyhome"` 26 | 27 | ## Configuration 28 | You can set the normal Hugo site variables in your `config.toml` but there is also some custom Anybody Home? variables you can set. This is an example of a full `config.toml`. 29 | 30 | ```toml 31 | theme = "anybodyhome" 32 | baseurl = "https://hugosite.com" 33 | languageCode = "en-us" 34 | title = "Anybody Home?" 35 | 36 | [params] 37 | subtitle = "A Simple Theme" 38 | ``` 39 | 40 | ## Contributing 41 | 42 | 1. Fork it 43 | 2. Create your feature branch - `git checkout -b my-new-feature-or-fix` 44 | 3. Commit your changes - `git commit -am 'Add some feature-or-fix'` 45 | 4. Push to the branch - `git push origin my-new-feature-or-fix` 46 | 5. Create new Pull Request 47 | 48 | ## Extra 49 | Take a look at my [docker setup](https://github.com/lasseborly/hugo-development) for developing with Hugo. It's, again, very simple, straight forward and open for contributions. 50 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | +++ 3 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/anybodyhome/images/screenshot.png -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/anybodyhome/images/tn.png -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/anybodyhome/layouts/404.html -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/_default/paginator.html: -------------------------------------------------------------------------------- 1 | {{ if .Paginator.HasPrev }} 2 | 3 | Previous Page 4 | 5 | {{ end }} 6 | {{ if .Paginator.HasNext }} 7 | 8 | Next Page 9 | 10 | {{ end }} 11 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ partial "head.html" }} 2 | {{ partial "header.html" . }} 3 | {{ $baseurl := .Site.BaseURL }} 4 |
5 |
6 |

{{ .Title }}

7 | 8 |
9 |
10 |
11 | {{ .Content }} 12 |
13 |
14 |
15 | {{ partial "footer.html" . }} 16 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/_default/summary.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ .Title }} 4 |

5 | 6 |
7 |

{{ .Summary }}

8 |
9 |
10 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/index.html: -------------------------------------------------------------------------------- 1 | {{ partial "head.html" . }} 2 | 3 | 4 | 5 | {{ partial "header.html" . }} 6 | 7 |
8 | {{ range (.Paginator 5).Pages }} 9 | {{ .Render "summary" }} 10 | {{ end }} 11 |
12 | 13 | {{ partial "paginator.html" . }} 14 | 15 | {{ partial "footer.html" . }} 16 | 17 | 18 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/partials/footer.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/anybodyhome/layouts/partials/footer.html -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ .Site.Title }} 7 | 8 | 12 | 13 | 19 | 20 | 25 | 26 | 31 | 34 | 37 | 38 | 43 | 44 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/partials/paginator.html: -------------------------------------------------------------------------------- 1 |
2 | {{ if .Paginator.HasPrev }} 3 | 6 | {{ end }} 7 | {{ if .Paginator.HasNext }} 8 | 11 | {{ end }} 12 |
13 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/layouts/summary.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ .Title }}

3 |

{{ .Date.Format "2. January, 2006"}}

4 |
5 |
6 | {{ .Summary }} 7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/static/css/styles.css: -------------------------------------------------------------------------------- 1 | @import 'https://fonts.googleapis.com/css?family=Lobster|Quicksand|Cutive+Mono'; 2 | 3 | body { 4 | width: 600px; 5 | margin: 0 auto; 6 | font-size: 18px; 7 | font-weight: 400; 8 | font-family: 'Quicksand', sans-serif; 9 | } 10 | 11 | @media(max-width: 600px) { 12 | body { 13 | width: 100%; 14 | box-sizing: border-box; 15 | padding: 0 20px; 16 | } 17 | } 18 | 19 | a { 20 | text-decoration: none; 21 | color: #336699; 22 | } 23 | 24 | a:visited { 25 | color: #000; 26 | } 27 | 28 | a:hover { 29 | color: #C0C0C0; 30 | } 31 | 32 | p { 33 | line-height: 1.4; 34 | text-align: justify; 35 | } 36 | 37 | section#header { 38 | margin: 40px 0; 39 | } 40 | 41 | section#header h1 { 42 | font-size: 2em; 43 | text-align: center; 44 | font-family: 'Lobster', cursive; 45 | font-size: 2em; 46 | margin: 0 0 9px 0; 47 | } 48 | 49 | section#header h2 { 50 | font-family: 'Cutive Mono', monospace; 51 | font-size: 0.8em; 52 | text-align: center; 53 | } 54 | 55 | section.summary { 56 | padding: 0 0 0 10px; 57 | border-left: 1px solid black; 58 | margin: 0 0 60px 0; 59 | } 60 | 61 | @media(max-width: 600px) { 62 | section.summary { 63 | padding: 0 0 0 0; 64 | border-left: 0px solid black; 65 | } 66 | } 67 | 68 | section.summary article { 69 | margin: 15px 0 0 0; 70 | } 71 | 72 | section h2 { 73 | font-size: 1.3em; 74 | font-family: 'Lobster', cursive; 75 | } 76 | 77 | section h2 a { 78 | color: #000; 79 | } 80 | 81 | section time { 82 | margin: 0 0 0 2px; 83 | font-size: 0.7em; 84 | font-weight: 600; 85 | } 86 | 87 | section article { 88 | margin: 15px 0 0 0; 89 | } 90 | 91 | section#paginator { 92 | margin: 0 0 140px 0; 93 | font-family: 'Lobster', cursive; 94 | } 95 | 96 | section#paginator #next { 97 | float: right; 98 | } 99 | 100 | #post { 101 | margin: 0 0 100px 0; 102 | } 103 | 104 | .videoWrapper { 105 | position: relative; 106 | padding-bottom: 56.25%; /* 16:9 */ 107 | padding-top: 25px; 108 | height: 0; 109 | margin: 10px; 110 | } 111 | .videoWrapper iframe { 112 | position: absolute; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: 100%; 117 | } 118 | -------------------------------------------------------------------------------- /res/hugo-res/themes/anybodyhome/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Anybody Home" 2 | license = "MIT" 3 | licenselink = "https://github.com/lasseborly/anybodyhome/blob/master/LICENSE.md" 4 | description = "A simple theme for simple people with simeple needs" 5 | homepage = "https:/blog.lasseborly.dk/" 6 | tags = ["clean", "simple"] 7 | features = ["highlightjs", "Blog only"] 8 | min_version = 0.16 9 | 10 | [author] 11 | name = "Lasse Borly 2 | 3 |
4 |
5 |
6 | 7 |
8 |

{{ .Title }}

9 |
{{ .Summary }}
10 |
11 |
12 | 13 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/_default/li.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 |
8 |

{{ .Title }}

9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ partial "header_before.html" . }} 2 | {{ partial "header_after.html" . }} 3 | 4 |
5 |
6 |
7 | 8 |

{{ .Title }}

9 | 10 |
11 | {{ range (.Paginate .Data.Pages).Pages }} 12 |
13 | {{ .Render "grid" }} 14 |
15 | {{ end }} 16 |
17 | 18 | {{ partial "pagination.html" . }} 19 | 20 |
21 | 22 |
23 | {{ partial "sidebar.html" . }} 24 |
25 | 26 |
27 | 28 |
29 | 30 | {{ partial "footer.html" . }} 31 | 32 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ partial "header_before.html" . }} 2 | 37 | {{ partial "header_after.html" . }} 38 | 39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |

{{ .Title }}

48 | {{ .Content }} 49 |
50 | 51 | 83 | 84 |
85 | 86 |
87 |
88 | {{ partial "sidebar.html" . }} 89 |
90 |
91 |
92 | 93 | {{ partial "footer.html" . }} 94 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/_default/terms.html: -------------------------------------------------------------------------------- 1 | {{ partial "header_before.html" . }} 2 | {{ partial "header_after.html" . }} 3 | 4 |
5 |
6 |
7 | 8 |

{{ .Title }}

9 | 10 |
    11 | {{ range $key, $value := .Data.Terms }}
  • {{ $key }}
  • {{ end }} 12 |
13 | 14 |
15 | 16 |
17 | {{ partial "sidebar.html" . }} 18 |
19 | 20 |
21 | 22 |
23 | 24 | {{ partial "footer.html" . }} 25 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/index.html: -------------------------------------------------------------------------------- 1 | 2 | {{ partial "header_before.html" . }} 3 | {{ partial "header_after.html" . }} 4 | 5 |
6 |
7 |
8 | 9 |
10 | {{ range $key, $value := .Paginator.Pages }} 11 | {{ if lt $key 4 }} 12 |
13 | {{ .Render "grid" }} 14 |
15 | {{ else }} 16 |
17 | {{ .Render "grid" }} 18 |
19 | {{ end }} 20 | {{ end }} 21 |
22 | 23 | {{ partial "pagination.html" . }} 24 | 25 |
26 | 27 |
28 | {{ partial "sidebar.html" . }} 29 |
30 | 31 |
32 | 33 |
34 | 35 | {{ partial "footer.html" . }} 36 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{ with .Site.Params.GoogleAnalyticsUserID }} 13 | 21 | {{ end }} 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/partials/header_after.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/partials/header_before.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ .Hugo.Generator }} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {{ if eq .URL "/" }} 17 | {{ .Title }} 18 | 19 | 20 | {{ else }} 21 | {{ .Title }} - {{ .Site.Title }} 22 | 23 | 24 | {{ end }} 25 | 26 | 27 | {{ with .Description }}{{ end }} 28 | {{ with .Params.image }}{{ end }} 29 | 30 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/partials/pagination.html: -------------------------------------------------------------------------------- 1 | {{ if or (.Paginator.HasPrev) (.Paginator.HasNext) }} 2 | 11 | {{ end }} 12 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/partials/sidebar.html: -------------------------------------------------------------------------------- 1 | 59 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/layouts/rss.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ .Site.Title }} 4 | {{ .Permalink }} 5 | en-us 6 | {{ .Site.Params.Author }} 7 | (C) {{ .Site.LastChange.Year }} 8 | {{ .Date }} 9 | 10 | {{ range .Data.Pages }} 11 | {{ if eq .Type "post"}} 12 | 13 | {{ .Title }} 14 | {{ .Permalink }} 15 | {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 MST" }} 16 | {{ .Site.Params.Author }} 17 | {{ .Permalink }} 18 | {{ .Content | html }} 19 | 20 | {{ end }} 21 | {{ end }} 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/static/css/custom.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/robust/static/css/custom.css -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/static/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * #eceff1 3 | * #b0bec5 4 | * #78909c 5 | */ 6 | 7 | /* Reset */ 8 | html { 9 | font-size: 16px; 10 | } 11 | 12 | body { 13 | font-family: "Noticia Text", "游明朝", YuMincho, "ヒラギノ明朝 ProN W3", "Hiragino Mincho ProN", "HG明朝E", "MS P明朝", "MS 明朝", serif; 14 | font-size: inherit; 15 | font-size: inherit; 16 | color: #000; 17 | line-height: 1rem; 18 | background-color: #eceff1; 19 | } 20 | 21 | a { 22 | color: #000; 23 | } 24 | 25 | a:hover, a:focus, a:active { 26 | color: #000; 27 | text-decoration: none; 28 | } 29 | 30 | p { 31 | margin: 0; 32 | } 33 | 34 | ul, ol { 35 | padding: 0; 36 | padding-left: 1.5rem; 37 | } 38 | 39 | li { 40 | line-height: 1.5rem; 41 | } 42 | 43 | img { 44 | width: 100%; 45 | } 46 | 47 | h1, h2, h3, h4, h5 ,h6 { margin: 0; } 48 | h1 { font-size: 1.6rem; line-height: 2rem; } 49 | h2 { font-size: 1.3rem; line-height: 2rem; } 50 | h3 { font-size: 1.1rem; line-height: 2rem; } 51 | h4 { font-size: 1rem; line-height: 1rem; } 52 | h5 { font-size: 1rem; line-height: 1rem; } 53 | 54 | @media (max-width: 768px) { 55 | h1 { font-size: 1.4rem; line-height: 1.5rem; } 56 | h2 { font-size: 1.2rem; line-height: 1.5rem; } 57 | } 58 | 59 | 60 | /* Override */ 61 | #TableOfContents { 62 | font-size: .8rem; 63 | line-height: 1.5rem; 64 | } 65 | 66 | #TableOfContents a { 67 | display: block; 68 | } 69 | 70 | #TableOfContents ul ul a { 71 | text-decoration: none; 72 | } 73 | 74 | #TableOfContents>ul { 75 | padding-left: 0; 76 | list-style: none; 77 | } 78 | 79 | #TableOfContents>ul>li { 80 | font-weight: 900; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | #TableOfContents>ul ul { 85 | padding-left: 0; 86 | font-weight: normal; 87 | list-style: none; 88 | } 89 | 90 | #TableOfContents>ul ul ul { 91 | padding-left: 1rem; 92 | list-style: none; 93 | } 94 | 95 | /* Layouts */ 96 | .l-header { 97 | background-color: #fff; 98 | padding: 1.5rem 0; 99 | text-align: center; 100 | margin-bottom: 2rem; 101 | } 102 | 103 | .l-footer { 104 | margin-top: 4rem; 105 | padding: 1rem 0; 106 | font-size: .8rem; 107 | color: #b0bec5; 108 | text-align: center; 109 | } 110 | 111 | .l-footer a { 112 | color: #78909c; 113 | } 114 | 115 | /* Parts:logo */ 116 | .p-logo a { 117 | font-family: 'Marcellus SC', cursive; 118 | font-size: 2rem; 119 | } 120 | 121 | /* Parts:menu */ 122 | .p-menu { 123 | line-height: 1.5rem; 124 | } 125 | 126 | .p-menu a { 127 | display: block; 128 | } 129 | 130 | .p-menu ul { 131 | font-size: .8rem; 132 | list-style: none; 133 | padding-left: 0; 134 | } 135 | 136 | .p-menu ul a { 137 | text-decoration: none; 138 | } 139 | 140 | .p-menu ul ul { 141 | padding-left: 1rem; 142 | } 143 | 144 | /* Parts:share */ 145 | .p-share { 146 | text-align: center; 147 | } 148 | 149 | .p-share a { 150 | display: inline-block; 151 | width: 2rem; 152 | height: 2rem; 153 | line-height: 2rem; 154 | background-color: #263238; 155 | border-radius: 100%; 156 | color: #eceff1; 157 | margin: 0 .5rem; 158 | } 159 | 160 | /* Parts:page-title */ 161 | .p-page-title { 162 | margin-bottom: 2rem; 163 | } 164 | 165 | /* Parts:paging */ 166 | .p-paging a { 167 | display: inline-block; 168 | line-height: 2rem; 169 | padding: 0 1rem; 170 | background-color: #b0bec5; 171 | margin-right: .5rem; 172 | } 173 | 174 | /* Parts:section */ 175 | section { 176 | margin-bottom: 2rem; 177 | } 178 | 179 | section>header { 180 | margin-bottom: .5rem; 181 | text-transform: uppercase; 182 | font-weight: 700; 183 | } 184 | 185 | section>div { 186 | font-size: .8rem; 187 | } 188 | 189 | /* Parts:article */ 190 | article { 191 | word-break: break-all; 192 | } 193 | 194 | article>a { 195 | display: block; 196 | } 197 | 198 | article .image { 199 | background-size: cover; 200 | background-position: center; 201 | } 202 | 203 | article .date { 204 | font-size: .8rem; 205 | } 206 | 207 | /* Parts:article:li */ 208 | article.li { 209 | margin-bottom: .5rem; 210 | } 211 | 212 | article.li .image { 213 | float: left; 214 | width: 2.5rem; 215 | height: 2.5rem; 216 | } 217 | 218 | article.li footer { 219 | display: table-cell; 220 | height: 2.5rem; 221 | vertical-align: middle; 222 | padding-left: .5rem; 223 | } 224 | 225 | article.li .date { 226 | font-size: .7rem; 227 | } 228 | 229 | article.li .title { 230 | font-size: .8rem; 231 | line-height: 1rem; 232 | font-weight: 700; 233 | } 234 | 235 | /* Parts:article:grid */ 236 | article.grid { 237 | margin-bottom: 2rem; 238 | background-color: #fff; 239 | height: 24rem; 240 | max-height: 24rem; 241 | overflow: hidden; 242 | } 243 | 244 | article.grid .image { 245 | min-height: 12rem; 246 | } 247 | 248 | article.grid .title { 249 | margin-bottom: .5rem; 250 | font-size: 1.2rem; 251 | line-height: 1.5rem; 252 | max-height: 4.5rem; 253 | overflow: hidden; 254 | } 255 | 256 | article.grid .summary { 257 | color: #333; 258 | max-height: 4rem; 259 | overflow: hidden; 260 | } 261 | 262 | article.grid footer { 263 | padding: 1rem; 264 | } 265 | 266 | /* Parts:article:single */ 267 | article.single { 268 | margin-bottom: 2rem; 269 | padding-bottom: 2rem; 270 | background-color: #fff; 271 | } 272 | 273 | article.single .image { 274 | min-height: 24rem; 275 | } 276 | 277 | @media (max-width: 768px) { 278 | article.single .image { 279 | min-height: 12rem; 280 | } 281 | } 282 | 283 | article.single aside { 284 | padding: 0 1rem; 285 | } 286 | 287 | article.single .body { 288 | margin: 0 auto; 289 | margin-bottom: 2rem; 290 | padding: 0 2rem; 291 | } 292 | 293 | @media (max-width: 768px) { 294 | article.single .body { 295 | padding: 0 1rem; 296 | } 297 | } 298 | 299 | article.single .body a { 300 | color: #78909c; 301 | text-decoration: underline; 302 | } 303 | 304 | article.single .body p { 305 | margin: 1rem 0; 306 | line-height: 1.5rem; 307 | } 308 | 309 | article.single .body pre { 310 | margin: 1rem -2rem; 311 | border-radius: 0; 312 | padding: 0; 313 | border: none; 314 | font-size: .7rem; 315 | line-height: 1rem; 316 | } 317 | 318 | article.single .body pre code { 319 | padding: 1rem 2rem; 320 | } 321 | 322 | @media (max-width: 768px) { 323 | article.single .body pre { 324 | margin: 1rem -1rem; 325 | } 326 | article.single .body pre code { 327 | padding: 1rem 1rem; 328 | } 329 | } 330 | 331 | article.single .body p>code { 332 | font-size: .8rem; 333 | line-height: 1rem; 334 | background-color: #eceff1; 335 | color: #78909c; 336 | } 337 | 338 | article.single .body h1 { margin: 2rem 0; font-weight: 700; } 339 | article.single .body h2 { margin: 2rem 0; font-weight: 700; } 340 | article.single .body h3 { margin: 1rem 0; font-weight: 700; } 341 | 342 | /* Helpers */ 343 | ul.h-inline, 344 | ol.h-inline { 345 | padding-left: 0; 346 | } 347 | 348 | .h-inline li { 349 | display: inline-block; 350 | margin-right: .5rem; 351 | } 352 | -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/static/images/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/hugo-res/themes/robust/static/images/default.jpg -------------------------------------------------------------------------------- /res/hugo-res/themes/robust/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Robust" 2 | license = "MIT" 3 | licenselink = "https://github.com/dim0627/hugo_theme_robust/blob/master/LICENSE.md" 4 | description = "Robust is blog theme for hugo." 5 | tags = ["blog"] 6 | features = ["blog"] 7 | min_version = 0.15 8 | 9 | [author] 10 | name = "Daisuke Tsuji" 11 | homepage = "http://yet.unresolved.xyz/" 12 | 13 | -------------------------------------------------------------------------------- /res/kalpurush.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/kalpurush.ttf -------------------------------------------------------------------------------- /res/lipi-hmdeditor-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/lipi-hmdeditor-icon.png -------------------------------------------------------------------------------- /res/lipi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SohanChy/Lipi/a279893fba2e71b5b1c82b9372414ca6c3fa3ebc/res/lipi-icon.png -------------------------------------------------------------------------------- /res/material.css: -------------------------------------------------------------------------------- 1 | 2 | .root { 3 | -fx-basic-color: red; 4 | -fx-darker-color: derive(-fx-basic-color, -40% ); 5 | -fx-lighter-color: derive(-fx-basic-color, 80% ); 6 | -fx-lightest-color: derive(-fx-basic-color, 95% ); 7 | -fx-dark-text-color: rgb(47.0, 52.0, 57.0); 8 | -fx-text-color: rgb(67.0, 72.0, 77.0); 9 | -fx-light-gray-color: rgb(200.0, 200.0, 200.0); 10 | -fx-lightest-gray-color: rgb(230.0, 230.0, 230.0); 11 | } 12 | 13 | .text { 14 | -fx-font-family: 'Roboto'; 15 | } 16 | 17 | /*.icon-label .text { 18 | -fx-font-family: FontAwesome !important; 19 | } 20 | */ 21 | 22 | .button { 23 | -fx-border-color: null; 24 | -fx-background-color: -fx-lightest-color; 25 | -fx-background-radius: 2px; 26 | -fx-font-size: 14px; 27 | } 28 | 29 | .button .text{ 30 | -fx-fill: white; 31 | } 32 | 33 | .button:hover { 34 | -fx-background-color: -fx-basic-color; 35 | } 36 | 37 | .button:hover .text{ 38 | -fx-fill: white; 39 | } 40 | 41 | .base-toolbar { 42 | -fx-background-color: white; 43 | } 44 | 45 | .container-toolbar { 46 | -fx-min-height: 32px; 47 | -fx-pref-height: 32px; 48 | -fx-max-height: 32px; 49 | -fx-background-color: -fx-lighter-color; 50 | -fx-padding: 2px 2px 2px 12px; 51 | } 52 | 53 | .application-toolbar { 54 | -fx-background-color: -fx-basic-color; 55 | -fx-padding: 4px; 56 | } 57 | 58 | 59 | .application-toolbar:large { 60 | -fx-border-color: -fx-basic-color; 61 | } 62 | 63 | .base-toolbar > .text { 64 | -fx-fill: white; 65 | 66 | } 67 | 68 | .container-toolbar > .text { 69 | -fx-font-size: 16px; 70 | } 71 | 72 | .application-toolbar > .text { 73 | -fx-font-size: 24px; 74 | } 75 | 76 | .application-toolbar:large > .text { 77 | -fx-font-size: 28px; 78 | } 79 | 80 | .base-toolbar > .action-box { 81 | -fx-spacing: 4px; 82 | } 83 | 84 | .base-toolbar > .action-box > .button { 85 | -fx-border-color: null; 86 | -fx-background-color: null; 87 | } 88 | 89 | /* 90 | .base-toolbar > .action-box > .button .text { 91 | -fx-font-family: FontAwesome !important; 92 | -fx-font-size: 22px; 93 | }*/ 94 | 95 | .container-toolbar > .action-box > .button .text { 96 | -fx-font-size: 16px; 97 | -fx-fill: darkslategray; 98 | } 99 | 100 | .application-toolbar > .action-box > .button .text { 101 | -fx-font-size: 22px; 102 | -fx-fill: white !important; 103 | } 104 | 105 | .workbench { 106 | -fx-background-color: white; 107 | } 108 | 109 | .base-container { 110 | -fx-padding: 8px 12px 8px 12px; 111 | -fx-background-insets: 0px, 2px; 112 | -fx-background-color: -fx-lighter-color, white; 113 | -fx-background-radius: 2px, 1px; 114 | } 115 | 116 | .base-container > .base-toolbar { 117 | -fx-background-radius: 2px 2px 0px 0px; 118 | } 119 | 120 | .base-container > .base-toolbar > .action-box > .button .text { 121 | -fx-font-size: 16px; 122 | -fx-fill: white !important; 123 | } 124 | 125 | .base-container > .infoFooterText > .label { 126 | -fx-font-size: 12px; 127 | -fx-text-fill: lightgrey; 128 | -fx-alignment: center; 129 | -fx-padding: 6px 0px 6px 0px; 130 | } 131 | 132 | .base-container-footer-seperator { 133 | -fx-stroke: -fx-lighter-color; 134 | -fx-opacity: 0.6; 135 | -fx-stroke-width: 1px; 136 | -fx-stroke-line-cap: butt; 137 | } 138 | 139 | .form-workbench { 140 | -fx-spacing: 12px; 141 | -fx-fill-width: true; 142 | -fx-padding: 12px; 143 | } 144 | 145 | .workbench-view > .action-footer { 146 | -fx-pref-height: 40px; 147 | -fx-min-height: 40px; 148 | -fx-max-height: 40px; 149 | } 150 | 151 | .workbench-view > .action-footer > .button{ 152 | -fx-background-color: white; 153 | -fx-text-fill: -fx-lighter-color; 154 | -fx-font-size: 16px; 155 | -fx-background-radius: 0px; 156 | -fx-border-color: -fx-lighter-color; 157 | -fx-border-width: 1px 0px 0px 0px; 158 | -fx-border-radius: 0px; 159 | } 160 | 161 | .workbench-view > .action-footer > .not-first-button{ 162 | -fx-border-width: 1px 0px 0px 1px; 163 | } 164 | 165 | .workbench-view > .action-footer > .button:hover{ 166 | -fx-background-color: -fx-lighter-color; 167 | -fx-text-fill: white; 168 | } 169 | 170 | 171 | .workbench-view > .action-footer > .button .icon-label .text{ 172 | -fx-fill: -fx-lighter-color; 173 | } 174 | 175 | .workbench-view > .action-footer > .button .icon-label .text{ 176 | } 177 | 178 | .workbench-view > .action-footer > .button:hover .icon-label .text{ 179 | -fx-fill: white; 180 | } 181 | 182 | .slider-pane-popup { 183 | -fx-background-color: whitesmoke; 184 | -fx-border-color: black; 185 | -fx-border-width: 0px 1px 0px 0px; 186 | -fx-effect: dropshadow(gaussian, #000000dd, 8, 0.4, 0, 0); 187 | } 188 | 189 | #slider-pane-glasspane { 190 | -fx-background-color: #33333388; 191 | } 192 | 193 | 194 | .menu-entry { 195 | -fx-padding: 6px 24px 6px 24px; 196 | } 197 | 198 | .menu-entry:highlighted { 199 | -fx-background-color: -fx-lighter-color; 200 | } 201 | 202 | .menu-entry-text { 203 | -fx-font-size: 16px; 204 | -fx-text-fill: black; 205 | } 206 | 207 | .menu-entry-icon { 208 | -fx-font-size: 20px; 209 | -fx-text-fill: #555555; 210 | -fx-alignment: center; 211 | -fx-text-alignment: center; 212 | -fx-padding: 0px 0px 2px 0px; 213 | } 214 | 215 | /* 216 | .menu-entry-icon .text { 217 | -fx-font-family: FontAwesome !important; 218 | } 219 | */ 220 | 221 | .menu-entry:highlighted .menu-entry-icon { 222 | -fx-text-fill: black; 223 | } 224 | 225 | #application-menu-button { 226 | -fx-border-color: null; 227 | -fx-background-color: null; 228 | -fx-font-size: 22px; 229 | -fx-text-fill: white; 230 | } 231 | 232 | /* 233 | #application-menu-button .text { 234 | -fx-font-family: FontAwesome !important; 235 | }*/ 236 | 237 | .icon-number-popup { 238 | -fx-font-size: 9px; 239 | -fx-text-fill: white; 240 | -fx-background-color: white, red; 241 | -fx-background-insets: 0px, 1.5px; 242 | -fx-background-radius: 16px, 12px; 243 | 244 | -fx-padding: 2px 6px 2px 6px; 245 | } 246 | 247 | .simple-media-cell .round-image-view { 248 | -fx-pref-width: 72px; 249 | -fx-pref-height: 72px; 250 | } 251 | 252 | .simple-media-cell .round-image-view-circle{ 253 | -fx-stroke-width: 1px; 254 | -fx-stroke: -fx-lighter-color; 255 | } 256 | 257 | .simple-media-cell .media-cell-title .text { 258 | -fx-font-size: 16px; 259 | } 260 | 261 | .simple-media-cell .media-cell-description .text { 262 | -fx-font-size: 12px; 263 | -fx-font-style: italic; 264 | -fx-fill: gray; 265 | } 266 | 267 | .simple-media-cell:hover .round-image-view-circle{ 268 | -fx-stroke: white; 269 | } 270 | 271 | .simple-media-cell:hover .media-cell-title .text { 272 | -fx-fill: white; 273 | } 274 | 275 | .simple-media-cell:hover .media-cell-description .text { 276 | -fx-fill: lightgrey; 277 | } 278 | 279 | 280 | .scroll-bar { 281 | -fx-background-color: transparent; 282 | } 283 | 284 | .scroll-bar .decrement-button { 285 | -fx-background-color: transparent; 286 | -fx-border-color: transparent; 287 | } 288 | 289 | .scroll-bar .decrement-arrow { 290 | -fx-background-color: lightgray; 291 | -fx-border-color: transparent; 292 | } 293 | 294 | .scroll-bar .decrement-arrow:hover { 295 | -fx-background-color: -fx-basic-color; 296 | -fx-border-color: transparent; 297 | } 298 | 299 | .scroll-bar .increment-button { 300 | -fx-background-color: transparent; 301 | -fx-border-color: transparent; 302 | } 303 | 304 | .scroll-bar .increment-arrow { 305 | -fx-background-color: lightgray; 306 | -fx-border-color: transparent; 307 | } 308 | 309 | .scroll-bar .increment-arrow:hover { 310 | -fx-background-color: -fx-basic-color; 311 | -fx-border-color: transparent; 312 | } 313 | 314 | .scroll-bar .track { 315 | -fx-background-color: transparent; 316 | } 317 | 318 | .scroll-bar:horizontal .thumb { 319 | -fx-background-insets: 6 0 6 0; 320 | } 321 | 322 | .scroll-bar .thumb { 323 | -fx-border-color: transparent; 324 | -fx-background-color: lightgray; 325 | -fx-background-insets: 0 6 0 6; 326 | } 327 | 328 | .scroll-bar .thumb:hover { 329 | -fx-background-color: -fx-lighter-color; 330 | } 331 | 332 | .scroll-bar .thumb:selected { 333 | -fx-background-color: -fx-lighter-color; 334 | } 335 | 336 | .scroll-bar .thumb:focused { 337 | -fx-background-color: -fx-lighter-color; 338 | } 339 | 340 | .workbench-view > .list-view { 341 | -fx-border-width: 0px; 342 | -fx-background-color: white; 343 | -fx-padding: 0px; 344 | } 345 | 346 | .workbench-view > .list-view .list-cell { 347 | -fx-background-color: white; 348 | -fx-border-color: lightgray; 349 | -fx-border-width: 1px 0px 0px 0px; 350 | -fx-padding: 12px; 351 | } 352 | 353 | .workbench-view > .list-view .list-cell:hover:filled { 354 | -fx-background-color: -fx-lighter-color; 355 | } 356 | 357 | .menu-pane > .menu-media-header { 358 | -fx-padding: 12px 6px 24px 24px; 359 | -fx-background-color: -fx-darker-color; 360 | -fx-border-color: #2e2e2e; 361 | -fx-border-width: 0px 0px 1px 0px; 362 | -fx-spacing: 6px; 363 | } 364 | 365 | .menu-pane > .menu-media-header .round-image-view-circle{ 366 | -fx-stroke: #ffffffcc; 367 | -fx-stroke-width: 1px; 368 | } 369 | 370 | .menu-pane > .menu-media-header .text{ 371 | -fx-fill: white; 372 | } 373 | 374 | .menu-pane > .menu-media-header .media-title .text{ 375 | -fx-font-size: 18px; 376 | } 377 | 378 | .menu-pane > .menu-media-header .media-description { 379 | -fx-max-width: 80000px; 380 | -fx-min-width: 0px; 381 | -fx-pref-width: 0px; 382 | } 383 | 384 | .menu-pane > .menu-media-header .media-description .text{ 385 | -fx-font-size: 10px; 386 | } 387 | 388 | .chat-bubble { 389 | -fx-fill: #2196F3; 390 | -fx-arc-height: 4px; 391 | -fx-arc-width: 4px; 392 | } 393 | 394 | .chat-bubble:me { 395 | -fx-fill: #4CAF50; 396 | } 397 | 398 | .chat-bubble-rect { 399 | -fx-arc-height: 12px; 400 | -fx-arc-width: 12px; 401 | } 402 | 403 | .chat-text { 404 | -fx-text-fill: white; 405 | } 406 | 407 | .chat-cell { 408 | -fx-border-width: 0px !important; 409 | } 410 | 411 | .chat-cell:hover { 412 | -fx-background-color: white !important; 413 | } 414 | 415 | .form-layout { 416 | -fx-padding: 12px; 417 | } 418 | 419 | .form-layout > .form-label { 420 | -fx-font-size: 16px; 421 | -fx-text-fill: -fx-dark-text-color; 422 | } 423 | 424 | .form-header-title { 425 | -fx-font-size: 18px; 426 | } 427 | 428 | .form-header-description { 429 | -fx-font-size: 12px; 430 | } 431 | 432 | .form-header-description .text { 433 | -fx-fill: gray; 434 | } 435 | 436 | .form-action-box { 437 | -fx-spacing: 8; 438 | -fx-alignment: center-right; 439 | -fx-padding: 16px 0px 0px 0px; 440 | } 441 | 442 | .form-action-box > .button{ 443 | -fx-font-size: 16px; 444 | } 445 | 446 | .form-seperator { 447 | -fx-stroke: lightgray; 448 | } 449 | 450 | .scroll-pane { 451 | -fx-background-color: transparent; 452 | -fx-border-width: 0px; 453 | } 454 | 455 | .scroll-pane .viewport { 456 | -fx-background-color: transparent; 457 | } 458 | 459 | .simple-image-view { 460 | -fx-background-color: black; 461 | } 462 | 463 | .overlay { 464 | -fx-padding: 12px; 465 | -fx-background-color: rgba(0, 0, 0, 0.4); 466 | -fx-border-color: rgba(0, 0, 0, 0.2); 467 | -fx-border-width: 1px 0px 0px 0px; 468 | } 469 | 470 | .overlay-content .text{ 471 | -fx-fill: white; 472 | } 473 | 474 | .overlay-title .text { 475 | -fx-font-size: 16px; 476 | } 477 | 478 | .overlay-description .text { 479 | -fx-font-size: 12px; 480 | -fx-font-style: italic; 481 | -fx-fill: white; 482 | } 483 | 484 | .overlay-seperator { 485 | -fx-stroke: rgba(255, 255, 255, 0.6); 486 | -fx-stroke-width: 1px; 487 | -fx-stroke-type: centered; 488 | } 489 | 490 | .toolbar-background-image-view { 491 | -fx-background-color: transparent; 492 | } 493 | 494 | .global-action-button { 495 | -fx-padding: 12px; 496 | } 497 | 498 | .global-action-button-background { 499 | -fx-fill: -fx-lighter-color; 500 | -fx-effect: dropshadow(gaussian, #000000dd, 8, 0.4, 0, 0); 501 | } 502 | 503 | .global-action-button:disabled > .global-action-button-background { 504 | -fx-fill: darkgray; 505 | } 506 | 507 | .global-action-button { 508 | -fx-spacing: 12px; 509 | } 510 | 511 | .global-action-button > .button { 512 | -fx-border-color: null; 513 | -fx-background-color: null; 514 | } 515 | 516 | /* 517 | .global-action-button > .button .text { 518 | -fx-font-family: FontAwesome !important; 519 | -fx-font-size: 36px; 520 | -fx-fill: white !important; 521 | }*/ 522 | 523 | .form-layout .text-field, .form-layout .text-area, .form-layout .combo-box-base, .form-layout .choice-box, .table-view .filler, .table-view .column-header { 524 | -fx-background-color: transparent; 525 | -fx-background-radius: 0; 526 | -fx-border-color: -fx-light-gray-color; 527 | -fx-border-width: 0 0 2 0; 528 | -fx-prompt-text-fill: -fx-lightest-color; 529 | -fx-highlight-fill: -fx-lightest-color; 530 | -fx-font-size: 16px; 531 | -fx-text-fill: -fx-text-color; 532 | } 533 | 534 | .form-layout .text-field:focused, .form-layout .text-area:focused, .form-layout .combo-box-base:focused, .form-layout .choice-box:focused { 535 | -fx-border-color: -fx-lighter-color; 536 | } 537 | 538 | .form-layout .text-field { 539 | -fx-padding: 0.5em 0.5em 0.3em 0.1em; 540 | } 541 | 542 | .table-view { 543 | -fx-table-header-border-color: transparent; 544 | -fx-table-cell-border-color: transparent; 545 | -fx-background-color: transparent; 546 | } 547 | 548 | .workbench-view > .table-view { 549 | -fx-padding: 12px; 550 | } 551 | 552 | .table-view .show-hide-columns-button { 553 | -fx-background-color: transparent; 554 | } 555 | 556 | .table-view .column-header .label, .table-view .filler .label, .table-view .column-drag-header .label { 557 | -fx-alignment: baseline-left; 558 | } 559 | 560 | .table-view .column-header-background { 561 | -fx-background-color: transparent; 562 | } 563 | 564 | .table-row-cell { 565 | -fx-background-color: transparent; 566 | } 567 | 568 | .table-row-cell:hover { 569 | -fx-background-color: -fx-lightest-gray-color; 570 | } 571 | 572 | .table-row-cell:selected { 573 | -fx-background-color: -fx-light-gray-color; 574 | } 575 | 576 | .table-row-cell:selected:hover { 577 | -fx-background-color: -fx-light-gray-color; 578 | } 579 | 580 | .table-row-cell:hover:focused { 581 | -fx-background-color: -fx-lightest-gray-color; 582 | } 583 | 584 | .table-row-cell:selected:focused { 585 | -fx-background-color: -fx-lighter-color; 586 | } 587 | 588 | .table-row-cell:selected:hover:focused { 589 | -fx-background-color: -fx-lighter-color; 590 | } 591 | 592 | .table-cell, .table-cell:even, .table-cell:odd { 593 | -fx-border-color: transparent; 594 | -fx-border-width: 0; 595 | -fx-font-size: 16px; 596 | -fx-text-fill: -fx-text-color; 597 | -fx-padding: 8px 4px 8px 4px; 598 | -fx-wrap-text: true; 599 | } 600 | 601 | .media-table-cell { 602 | -fx-padding: 8px 8px 8px 8px !important; 603 | } -------------------------------------------------------------------------------- /src/Lipi.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Sohan Chowdhury on 9/26/16. 3 | * Website: sohanchy.com 4 | * Email: sifat3d@gmail.com 5 | */ 6 | 7 | import javafx.application.Application; 8 | import javafx.scene.Scene; 9 | import javafx.scene.image.Image; 10 | import javafx.scene.layout.Pane; 11 | import javafx.scene.layout.VBox; 12 | import javafx.scene.text.Font; 13 | import javafx.stage.Stage; 14 | import view.hugo.pane.HostServicesProviderUtil; 15 | import view.wizard.WelcomeWizard; 16 | 17 | import java.io.File; 18 | import java.nio.file.Paths; 19 | 20 | public class Lipi extends Application { 21 | 22 | public Stage primaryStage; 23 | Pane wizPane; 24 | 25 | public static void main(String[] args) { 26 | launch(args); 27 | } 28 | 29 | @Override 30 | public void start(Stage primaryStage) { 31 | 32 | this.primaryStage = primaryStage; 33 | 34 | readyGui(); 35 | readyWizard(); 36 | 37 | primaryStage.show(); 38 | } 39 | 40 | private void readyGui() { 41 | 42 | //Must do this for opening browser; 43 | HostServicesProviderUtil.INSTANCE.init(getHostServices()); 44 | 45 | //Load font 46 | File f = new File("kalpurush.ttf"); 47 | try { 48 | Font.loadFont(f.getCanonicalPath(), 10); 49 | } catch (Exception e) { 50 | System.out.println(e.getMessage()); 51 | e.printStackTrace(); 52 | } 53 | 54 | wizPane = new VBox(); 55 | 56 | wizPane.getStylesheets().add(Paths.get("res/material.css").toAbsolutePath().toUri().toString()); 57 | wizPane.getStylesheets().add(Paths.get("res/custom.css").toAbsolutePath().toUri().toString()); 58 | 59 | primaryStage.getIcons().add( 60 | new Image(Paths.get("res/lipi-icon.png").toAbsolutePath().toUri().toString()) 61 | ); 62 | } 63 | 64 | public void readyWizard() { 65 | 66 | primaryStage.setTitle("Lipi"); 67 | 68 | WelcomeWizard welcome = new WelcomeWizard(primaryStage); 69 | 70 | wizPane.getChildren().add(welcome); 71 | 72 | primaryStage.setScene(new Scene(wizPane)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Lipi 3 | 4 | -------------------------------------------------------------------------------- /src/model/hugo/HMDFileCreator.java: -------------------------------------------------------------------------------- 1 | package model.hugo; 2 | 3 | import view.utils.ExceptionAlerter; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Calendar; 9 | 10 | /** 11 | * Created by Sohan Chowdhury on 8/26/16. 12 | * Website: sohanchy.com 13 | * Email: sifat3d@gmail.com 14 | */ 15 | public class HMDFileCreator { 16 | 17 | private HMDFileProcessor HMDFileProcessor; 18 | private File file; 19 | 20 | public HMDFileCreator(String filePath) { 21 | 22 | file = new File(filePath); 23 | try { 24 | file.createNewFile(); 25 | HMDFileProcessor = new HMDFileProcessor(filePath); 26 | } catch (IOException e) { 27 | ExceptionAlerter.showException(e); 28 | System.exit(0); 29 | } 30 | 31 | } 32 | 33 | public void setupFile() { 34 | setupFile("Hello Internet!", "This is a simple empty blog post.", ""); 35 | } 36 | 37 | public void setupFile(String title, String description, String postContent) { 38 | buildBasicFrontMatter(title, description); 39 | this.HMDFileProcessor.setPostContent(postContent); 40 | } 41 | 42 | private void buildBasicFrontMatter(String title, String description) { 43 | StringBuilder basicFrontMatter = new StringBuilder(); 44 | 45 | basicFrontMatter.append("title = \"").append(title).append("\"\n"); 46 | basicFrontMatter.append("description = \"").append(description).append("\"\n"); 47 | 48 | String timeStamp = new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime()); 49 | basicFrontMatter.append("lastmod = \"").append(timeStamp).append("\"\n"); 50 | basicFrontMatter.append("date = \"").append(timeStamp).append("\"\n"); 51 | 52 | basicFrontMatter.append("tags = [ \"Untagged\" ] \n"); 53 | 54 | this.HMDFileProcessor.setFrontMatter(basicFrontMatter.toString()); 55 | } 56 | 57 | public void setupAndMakeFile(String title, String description, String postContent) { 58 | setupFile(title, description, postContent); 59 | makeFile(); 60 | } 61 | 62 | public void makeFile() { 63 | HMDFileProcessor.writeHMdFile(true); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/model/hugo/HMDFileProcessor.java: -------------------------------------------------------------------------------- 1 | package model.hugo; 2 | 3 | import model.toml.TomlUtils; 4 | import model.utility.FileHandler; 5 | 6 | import java.io.*; 7 | import java.nio.charset.StandardCharsets; 8 | 9 | public class HMDFileProcessor { 10 | private String frontMatter, postContent; 11 | private String filePath; 12 | private File mdFile; 13 | private boolean validMd; 14 | 15 | public HMDFileProcessor(String filePath) { 16 | this.filePath = filePath; 17 | setupFile(); 18 | } 19 | 20 | public String getFileName() { 21 | return mdFile.getName(); 22 | } 23 | 24 | public File getFile() { 25 | return mdFile; 26 | } 27 | 28 | public boolean isValidMd() { 29 | return validMd; 30 | } 31 | 32 | private void setupFile() { 33 | this.mdFile = new File(filePath); 34 | } 35 | 36 | public String getFrontMatter() { 37 | return frontMatter; 38 | } 39 | 40 | public void setFrontMatter(String frontMatter) { 41 | this.frontMatter = frontMatter.trim() + "\n"; 42 | } 43 | 44 | public String getPostContent() { 45 | return postContent; 46 | } 47 | 48 | public void setPostContent(String postContent) { 49 | this.postContent = postContent.trim() + "\n"; 50 | } 51 | 52 | public boolean readHMdFile() { 53 | 54 | try { 55 | BufferedReader br = new BufferedReader( 56 | new InputStreamReader( 57 | new FileInputStream(mdFile), StandardCharsets.UTF_8)); 58 | 59 | String line = br.readLine(); 60 | 61 | boolean foundTomlIdentifier = false; 62 | for (int i = 0; i < 3 && line != null; i++) { 63 | 64 | //try first 3 lines 65 | if (line.contains(TomlUtils.TOML_IDENTIFIER)) { 66 | foundTomlIdentifier = true; 67 | break; 68 | } 69 | 70 | line = br.readLine(); 71 | } 72 | if (foundTomlIdentifier == false || line == null) { 73 | throw new IOException("No toml front matter found, Invalid or Empty Hugo Markdown file." + filePath); 74 | } 75 | 76 | frontMatter = postContent = ""; 77 | for (line = br.readLine(); 78 | line != null && !line.contains(TomlUtils.TOML_IDENTIFIER); 79 | line = br.readLine()) { 80 | 81 | frontMatter += (line + "\n"); 82 | } 83 | 84 | frontMatter = frontMatter.trim() + "\n"; 85 | 86 | if (frontMatter.isEmpty()) { 87 | throw new Exception("toml is empty"); 88 | } 89 | 90 | for (line = br.readLine(); 91 | line != null; 92 | line = br.readLine()) { 93 | 94 | postContent += (line + "\n"); 95 | } 96 | 97 | postContent = postContent.trim() + "\n"; 98 | 99 | validMd = true; 100 | return true; 101 | 102 | } catch (IOException e) { 103 | validMd = false; 104 | System.out.println("IOException: " + e.getMessage()); 105 | e.printStackTrace(); 106 | setNull(); 107 | return false; 108 | } catch (Exception e) { 109 | validMd = false; 110 | System.out.println("Some Exception in file: " + filePath + "\n" + e.getMessage()); 111 | e.printStackTrace(); 112 | setNull(); 113 | return false; 114 | } 115 | 116 | 117 | } 118 | 119 | private void setNull() { 120 | frontMatter = postContent = null; 121 | } 122 | 123 | public boolean writeHMdFile(boolean force) { 124 | String combinedMdText = TomlUtils.TOML_IDENTIFIER + "\n" 125 | + frontMatter + TomlUtils.TOML_IDENTIFIER + "\n \n" 126 | + postContent; 127 | 128 | try { 129 | FileHandler.writeFile(combinedMdText, mdFile); 130 | return true; 131 | } catch (IOException e) { 132 | e.printStackTrace(); 133 | return false; 134 | } 135 | } 136 | 137 | public boolean writeHMdFile() { 138 | 139 | try { 140 | if (validMd) { 141 | return writeHMdFile(true); 142 | } else { 143 | throw new Exception("Not valid HMd File."); 144 | } 145 | } catch (Exception e) { 146 | System.out.println(e.getMessage()); 147 | e.printStackTrace(); 148 | } 149 | 150 | return false; 151 | } 152 | 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/model/hugo/Hugo.java: -------------------------------------------------------------------------------- 1 | package model.hugo; 2 | 3 | import model.utility.CallbackVisitor; 4 | import model.utility.Ipc; 5 | import org.apache.commons.io.FileUtils; 6 | 7 | import java.io.File; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | public class Hugo { 13 | private final static String[] paramServer = {"server"}; 14 | private final static String[] paramNewSite = {"new", "site"}; 15 | private final Ipc hugoIpc; 16 | private final String srcDir; 17 | private String pubDir; 18 | private List params; 19 | private Thread serverThread; 20 | 21 | public Hugo(String srcDir) { 22 | this.srcDir = srcDir; 23 | pubDir = srcDir + File.separator + "public"; 24 | // System.out.println(pubDir); 25 | hugoIpc = new Ipc("exec" + File.separator + "hugo"); 26 | } 27 | 28 | public String getSrcDir() { 29 | return srcDir; 30 | } 31 | 32 | public String getPubDir() { 33 | return pubDir; 34 | } 35 | 36 | public void setPubDir(String pubDir) { 37 | this.pubDir = pubDir; 38 | } 39 | 40 | public void hugoMakeSite(String blogName) { 41 | params = new ArrayList(); 42 | params.addAll(Arrays.asList(paramNewSite)); 43 | params.add(blogName); 44 | 45 | hugoIpc.setProgArgs(params); 46 | hugoIpc.runProc(); 47 | hugoIpc.showOutput(); 48 | 49 | } 50 | 51 | protected void hugoBuild() { 52 | params = new ArrayList(); 53 | params.add("--source"); 54 | params.add(srcDir); 55 | params.add("--destination"); 56 | params.add(pubDir); 57 | 58 | try { 59 | FileUtils.deleteDirectory(new File(pubDir)); 60 | } catch (Exception e) { 61 | System.out.println(e.getMessage() + "Maybe no previous public folder exists."); 62 | } 63 | 64 | hugoIpc.setProgArgs(params); 65 | hugoIpc.runProc(); 66 | hugoIpc.showOutput(); 67 | } 68 | 69 | //do not call this without a separate thread 70 | private void runHugoServer(CallbackVisitor callback) { 71 | 72 | System.out.println("Server src: " + srcDir); 73 | 74 | params = new ArrayList(); 75 | params.add("server"); 76 | 77 | params.add("--source"); 78 | params.add(srcDir); 79 | 80 | hugoIpc.setProgArgs(params); 81 | hugoIpc.runProc(); 82 | hugoIpc.showOutput(); 83 | callback.call(); 84 | } 85 | 86 | public void runHugoBuild(CallbackVisitor callBack) { 87 | HugoThread hugoBuilderThread = new HugoThread(this) { 88 | public void run() { 89 | hugo.hugoBuild(); 90 | } 91 | }; 92 | hugoBuilderThread.start(); 93 | callBack.call(); 94 | } 95 | 96 | public boolean startHugoServer(CallbackVisitor callback) { 97 | if (serverThread == null) { 98 | serverThread = new HugoThread(this) { 99 | public void run() { 100 | hugo.runHugoServer(callback); 101 | } 102 | }; 103 | 104 | serverThread.start(); 105 | return true; 106 | } 107 | return false; 108 | } 109 | 110 | public boolean isServerAlive() { 111 | return (serverThread.getState() != Thread.State.TERMINATED); 112 | } 113 | 114 | public boolean stopHugoServer() { 115 | if (serverThread != null) { 116 | hugoIpc.destroy(); 117 | serverThread = null; 118 | return true; 119 | } 120 | 121 | return false; 122 | } 123 | 124 | public String getHugoOut() { 125 | return hugoIpc.stdOut; 126 | } 127 | 128 | private abstract class HugoThread extends Thread { 129 | public final Hugo hugo; 130 | 131 | private HugoThread(Hugo hugo) { 132 | this.hugo = hugo; 133 | // this.setDaemon(true); 134 | } 135 | 136 | public abstract void run(); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/model/toml/TomlConfig.java: -------------------------------------------------------------------------------- 1 | package model.toml; 2 | 3 | import model.utility.FileHandler; 4 | import view.utils.ExceptionAlerter; 5 | 6 | import java.io.IOException; 7 | import java.util.Map; 8 | 9 | public class TomlConfig implements TomlParser { 10 | private String filepath; 11 | private Map tomlMap; 12 | 13 | public TomlConfig() { 14 | } 15 | 16 | public TomlConfig(String filepath) { 17 | setTomlFile(filepath); 18 | } 19 | 20 | public void setTomlFile(String filepath) { 21 | this.filepath = filepath; 22 | readTomlMap(); 23 | } 24 | 25 | public Map getTomlMap() { 26 | return tomlMap; 27 | } 28 | 29 | public void setTomlMap(Map tomlMap) { 30 | this.tomlMap = tomlMap; 31 | } 32 | 33 | public void readTomlMap() { 34 | try { 35 | tomlMap = TomlUtils.readToml(FileHandler.readFile(filepath)); 36 | } catch (IOException e) { 37 | ExceptionAlerter.showException(e); 38 | } 39 | } 40 | 41 | public void writeTomlMap() { 42 | try { 43 | FileHandler.writeFile(TomlUtils.toToml(tomlMap), filepath); 44 | } catch (IOException e) { 45 | e.printStackTrace(); 46 | System.out.println(e.getMessage()); 47 | } 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return TomlUtils.toToml(tomlMap); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/model/toml/TomlParser.java: -------------------------------------------------------------------------------- 1 | package model.toml; 2 | 3 | import java.util.Map; 4 | 5 | public interface TomlParser { 6 | Map getTomlMap(); 7 | 8 | void setTomlMap(Map tomlMap); 9 | 10 | void readTomlMap(); 11 | 12 | void writeTomlMap(); 13 | 14 | String toString(); 15 | } 16 | -------------------------------------------------------------------------------- /src/model/toml/TomlString.java: -------------------------------------------------------------------------------- 1 | package model.toml; 2 | 3 | import java.util.Map; 4 | 5 | public class TomlString implements TomlParser { 6 | private String tomlString; 7 | private Map tomlMap; 8 | 9 | public TomlString() { 10 | } 11 | public TomlString(String toml) { 12 | setTomlString(toml); 13 | } 14 | 15 | public void setTomlString(String toml) { 16 | this.tomlString = toml; 17 | readTomlMap(); 18 | } 19 | 20 | public Map getTomlMap() { 21 | return tomlMap; 22 | } 23 | 24 | public void setTomlMap(Map tomlMap) { 25 | this.tomlMap = tomlMap; 26 | writeTomlMap(); 27 | } 28 | 29 | public void readTomlMap() { 30 | tomlMap = TomlUtils.readToml(tomlString); 31 | } 32 | 33 | public void writeTomlMap() { 34 | tomlString = TomlUtils.toToml(tomlMap); 35 | } 36 | 37 | 38 | @Override 39 | public String toString() { 40 | return tomlString; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/model/toml/TomlUtils.java: -------------------------------------------------------------------------------- 1 | package model.toml; 2 | 3 | import com.moandjiezana.toml.Toml; 4 | import com.moandjiezana.toml.TomlWriter; 5 | 6 | import java.util.Map; 7 | 8 | public abstract class TomlUtils { 9 | 10 | public static final String TOML_IDENTIFIER = "+++"; 11 | 12 | public static Map readToml(String toml) { 13 | return new Toml().read(toml).toMap(); 14 | } 15 | 16 | public static String toToml(Map tomlMap) { 17 | TomlWriter tomlWriter = new TomlWriter(); 18 | return tomlWriter.write(tomlMap); 19 | } 20 | 21 | public static String toToml(Object from) { 22 | TomlWriter tomlWriter = new TomlWriter(); 23 | return tomlWriter.write(from); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/model/utility/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | GroupedSorting=true 3 | SortRole=type 4 | Timestamp=2016,8,6,13,4,30 5 | Version=3 6 | ViewMode=1 7 | VisibleRoles=Details_text,Details_size,Details_date,Details_type,CustomizedDetails 8 | -------------------------------------------------------------------------------- /src/model/utility/CallbackVisitor.java: -------------------------------------------------------------------------------- 1 | package model.utility; 2 | 3 | /** 4 | * Created by Sohan Chowdhury on 8/25/16. 5 | * Website: sohanchy.com 6 | * Email: sifat3d@gmail.com 7 | */ 8 | public interface CallbackVisitor { 9 | void call(); 10 | } 11 | -------------------------------------------------------------------------------- /src/model/utility/FileHandler.java: -------------------------------------------------------------------------------- 1 | package model.utility; 2 | 3 | import java.io.*; 4 | import java.nio.charset.Charset; 5 | import java.nio.charset.StandardCharsets; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | 9 | public class FileHandler { 10 | 11 | private FileHandler() { 12 | //FULLY STATIC CLASS 13 | } 14 | 15 | public static String readFile(String path, Charset encoding) throws IOException { 16 | byte[] encoded; 17 | encoded = Files.readAllBytes(Paths.get(path)); 18 | 19 | assert encoded != null; 20 | return new String(encoded, encoding); 21 | } 22 | 23 | public static String readFile(String path) throws IOException { 24 | 25 | return readFile(path, StandardCharsets.UTF_8); 26 | } 27 | 28 | public static boolean makeDir(String path) { 29 | return new File(path).mkdir(); 30 | } 31 | 32 | public static void writeFile(String textString, File f, Charset encoding) 33 | throws IOException { 34 | 35 | try (Writer fWriter = new BufferedWriter(new OutputStreamWriter( 36 | new FileOutputStream(f), encoding))) { 37 | fWriter.write(textString); 38 | } 39 | } 40 | 41 | public static void writeFile(String textString, File f) 42 | throws IOException { 43 | //System.out.println(f.getCanonicalPath()); 44 | writeFile(textString, f, StandardCharsets.UTF_8); 45 | } 46 | 47 | public static void writeFile(String textString, String filepath) 48 | throws IOException { 49 | File f = new File(filepath); 50 | writeFile(textString, f, StandardCharsets.UTF_8); 51 | } 52 | 53 | public static File stringToTempFile(String textString) { 54 | File f = null; 55 | try { 56 | f = getExpiringTempFile(); 57 | 58 | writeFile(textString, f); 59 | 60 | //System.out.println(textString); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | return f; 65 | } 66 | 67 | public static File getExpiringTempFile() { 68 | 69 | File f = null; 70 | 71 | try { 72 | f = File.createTempFile("JavaFX_pd_", ".tmp"); 73 | f.deleteOnExit(); 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | } 77 | 78 | return f; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/model/utility/Ipc.java: -------------------------------------------------------------------------------- 1 | package model.utility; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.InputStreamReader; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | //Give executable filename, add optional arguments/commands 10 | //Call runProc() 11 | public class Ipc { 12 | public String stdOut, stdErr; 13 | private String progName, execLoc; 14 | private List command; 15 | private Process proc; 16 | private boolean isDestroyed; 17 | 18 | public Ipc(String progName) { 19 | 20 | setProgName(progName); 21 | } 22 | 23 | public void setProgName(String progName) { 24 | 25 | this.progName = progName; 26 | setProgArgs(); 27 | setExecLoc(); 28 | } 29 | 30 | public void setProgArgs() { 31 | 32 | command = new ArrayList(); 33 | command.add(execLoc); 34 | } 35 | 36 | public void setProgArgs(List args) { 37 | 38 | setProgArgs(); 39 | //Converts Space separated args to list then add to end of command 40 | command.addAll(args); 41 | } 42 | 43 | private void setExecLoc() { 44 | 45 | execLoc = System.getProperty("user.dir") + "/" + progName; 46 | 47 | //Check for executable file and adjust 48 | File f = new File(execLoc); 49 | 50 | if (!f.exists() || f.isDirectory()) { 51 | // System.out.println("Maybe its Windows?"); 52 | execLoc = execLoc + ".exe"; 53 | 54 | if (!f.exists() || f.isDirectory()) { 55 | System.out.println("File not found at all"); 56 | } 57 | 58 | } else { 59 | //System.out.println("File found,Assuming Linux"); 60 | } 61 | 62 | } 63 | 64 | public void runProc() { 65 | 66 | try { 67 | isDestroyed = false; 68 | proc = new ProcessBuilder().command(command).redirectErrorStream(true).start(); 69 | saveOutput(); 70 | proc.waitFor(); 71 | } catch (Exception e) { 72 | isDestroyed = true; 73 | e.printStackTrace(); 74 | } 75 | 76 | } 77 | 78 | public void showOutput() { 79 | 80 | System.out.println("Here is the standard output of the command:\n" 81 | + stdOut); 82 | 83 | System.out.println("Here is the standard error of the command (if any):\n" 84 | + stdErr); 85 | 86 | } 87 | 88 | public void saveOutput() { 89 | stdOut = stdErr = "_"; 90 | try { 91 | BufferedReader stdInput = new BufferedReader(new 92 | InputStreamReader(proc.getInputStream())); 93 | 94 | BufferedReader stdError = new BufferedReader(new 95 | InputStreamReader(proc.getErrorStream())); 96 | 97 | String strTmp; 98 | // read the output from the command 99 | while ((strTmp = stdInput.readLine()) != null) { 100 | stdOut += ("_" + strTmp + "\n"); 101 | 102 | if (isDestroyed) { 103 | break; 104 | } 105 | } 106 | 107 | // read any errors from the attempted command 108 | if (!isDestroyed) { 109 | while ((strTmp = stdError.readLine()) != null) { 110 | stdErr += ("_" + strTmp + "\n"); 111 | 112 | if (isDestroyed) { 113 | break; 114 | } 115 | } 116 | } 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | } 120 | 121 | } 122 | 123 | public void destroy() { 124 | isDestroyed = true; 125 | proc.destroy(); 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/model/utility/MarkdownFileUtils.java: -------------------------------------------------------------------------------- 1 | package model.utility; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.io.IOException; 6 | 7 | /** 8 | * Created by Sohan Chowdhury on 8/27/16. 9 | * Website: sohanchy.com 10 | * Email: sifat3d@gmail.com 11 | */ 12 | public class MarkdownFileUtils { 13 | public static FilenameFilter getMdFileFilter() { 14 | return new FilenameFilter() { 15 | public boolean accept(File dir, String name) { 16 | 17 | try { 18 | File f = new File(dir.getCanonicalPath() + File.separator + name); 19 | 20 | if (f.isDirectory()) { 21 | return true; 22 | } else { 23 | return name.toLowerCase().endsWith(".md"); 24 | } 25 | } catch (IOException e) { 26 | System.out.println(e.getMessage()); 27 | e.printStackTrace(); 28 | return false; 29 | } 30 | } 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/model/utility/Pandoc.java: -------------------------------------------------------------------------------- 1 | package model.utility; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | public class Pandoc { 9 | 10 | private final static String[] paramHTMLtoMD = {"-f", "html", "-t", "markdown_github-raw_html-native_divs-native_spans"}; 11 | private final static String[] paramMDtoHTML = {"-f", "markdown_github", "-t", "html"}; 12 | private final Ipc pandoc; 13 | private List params; 14 | 15 | public Pandoc() { 16 | pandoc = new Ipc("exec" + File.separator + "pandoc"); 17 | 18 | } 19 | 20 | public String htmlToMd(String html) { 21 | 22 | String md = null; 23 | try { 24 | String outFile = FileHandler.getExpiringTempFile().getCanonicalPath(); 25 | 26 | htmlToMdFile(html, outFile); 27 | 28 | md = FileHandler.readFile(outFile); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | 33 | return md; 34 | } 35 | 36 | public String mdToHtml(String md) { 37 | 38 | String html = null; 39 | try { 40 | String outFile = FileHandler.getExpiringTempFile().getCanonicalPath(); 41 | 42 | mdToHtmlFile(md, outFile); 43 | 44 | html = FileHandler.readFile(outFile); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | return html; 49 | } 50 | 51 | private boolean htmlToMdFile(String html, String outFile) { 52 | 53 | try { 54 | File tmpHtml = FileHandler.stringToTempFile(html); 55 | 56 | params = new ArrayList(); 57 | params.addAll(Arrays.asList(paramHTMLtoMD)); 58 | 59 | //System.out.println(tmpHtml.getCanonicalPath()); 60 | 61 | params.add(tmpHtml.getCanonicalPath()); 62 | params.add("-o"); 63 | params.add(outFile); 64 | 65 | pandoc.setProgArgs(params); 66 | 67 | pandoc.runProc(); 68 | 69 | return true; 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | 74 | return false; 75 | } 76 | 77 | private boolean mdToHtmlFile(String md, String outFile) { 78 | 79 | try { 80 | File tmpMd = FileHandler.stringToTempFile(md); 81 | 82 | params = new ArrayList(); 83 | params.addAll(Arrays.asList(paramMDtoHTML)); 84 | 85 | //System.out.println(tmpHtml.getCanonicalPath()); 86 | 87 | params.add(tmpMd.getCanonicalPath()); 88 | params.add("-o"); 89 | params.add(outFile); 90 | 91 | pandoc.setProgArgs(params); 92 | 93 | pandoc.runProc(); 94 | 95 | return true; 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | } 99 | 100 | return false; 101 | 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/tests/RunTests.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import model.hugo.HMDFileProcessor; 4 | import model.hugo.Hugo; 5 | import model.toml.TomlUtils; 6 | import model.utility.CallbackVisitor; 7 | import model.utility.FileHandler; 8 | import model.utility.Ipc; 9 | import model.utility.Pandoc; 10 | 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | class RunTests { 16 | private static final String testsFolder = "tests-res"; 17 | 18 | public static void main(String[] args) { 19 | 20 | System.out.println("This is the class to run tests on features."); 21 | 22 | testHugo(); 23 | testHMdFileProcessor(); 24 | // 25 | testTomlParser(); 26 | } 27 | 28 | private static void testTomlParser() { 29 | String inp; 30 | /* 31 | inp = testsFolder + "/tomlParserTest.md"; 32 | HMDFileProcessor mdObject = new HMDFileProcessor(inp); 33 | mdObject.readHMdFile(); 34 | 35 | System.out.println(TomlUtils.readToml(mdObject.getFrontMatter()));*/ 36 | 37 | inp = testsFolder + "/tomlConfigTest.toml"; 38 | 39 | try { 40 | System.out.println(TomlUtils.toToml(TomlUtils.readToml(FileHandler.readFile(inp)))); 41 | } catch (IOException e) { 42 | System.out.println(e.getMessage()); 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | private static void testHugo() { 48 | 49 | Hugo testing = new Hugo("/home/sohan/Sandbox/Java/blog"); 50 | testing.startHugoServer(new CallbackVisitor() { 51 | @Override 52 | public void call() { 53 | System.out.println("Ended"); 54 | } 55 | }); 56 | 57 | try { 58 | Thread.sleep(2000); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | 63 | System.out.println("Slept 3000 ms"); 64 | testing.stopHugoServer(); 65 | 66 | //System.out.println(testing.getHugoOut()); 67 | } 68 | 69 | 70 | private static void testHMdFileProcessor() { 71 | 72 | HMDFileProcessor mdObject = new HMDFileProcessor(testsFolder + "/test.md"); 73 | 74 | 75 | mdObject.readHMdFile(); 76 | //mdObject.setPostContent((mdObject.getPostContent() + "-----TEST-----")); 77 | 78 | mdObject.writeHMdFile(); 79 | 80 | System.out.println(mdObject.getFrontMatter()); 81 | System.out.println(mdObject.getPostContent()); 82 | 83 | } 84 | 85 | public static void testIpc() { 86 | 87 | Ipc pandoc = new Ipc("pandoc"); 88 | 89 | List params = new ArrayList(); 90 | 91 | params.add("test.html"); 92 | params.add("-o"); 93 | params.add("test.md"); 94 | 95 | pandoc.setProgArgs(params); 96 | 97 | pandoc.runProc(); 98 | } 99 | 100 | public static void testPandoc() { 101 | Pandoc PandocParser = new Pandoc(); 102 | 103 | //System.out.println( PandocParser.htmlToMd( FileHandler.readFile("test.html") ) ); 104 | try { 105 | System.out.println(PandocParser.htmlToMd(FileHandler.readFile(testsFolder + "/test.html"))); 106 | } catch (IOException e) { 107 | System.out.println(e.getMessage()); 108 | e.printStackTrace(); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/tests/RunTestsJavaFX.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import javafx.application.Application; 4 | import javafx.event.ActionEvent; 5 | import javafx.event.EventHandler; 6 | import javafx.scene.Scene; 7 | import javafx.scene.control.Button; 8 | import javafx.scene.control.ScrollPane; 9 | import javafx.scene.layout.Pane; 10 | import javafx.scene.layout.VBox; 11 | import javafx.scene.text.Font; 12 | import javafx.scene.text.Text; 13 | import javafx.stage.Stage; 14 | import model.hugo.HMDFileProcessor; 15 | import model.utility.FileHandler; 16 | import view.dashboard.DashboardMain; 17 | import view.filetree.FileTreeTable; 18 | import view.hugo.hmd.TabbedHMDPostEditor; 19 | import view.hugo.markdown.MarkdownEditorControl; 20 | import view.hugo.pane.HostServicesProviderUtil; 21 | import view.hugo.pane.HugoPane; 22 | import view.toml.TomlConfigEditor; 23 | import view.toml.TomlEditorControl; 24 | import view.utils.ExceptionAlerter; 25 | import view.wizard.WelcomeWizard; 26 | 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.nio.file.Paths; 30 | 31 | public class RunTestsJavaFX extends Application { 32 | private static final String testsFolder = "tests-res"; 33 | private static final String testsBlog = testsFolder + File.separator + "blog"; 34 | 35 | String inp; 36 | Stage primaryStage, editorStage; 37 | Pane pane; 38 | TabbedHMDPostEditor tabbedHMDPostEditor; 39 | 40 | public static void main(String[] args) { 41 | launch(args); 42 | } 43 | 44 | private void readyGui(Stage primaryStage) { 45 | this.primaryStage = primaryStage; 46 | editorStage = new Stage(); 47 | 48 | tabbedHMDPostEditor = new TabbedHMDPostEditor(editorStage); 49 | editorStage.setScene(new Scene(tabbedHMDPostEditor)); 50 | 51 | primaryStage.setTitle("Main Application"); 52 | editorStage.setTitle("Hugo Markdown Editor"); 53 | //Must do this for opening browser; 54 | HostServicesProviderUtil.INSTANCE.init(getHostServices()); 55 | 56 | pane = new VBox(); 57 | 58 | File f = new File("kalpurush.ttf"); 59 | try { 60 | Font.loadFont(f.getCanonicalPath(), 10); 61 | } catch (Exception e) { 62 | System.out.println(e.getMessage()); 63 | e.printStackTrace(); 64 | } 65 | 66 | pane.getStylesheets().add(Paths.get("res/material.css").toAbsolutePath().toUri().toString()); 67 | pane.getStylesheets().add(Paths.get("res/custom.css").toAbsolutePath().toUri().toString()); 68 | // 69 | 70 | primaryStage.setScene(new Scene(pane)); 71 | } 72 | 73 | @Override 74 | public void start(Stage primaryStage) throws Exception { 75 | readyGui(primaryStage); 76 | 77 | 78 | // testTomlEditor(); 79 | // testMdEditor(); 80 | // testHMdPostEditor(); 81 | // testFileTreeControl(); 82 | // testHugoPane(); 83 | // testTabbedHMdPostEditor(); 84 | // testTomlConfigEditor(); 85 | testDashboardMain(); 86 | // 87 | // wizard(); 88 | 89 | primaryStage.show(); 90 | } 91 | 92 | public void testTomlEditor() { 93 | //inp = testsFolder + "/tomlConfigTest.toml"; 94 | inp = testsFolder + "/tomlConfigTest.toml"; 95 | 96 | HMDFileProcessor mdObject = new HMDFileProcessor(testsFolder + "/test.md"); 97 | mdObject.readHMdFile(); 98 | 99 | 100 | // TomlParser tomlParser = new TomlString(mdObject.getFrontMatter()); 101 | 102 | String tomlString; 103 | try { 104 | tomlString = FileHandler.readFile(inp); 105 | 106 | 107 | TomlEditorControl tomlEditor = new TomlEditorControl(tomlString); 108 | 109 | Button print = new Button("print"); 110 | print.setOnAction(new EventHandler() { 111 | @Override 112 | public void handle(ActionEvent event) { 113 | mdObject.setFrontMatter(tomlEditor.getTomlString()); 114 | System.out.println(mdObject.getFrontMatter()); 115 | } 116 | }); 117 | 118 | tomlEditor.getChildren().add(print); 119 | 120 | ScrollPane sp = new ScrollPane(tomlEditor); 121 | sp.setFitToHeight(true); 122 | 123 | pane.getChildren().add(sp); 124 | 125 | primaryStage.setTitle("Toml Editor"); 126 | 127 | } catch (IOException e) { 128 | ExceptionAlerter.showException(e); 129 | } 130 | } 131 | 132 | public void testMdEditor() { 133 | 134 | MarkdownEditorControl mdEditor = new MarkdownEditorControl(); 135 | 136 | pane.getChildren().add(new Pane(mdEditor)); 137 | 138 | primaryStage.setTitle("Markdown Editor"); 139 | } 140 | 141 | // public void testHMdPostEditor() { 142 | // 143 | // HMDFileProcessor mdObject = new HMDFileProcessor(testsFolder + "/test.md"); 144 | // mdObject.readHMdFile(); 145 | // HMDPostEditorControl hMDEditor = new HMDPostEditorControl(mdObject,); 146 | // TabPane p = new TabPane(); 147 | // p.getTabs().add(0, new Tab(hMDEditor.getFileName(), hMDEditor)); 148 | // 149 | // mdObject = new HMDFileProcessor(testsFolder + "/tomlParserTest.md"); 150 | // mdObject.readHMdFile(); 151 | // hMDEditor = new HMDPostEditorControl(mdObject,testsFolder); 152 | // p.getTabs().add(1, new Tab(hMDEditor.getFileName(), hMDEditor)); 153 | // 154 | // pane.getChildren().add(p); 155 | // 156 | // primaryStage.setTitle("Post Editor"); 157 | // } 158 | 159 | public void testFileTreeControl() { 160 | 161 | primaryStage.setTitle("FileTreeControl"); 162 | 163 | FileTreeTable ft = new FileTreeTable(testsBlog, tabbedHMDPostEditor); 164 | 165 | Text txt = new Text("TEst teST স্ট্য্যাকওভারফ্লোর প্রোগ্রামিং"); 166 | 167 | pane.getChildren().addAll(ft, txt); 168 | 169 | // ft.setFitToHeight(true); 170 | } 171 | 172 | public void testHugoPane() { 173 | 174 | primaryStage.setTitle("HugoPane"); 175 | 176 | HugoPane hp = new HugoPane(); 177 | hp.setup(testsBlog, tabbedHMDPostEditor); 178 | 179 | pane.getChildren().addAll(hp); 180 | 181 | // ft.setFitToHeight(true); 182 | } 183 | 184 | public void testTabbedHMdPostEditor() { 185 | HMDFileProcessor mdObject = new HMDFileProcessor(testsFolder + "/test.md"); 186 | tabbedHMDPostEditor.addTab(mdObject); 187 | 188 | } 189 | 190 | 191 | public void testTomlConfigEditor() { 192 | inp = testsFolder + "/tomlConfigTest.toml"; 193 | 194 | TomlConfigEditor tomlEditor = new TomlConfigEditor(inp); 195 | pane.getChildren().add(tomlEditor); 196 | 197 | 198 | } 199 | 200 | public void testDashboardMain() { 201 | 202 | primaryStage.setTitle("Blog Dashboard - Lipi"); 203 | 204 | String blogFolder = "/media/sohan/Mediabox/Downloads/blog/"; 205 | 206 | DashboardMain mainDashboard = new DashboardMain(blogFolder, tabbedHMDPostEditor); 207 | 208 | pane.getChildren().add(mainDashboard); 209 | 210 | } 211 | 212 | 213 | public void wizard() { 214 | 215 | primaryStage.setTitle("Lipi"); 216 | 217 | WelcomeWizard welcome = new WelcomeWizard(primaryStage); 218 | 219 | pane.getChildren().add(welcome); 220 | 221 | } 222 | 223 | } -------------------------------------------------------------------------------- /src/view/dashboard/DashboardMain.java: -------------------------------------------------------------------------------- 1 | package view.dashboard; 2 | 3 | import javafx.fxml.FXML; 4 | import javafx.fxml.FXMLLoader; 5 | import javafx.scene.layout.BorderPane; 6 | import view.filetree.FileTreeTable; 7 | import view.hugo.hmd.TabbedHMDPostEditor; 8 | import view.hugo.pane.HugoPane; 9 | import view.utils.ExceptionAlerter; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * Created by Sohan Chowdhury on 8/21/16. 15 | * Website: sohanchy.com 16 | * Email: sifat3d@gmail.com 17 | */ 18 | public class DashboardMain extends BorderPane { 19 | private final String hugoBlogRootDirPath; 20 | TabbedHMDPostEditor tabbedHMDPostEditor; 21 | @FXML 22 | private HugoPane hugoPaneComponent; 23 | @FXML 24 | private FileTreeTable fileTreeTableComponent; 25 | 26 | public DashboardMain(String hugoBlogRootDirPath, TabbedHMDPostEditor tabbedHMDPostEditor) { 27 | super(); 28 | bindFxml(); 29 | 30 | this.tabbedHMDPostEditor = tabbedHMDPostEditor; 31 | this.hugoBlogRootDirPath = hugoBlogRootDirPath; 32 | 33 | initComponents(); 34 | } 35 | 36 | public void initComponents() { 37 | fileTreeTableComponent.setup(hugoBlogRootDirPath, tabbedHMDPostEditor); 38 | hugoPaneComponent.setup(hugoBlogRootDirPath, tabbedHMDPostEditor, fileTreeTableComponent); 39 | this.tabbedHMDPostEditor.blogDir = hugoBlogRootDirPath; 40 | 41 | } 42 | 43 | private void bindFxml() { 44 | FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("dashboard_main.fxml")); 45 | fxmlLoader.setRoot(this); 46 | fxmlLoader.setController(this); 47 | 48 | try { 49 | fxmlLoader.load(); 50 | } catch (IOException e) { 51 | System.out.println("Failed to load fxml" + e.getMessage()); 52 | ExceptionAlerter.showException(e); 53 | throw new RuntimeException(e); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/view/dashboard/dashboard_main.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 |
18 | 20 |
21 |
22 | -------------------------------------------------------------------------------- /src/view/filetree/FileTreeTable.java: -------------------------------------------------------------------------------- 1 | package view.filetree; 2 | 3 | import javafx.beans.property.ReadOnlyObjectWrapper; 4 | import javafx.beans.value.ObservableValue; 5 | import javafx.collections.FXCollections; 6 | import javafx.collections.ObservableList; 7 | import javafx.css.PseudoClass; 8 | import javafx.event.ActionEvent; 9 | import javafx.event.EventHandler; 10 | import javafx.fxml.FXML; 11 | import javafx.fxml.FXMLLoader; 12 | import javafx.scene.control.*; 13 | import javafx.scene.input.MouseEvent; 14 | import javafx.scene.layout.AnchorPane; 15 | import javafx.stage.WindowEvent; 16 | import javafx.util.Callback; 17 | import model.hugo.HMDFileProcessor; 18 | import model.toml.TomlString; 19 | import model.utility.MarkdownFileUtils; 20 | import view.hugo.hmd.TabbedHMDPostEditor; 21 | import view.utils.ExceptionAlerter; 22 | 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.text.DateFormat; 26 | import java.text.NumberFormat; 27 | import java.util.Comparator; 28 | import java.util.Date; 29 | import java.util.Optional; 30 | 31 | 32 | public class FileTreeTable extends AnchorPane { 33 | 34 | private final static NumberFormat NumberFormater = NumberFormat.getIntegerInstance(); 35 | private final static DateFormat DateFormatter = DateFormat.getDateTimeInstance(); 36 | private final ContextMenu rightClickContextMenu; 37 | private String hugoBlogRootDirPath, hugoBlogContentDirPath; 38 | private TabbedHMDPostEditor tabbedHMDPostEditor; 39 | //FXML 40 | @FXML 41 | private TreeTableView treeTableView; 42 | @FXML 43 | private TreeTableColumn nameCol, titleCol, lastModCol; 44 | 45 | public FileTreeTable() { 46 | super(); 47 | bindFxml(); 48 | rightClickContextMenu = new ContextMenu(); 49 | buildContextMenu(); 50 | } 51 | 52 | 53 | public FileTreeTable(String hugoBlogRootDirPath, TabbedHMDPostEditor tabbedHMDPostEditor) { 54 | this(); 55 | setup(hugoBlogRootDirPath, tabbedHMDPostEditor); 56 | } 57 | 58 | private void bindFxml() { 59 | FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("file_tree_table.fxml")); 60 | fxmlLoader.setRoot(this); 61 | fxmlLoader.setController(this); 62 | 63 | try { 64 | fxmlLoader.load(); 65 | } catch (IOException e) { 66 | System.out.println("Failed to load fxml" + e.getMessage()); 67 | ExceptionAlerter.showException(e); 68 | throw new RuntimeException(e); 69 | } 70 | 71 | this.getStyleClass().add("file-tree-table"); 72 | } 73 | 74 | public void setup(String hugoBlogRootDirPath, TabbedHMDPostEditor tabbedHMDPostEditor) { 75 | 76 | // buildRightClickContextMenu(); 77 | 78 | this.hugoBlogRootDirPath = hugoBlogRootDirPath; 79 | this.hugoBlogContentDirPath = this.hugoBlogRootDirPath + File.separator + "content"; 80 | this.tabbedHMDPostEditor = tabbedHMDPostEditor; 81 | prepare(); 82 | } 83 | 84 | private void prepare() { 85 | buildFileBrowserTreeTableView(treeTableView); 86 | 87 | final PseudoClass firstRowClass = PseudoClass.getPseudoClass("first-row"); 88 | 89 | treeTableView.setRowFactory(treeTable -> { 90 | TreeTableRow row = new TreeTableRow(); 91 | row.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> 92 | row.pseudoClassStateChanged(firstRowClass, newTreeItem == treeTable.getRoot())); 93 | row.setContextMenu(rightClickContextMenu); 94 | return row; 95 | }); 96 | 97 | treeTableView.setOnMouseClicked( 98 | new EventHandler() { 99 | @Override 100 | public void handle(MouseEvent mouseEvent) { 101 | if (mouseEvent.getClickCount() == 2) { 102 | openSelectedTreeitemInHmdEditor(); 103 | } 104 | 105 | } 106 | }); 107 | 108 | // this.getChildren().add(treeTableView); 109 | } 110 | 111 | private void openSelectedTreeitemInHmdEditor() { 112 | TreeItem file = treeTableView.getSelectionModel().getSelectedItem(); 113 | 114 | if (file != null) { 115 | if (!file.getValue().isDirectory() && file.getValue().getName().endsWith(".md")) { 116 | try { 117 | System.out.println(file.getValue()); 118 | openHMdPostEditor(file.getValue().getCanonicalPath()); 119 | } catch (IOException e) { 120 | ExceptionAlerter.showException(e); 121 | } 122 | } 123 | } 124 | } 125 | 126 | 127 | private void buildFileBrowserTreeTableView(TreeTableView treeTableView) { 128 | TreeItem root = createNode(new File(hugoBlogContentDirPath)); 129 | root.setExpanded(true); 130 | 131 | treeTableView.setRoot(root); 132 | 133 | nameCol.setCellValueFactory( 134 | new Callback, ObservableValue>() { 135 | @Override 136 | public ObservableValue call(TreeTableColumn.CellDataFeatures p) { 137 | File f = p.getValue().getValue(); 138 | String text = (f.getParentFile() == null) ? "/" : f.getName(); 139 | return new ReadOnlyObjectWrapper(text); 140 | } 141 | }); 142 | 143 | nameCol.setCellFactory(new Callback, TreeTableCell>() { 144 | @Override 145 | public TreeTableCell call(TreeTableColumn param) { 146 | return new TreeTableCell() { 147 | @Override 148 | protected void updateItem(String item, boolean empty) { 149 | super.updateItem(item, empty); 150 | 151 | /* if(getFileExtension(item).equals("md")){ 152 | setContextMenu(rightClickContextMenu); 153 | }*/ 154 | 155 | if (item == null || empty) { 156 | setText(null); 157 | } else { 158 | setText(item); 159 | } 160 | } 161 | }; 162 | } 163 | 164 | }); 165 | 166 | titleCol.setCellValueFactory(new Callback, ObservableValue>() { 167 | @Override 168 | public ObservableValue call(TreeTableColumn.CellDataFeatures p) { 169 | return new ReadOnlyObjectWrapper(p.getValue().getValue()); 170 | } 171 | }); 172 | titleCol.setCellFactory(new Callback, TreeTableCell>() { 173 | @Override 174 | public TreeTableCell call(final TreeTableColumn p) { 175 | return new TreeTableCell() { 176 | 177 | @Override 178 | protected void updateItem(File item, boolean empty) { 179 | super.updateItem(item, empty); 180 | 181 | TreeTableView treeTable = p.getTreeTableView(); 182 | 183 | TreeItem treeItem = treeTable.getTreeItem(getIndex()); 184 | if (item == null || empty || treeItem == null || 185 | treeItem.getValue() == null || treeItem.getValue().isDirectory()) { 186 | setText(null); 187 | } else if (getFileExtension(item).equals("md")) { 188 | try { 189 | HMDFileProcessor hmd = new HMDFileProcessor(item.getCanonicalPath()); 190 | hmd.readHMdFile(); 191 | 192 | // setContextMenu(rightClickContextMenu); 193 | 194 | if (hmd.isValidMd()) { 195 | TomlString ts = new TomlString(hmd.getFrontMatter()); 196 | String postTitle = ts.getTomlMap().get("title").toString(); 197 | 198 | if (postTitle != null) { 199 | setText(postTitle); 200 | } else { 201 | throw new Exception("TOML without any TITLE attribute."); 202 | } 203 | } 204 | } catch (Exception e) { 205 | //ExceptionAlerter.showException(e); 206 | } 207 | } else { 208 | setText(getFileExtension(item)); 209 | } 210 | } 211 | }; 212 | } 213 | }); 214 | titleCol.setComparator(new Comparator() { 215 | @Override 216 | public int compare(File f1, File f2) { 217 | long s1 = f1.isDirectory() ? 0 : f1.length(); 218 | long s2 = f2.isDirectory() ? 0 : f2.length(); 219 | long result = s1 - s2; 220 | if (result < 0) { 221 | return -1; 222 | } else if (result == 0) { 223 | return 0; 224 | } else { 225 | return 1; 226 | } 227 | } 228 | }); 229 | 230 | // --- modified column 231 | lastModCol.setCellValueFactory(new Callback, ObservableValue>() { 232 | @Override 233 | public ObservableValue call(TreeTableColumn.CellDataFeatures p) { 234 | if (!p.getValue().getValue().isDirectory()) { 235 | return new ReadOnlyObjectWrapper(new Date(p.getValue().getValue().lastModified())); 236 | } else return null; 237 | } 238 | }); 239 | lastModCol.setCellFactory(new Callback, TreeTableCell>() { 240 | @Override 241 | public TreeTableCell call(TreeTableColumn p) { 242 | return new TreeTableCell() { 243 | @Override 244 | protected void updateItem(Date item, boolean empty) { 245 | super.updateItem(item, empty); 246 | 247 | if (item == null || empty) { 248 | setText(null); 249 | } else { 250 | setText(DateFormatter.format(item)); 251 | // setContextMenu(rightClickContextMenu); 252 | } 253 | } 254 | }; 255 | } 256 | }); 257 | 258 | // treeTableView.getColumns().setAll(nameCol, titleCol, lastModCol); 259 | } 260 | 261 | private TreeItem createNode(final File f) { 262 | 263 | final TreeItem node = new TreeItem(f) { 264 | private boolean isLeaf; 265 | private boolean isFirstTimeChildren = true; 266 | private boolean isFirstTimeLeaf = true; 267 | 268 | @Override 269 | public ObservableList> getChildren() { 270 | if (isFirstTimeChildren) { 271 | isFirstTimeChildren = false; 272 | super.getChildren().setAll(buildChildren(this)); 273 | } 274 | return super.getChildren(); 275 | } 276 | 277 | @Override 278 | public boolean isLeaf() { 279 | if (isFirstTimeLeaf) { 280 | isFirstTimeLeaf = false; 281 | File f = getValue(); 282 | isLeaf = f.isFile(); 283 | } 284 | 285 | return isLeaf; 286 | } 287 | }; 288 | 289 | return node; 290 | } 291 | 292 | private ObservableList> buildChildren(TreeItem TreeItem) { 293 | File f = TreeItem.getValue(); 294 | if (f != null && f.isDirectory()) { 295 | 296 | File[] files = f.listFiles(MarkdownFileUtils.getMdFileFilter()); 297 | if (files != null) { 298 | ObservableList> children = FXCollections.observableArrayList(); 299 | 300 | for (File childFile : files) { 301 | javafx.scene.control.TreeItem node = createNode(childFile); 302 | node.setExpanded(true); 303 | children.add(node); 304 | } 305 | 306 | return children; 307 | } 308 | } 309 | 310 | return FXCollections.emptyObservableList(); 311 | } 312 | 313 | 314 | private void openHMdPostEditor(String file) { 315 | 316 | HMDFileProcessor selectedMdFile = new HMDFileProcessor(file); 317 | tabbedHMDPostEditor.addTab(selectedMdFile); 318 | 319 | } 320 | 321 | private String getFileExtension(File file) { 322 | String fileName = file.getName(); 323 | return getFileExtension(fileName); 324 | } 325 | 326 | private String getFileExtension(String fileName) { 327 | try { 328 | return fileName.substring(fileName.lastIndexOf(".") + 1); 329 | } catch (Exception e) { 330 | return ""; 331 | } 332 | } 333 | 334 | private void buildContextMenu() { 335 | 336 | MenuItem edit = new MenuItem("Edit"); 337 | edit.setOnAction(new EventHandler() { 338 | public void handle(ActionEvent e) { 339 | openSelectedTreeitemInHmdEditor(); 340 | } 341 | }); 342 | 343 | MenuItem delete = new MenuItem("Delete"); 344 | delete.setOnAction(new EventHandler() { 345 | public void handle(ActionEvent e) { 346 | File file = treeTableView.getSelectionModel().getSelectedItem().getValue(); 347 | 348 | Alert alert = new Alert(Alert.AlertType.CONFIRMATION); 349 | alert.setTitle("Confirm Delete"); 350 | alert.setHeaderText("Are you sure?"); 351 | 352 | if (!file.isDirectory()) { 353 | alert.setContentText("Click YES to delete " + file.getName()); 354 | } else { 355 | alert.setContentText("This is a folder, IT MUST BE EMPTY TO DELETE!!! :" + file.getName()); 356 | } 357 | 358 | 359 | Optional result = alert.showAndWait(); 360 | if (result.get() == ButtonType.OK) { 361 | 362 | if (!file.delete()) { 363 | alert = new Alert(Alert.AlertType.INFORMATION); 364 | alert.setTitle("Delete FAILED"); 365 | alert.setHeaderText(null); 366 | alert.setContentText("You tried to delete " + file.getName() + ".\n" 367 | + "but the Delete operation FAILED!\n" + 368 | "Check error/exception for details." 369 | ); 370 | alert.showAndWait(); 371 | } 372 | 373 | buildFileBrowserTreeTableView(treeTableView); 374 | } 375 | } 376 | }); 377 | rightClickContextMenu.getItems().addAll(edit, delete); 378 | 379 | rightClickContextMenu.setOnShowing(new EventHandler() { 380 | public void handle(WindowEvent e) { 381 | File file = treeTableView.getSelectionModel().getSelectedItem().getValue(); 382 | 383 | if (file.isDirectory()) { 384 | edit.setText("New Post"); 385 | edit.setOnAction(new EventHandler() { 386 | public void handle(ActionEvent e) { 387 | File file = treeTableView.getSelectionModel().getSelectedItem().getValue(); 388 | 389 | TabbedHMDPostEditor.createNewPostAndOpen(tabbedHMDPostEditor, file); 390 | reloadTree(); 391 | } 392 | }); 393 | 394 | } 395 | } 396 | }); 397 | } 398 | 399 | public void reloadTree() { 400 | buildFileBrowserTreeTableView(treeTableView); 401 | } 402 | 403 | } 404 | -------------------------------------------------------------------------------- /src/view/filetree/file_tree_table.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/view/hugo/hmd/HMDPostEditor.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 16 | 17 | 19 | 20 | 21 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 33 | 34 |