├── .editorconfig ├── .gitignore ├── Dark ├── userchrome.css └── userstyle.css ├── README.md ├── images └── Dark.png ├── sample.md └── tcu /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | charset = utf-8 8 | 9 | [*.md] 10 | indent_style = tab 11 | indent_size = 4 12 | tab_width = 4 13 | 14 | [*.css] 15 | indent_style = tab 16 | indent_size = 2 17 | tab_width = 2 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Misc 5 | *~ 6 | TODO 7 | -------------------------------------------------------------------------------- /Dark/userchrome.css: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Styling for Dark Theme * 3 | * * 4 | * For styling the entire Joplin app (except the rendered Markdown, * 5 | * which is defined in `userstyle.css`) * 6 | *****************************************************************************/ 7 | 8 | :root { 9 | --editor-heading-color: cyan; 10 | --editor-heading-font-weight: bold; /* not used */ 11 | --editor-heading-font-size: 1.1em; /* not used */ 12 | --editor-code-color: greenyellow; 13 | --editor-text-in-brackets-color: #f9ee98; /* yellowish */ 14 | --editor-text-in-parens-color: #dddddd; /* lightgrey */ 15 | --editor-strong-color: salmon; 16 | --editor-emphasis-color: salmon; 17 | --editor-emphasis-font-style: italic; 18 | --editor-list-element-color: deepskyblue; 19 | --editor-checkbox-color: lightgrey; 20 | --editor-checkbox-checked-color: #FFCB6B; /* orange */ 21 | --editor-selected-text-bgcolor: #0663d3; /* blue */ 22 | --note-count-label-background-color: #1d2927; 23 | --note-count-label-box-shadow: white; 24 | } 25 | /* not used: to take effect the proper section must be uncommented */ 26 | 27 | /*------ Editor: Headings ---------------------------------------------------*/ 28 | .cm-header { 29 | color: var(--editor-heading-color) !important; 30 | } 31 | /*---------------------------------------------------------------------------*/ 32 | 33 | /*------ Editor: inline code and codeblocks ---------------------------------*/ 34 | pre.CodeMirror-line span[role="presentation"] span.cm-comment { 35 | color: var(--editor-code-color) !important; 36 | } 37 | /*---------------------------------------------------------------------------*/ 38 | 39 | /*------ Editor: codeblock issue macOS 10.14.x (https://g0to.ca/0k7vF) ------*/ 40 | /* 41 | .CodeMirror .cm-jn-code-block { 42 | background-color: unset !important; 43 | } 44 | */ 45 | /*---------------------------------------------------------------------------*/ 46 | 47 | /*------ Editor: text in brackets [ ] ---------------------------------------*/ 48 | .cm-link-text { 49 | color: var(--editor-text-in-brackets-color) !important; 50 | } 51 | /*---------------------------------------------------------------------------*/ 52 | 53 | /*------ Editor: text/link in parens ( ) ------------ ----------------------*/ 54 | .cm-string.cm-url { 55 | color: var(--editor-text-in-parens-color) !important; 56 | } 57 | /*---------------------------------------------------------------------------*/ 58 | 59 | /*------ Editor: strong -----------------------------------------------------*/ 60 | .cm-strong { 61 | color: var(--editor-strong-color) !important; 62 | } 63 | /*---------------------------------------------------------------------------*/ 64 | 65 | /*------ Editor: italics ----------------------------------------------------*/ 66 | .cm-em { 67 | color: var(--editor-emphasis-color) !important; 68 | } 69 | /*---------------------------------------------------------------------------*/ 70 | 71 | /*------ Editor: list elements and checkbox elements ------------------------*/ 72 | .cm-variable-2, .cm-variable-3, .cm-keyword { 73 | color: var(--editor-list-element-color) !important; 74 | } 75 | /*---------------------------------------------------------------------------*/ 76 | 77 | /*------ Editor: checkbox [ ] and [x] ---------------------------------------*/ 78 | .cm-meta { 79 | color: var(--editor-checkbox-checked-color) !important; 80 | } 81 | .cm-property { 82 | color: var(--editor-checkbox-checked-color) !important; 83 | } 84 | /*---------------------------------------------------------------------------*/ 85 | 86 | /*------ Editor: selected text background color -----------------------------*/ 87 | .CodeMirror-selected { 88 | background: var(--editor-selected-text-bgcolor) !important; 89 | } 90 | /*---------------------------------------------------------------------------*/ 91 | 92 | /*------ Notebook and note list panes: Dim items ----------------------------*/ 93 | /* 94 | a.list-item { 95 | color: #A3A79F !important; 96 | } 97 | 98 | .fas.fa-caret-right, .fas.fa-caret-down { 99 | color: #575856 !important; 100 | } 101 | 102 | .note-list input[type="checkbox"i] { 103 | opacity: .5; 104 | } 105 | */ 106 | /*---------------------------------------------------------------------------*/ 107 | 108 | /*------ Notebook pane: Nicer note count label ------------------------------*/ 109 | .note-count-label { 110 | display: flex; 111 | margin: 0 4px 0 auto; 112 | padding: 0 6px; 113 | padding-left: 0; 114 | background: var(--note-count-label-background-color); 115 | border-radius: 8px; 116 | box-shadow: 0 0 2px var(--note-count-label-box-shadow); 117 | opacity: 1 !important; 118 | } 119 | /*---------------------------------------------------------------------------*/ 120 | 121 | /*------ Notebook pane: use lines for notebook tree -------------------------*/ 122 | /* 123 | .folders i.fas.fa-caret-right, .folders i.fas.fa-caret-down { 124 | padding-right: 3px !important; 125 | } 126 | 127 | .folders .list-item-container { 128 | margin: 0 !important; 129 | } 130 | 131 | .folders a.list-item { 132 | border-left: 1px solid #575856 !important; 133 | padding-left: 9px; 134 | margin: 0 !important; 135 | } 136 | */ 137 | /*---------------------------------------------------------------------------*/ 138 | 139 | /*------ Remove New notebook button -----------------------------------------*/ 140 | /* 141 | #react-root > div > div > div.resizableLayoutItem.rli-root > div.resizableLayoutItem.rli-sideBar > div > div > div:nth-child(1) > div:nth-child(1) > button { 142 | display: none; 143 | } 144 | */ 145 | /*---------------------------------------------------------------------------*/ 146 | 147 | /*------ Remove New to-do button --------------------------------------------*/ 148 | /* 149 | button.new-todo-button { 150 | display: none; 151 | } 152 | */ 153 | /*---------------------------------------------------------------------------*/ 154 | 155 | /*------ Remove New note button ---------------------------------------------*/ 156 | /* 157 | button.new-note-button { 158 | display: none; 159 | } 160 | */ 161 | /*---------------------------------------------------------------------------*/ 162 | 163 | /*------ Remove New note/to-do buttons (entire div)--------------------------*/ 164 | /* 165 | div.new-note-todo-buttons { 166 | display: none; 167 | } 168 | */ 169 | /*---------------------------------------------------------------------------*/ 170 | 171 | /*------ Remove Code View button --------------------------------------------*/ 172 | /* 173 | div.editor-toolbar div button { 174 | display: none !important; 175 | } 176 | */ 177 | /*---------------------------------------------------------------------------*/ 178 | 179 | /*------ Remove Spellcheck button -------------------------------------------*/ 180 | /* 181 | a[title="Spell checker"] { 182 | display: none; 183 | } 184 | */ 185 | /*---------------------------------------------------------------------------*/ 186 | 187 | /*------ Input fields: Search (global, local), Note Title -------------------*/ 188 | /* .header input { */ 189 | input { 190 | border-radius: 14px !important; 191 | border: 1px solid rgb(85, 85, 85); 192 | outline: none; 193 | /* 194 | background-color: #888888 !important; 195 | */ 196 | } 197 | /*---------------------------------------------------------------------------*/ 198 | 199 | /*------ Attachment pane: make first 2 columns easier to read ---------------*/ 200 | #react-root > div > div > div:nth-child(1) > div:nth-child(2) > table > tbody > tr > td.titleCell, 201 | #react-root > div > div > div:nth-child(1) > div:nth-child(2) > table > tbody > tr > td:nth-child(2) { 202 | font-size: unset !important; 203 | } 204 | /*---------------------------------------------------------------------------*/ 205 | 206 | /*------ Sync button --------------------------------------------------------*/ 207 | /* Add button background, add rounded corners */ 208 | div.resizableLayoutItem.rli-sideBar > div > div > div:nth-child(2) > button { 209 | background-color: #25282E !important; 210 | border-radius: 16px !important; 211 | } 212 | 213 | /* Outline colour change on hover */ 214 | div.resizableLayoutItem.rli-sideBar > div > div > div:nth-child(2) > button:hover { 215 | border: 1px solid #789FE9 !important; 216 | border-radius: 16px !important; 217 | } 218 | 219 | /* Prevent button text color changing on hover */ 220 | div.resizableLayoutItem.rli-sideBar > div > div > div:nth-child(2) > button > span { 221 | color: #FFFFFF !important; 222 | } 223 | /*---------------------------------------------------------------------------*/ 224 | 225 | /*------ Toolbar buttons ----------------------------------------------------*/ 226 | .icon-code:before { 227 | display: block; 228 | content: url("data:image/svg+xml;charset=UTF-8, "); 229 | background-size: 18px 18px; 230 | height: 18px; 231 | width: 18px; 232 | padding-left: 3px; 233 | } 234 | 235 | .icon-numbered-list:before { 236 | display: block; 237 | content: url("data:image/svg+xml;charset=UTF-8, "); 238 | background-size: 18px 18px; 239 | height: 18px; 240 | width: 18px; 241 | padding-left: 3px; 242 | } 243 | 244 | .icon-to-do-list:before { 245 | display: block; 246 | content: url("data:image/svg+xml;charset=UTF-8, "); 247 | background-size: 18px 18px; 248 | height: 18px; 249 | width: 18px; 250 | padding-left: 2px; 251 | } 252 | /*---------------------------------------------------------------------------*/ 253 | -------------------------------------------------------------------------------- /Dark/userstyle.css: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Styling for Dark Theme * 3 | * * 4 | * Rendered Markdown * 5 | * Application styling is defined in `userchrome.css` * 6 | *****************************************************************************/ 7 | 8 | :root { 9 | --font-size: 13px; 10 | --mark-bgcolor: #BBDD66; /* greenish */ 11 | --search-result-bgcolor: #F3B717; /* amber */ 12 | --current-search-result-bgcolor: #CF3F00; /* red */ 13 | --preformatted-text-bgcolor: #282c34; /* darkgray */ 14 | --heading-bgcolor: #444444; /* gray */ 15 | --heading-print-bgcolor: #eeeeee; /* lightgray */ 16 | } 17 | 18 | /*------ Change the font size to 13px ---------------------------------------*/ 19 | body, th, td, p.inline-code { 20 | font-size: var(--font-size); 21 | } 22 | /*---------------------------------------------------------------------------*/ 23 | 24 | /*------ Better inline code size --------------------------------------------*/ 25 | .inline-code { 26 | font-size: 1em; 27 | } 28 | /*---------------------------------------------------------------------------*/ 29 | 30 | /*------ Colors for different mark tags -------------------------------------*/ 31 | /* ==mark== */ 32 | mark { 33 | background-color: var(--mark-bgcolor); 34 | padding: 1px 2px; 35 | } 36 | /* occurrences of search term */ 37 | mark[data-markjs] { 38 | background-color: var(--search-result-bgcolor); 39 | padding: 0; 40 | } 41 | /* current search term (local search) */ 42 | mark[data-markjs].mark-selected { 43 | background-color: var(--current-search-result-bgcolor); 44 | } 45 | /*---------------------------------------------------------------------------*/ 46 | 47 | /*------ align checkbox to the first line (baseline) ------------------------*/ 48 | li.md-checkbox .checkbox-wrapper { 49 | align-items: baseline; 50 | } 51 | /*---------------------------------------------------------------------------*/ 52 | 53 | /*------ Add background and padding to preformatted text --------------------*/ 54 | pre { 55 | padding: 0.5em; 56 | background: var(--preformatted-text-bgcolor); 57 | } 58 | /*---------------------------------------------------------------------------*/ 59 | 60 | /*------ Headings: change background and padding ----------------------------*/ 61 | h1, h2, h3, h4, h5, h6 { 62 | background-color: var(--heading-bgcolor); 63 | padding-bottom: .1em; 64 | padding-top: .2em; 65 | padding-left: .4em; 66 | border-bottom: unset; 67 | } 68 | /*---------------------------------------------------------------------------*/ 69 | 70 | /*------ Headings: Use nested counters --------------------------------------*/ 71 | body { counter-reset: h1counter; } 72 | h1 { counter-reset: h2counter; } 73 | h2 { counter-reset: h3counter; } 74 | h3 { counter-reset: h4counter; } 75 | h4 { counter-reset: h5counter; } 76 | h5 { counter-reset: h6counter; } 77 | h6 {} 78 | 79 | h1:before { 80 | counter-increment: h1counter; 81 | content: counter(h1counter) ".\0000a0\0000a0"; 82 | } 83 | 84 | h2:before { 85 | counter-increment: h2counter; 86 | content: counter(h1counter) "." counter(h2counter) ".\0000a0\0000a0"; 87 | } 88 | 89 | h3:before { 90 | counter-increment: h3counter; 91 | content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) ".\0000a0\0000a0"; 92 | } 93 | 94 | h4:before { 95 | counter-increment: h4counter; 96 | content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) ".\0000a0\0000a0"; 97 | } 98 | 99 | h5:before { 100 | counter-increment: h5counter; 101 | content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) "." counter(h5counter) ".\0000a0\0000a0"; 102 | } 103 | 104 | h6:before { 105 | counter-increment: h6counter; 106 | content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) "." counter(h5counter) "." counter(h6counter) ".\0000a0\0000a0"; 107 | } 108 | /*---------------------------------------------------------------------------*/ 109 | 110 | /*------ TOC: Use nested counters for list items ----------------------------*/ 111 | .table-of-contents ol { 112 | counter-reset: list-item; 113 | } 114 | .table-of-contents li { 115 | display: block; counter-increment: list-item; 116 | } 117 | .table-of-contents li:before { 118 | content: counters(list-item,'.') '.\0000a0'; 119 | } 120 | /*---------------------------------------------------------------------------*/ 121 | 122 | /*------ TOC: Make TOC a fixed height and scrollable ------------------------*/ 123 | /* 124 | .table-of-contents { 125 | overflow-y: auto; 126 | height: 18em; 127 | } 128 | */ 129 | /*---------------------------------------------------------------------------*/ 130 | 131 | /*------ TOC: Sidebar (move mouse to right edge) ----------------------------*/ 132 | @media not print { 133 | 134 | nav.table-of-contents ul { 135 | list-style-type: none; 136 | margin-top: 0px; 137 | margin-bottom: 0px; 138 | } 139 | 140 | nav.table-of-contents>ul { 141 | top: 5px; 142 | right: 0px; 143 | z-index: 99; 144 | 145 | font-size: 12px; 146 | position: fixed; 147 | padding: 15px; 148 | 149 | border-radius: 10px 0px 0px 10px; 150 | margin: 0px; 151 | 152 | overflow: hidden; 153 | height: 90%; 154 | width: 5px; 155 | transition: .2s; 156 | } 157 | 158 | nav.table-of-contents::after { 159 | content: "[TOC - move your cursor to the right edge]"; 160 | color: #dddddd; 161 | } 162 | 163 | nav.table-of-contents>ul:hover { 164 | background: #444444; 165 | box-shadow: -5px 0px 10px 0px rgba(211,211,211,0.75); 166 | 167 | width: 40%; 168 | color: none; 169 | overflow: scroll; 170 | } 171 | 172 | nav.table-of-contents>ul:hover::before { 173 | content: "TABLE OF CONTENTS"; 174 | } 175 | 176 | nav.table-of-contents>ul:hover li { 177 | display: list-item; 178 | } 179 | 180 | nav.table-of-contents li { 181 | display: none; 182 | white-space: nowrap; 183 | overflow: hidden; 184 | margin: 0px; 185 | padding: 0px; 186 | } 187 | 188 | nav.table-of-contents a { 189 | text-decoration: none !important; 190 | } 191 | 192 | } 193 | /*---------------------------------------------------------------------------*/ 194 | 195 | /*------ Katex: Make font (symbols and formulas) bigger ---------------------*/ 196 | /* 197 | .katex { 198 | font-size: 1.6em; 199 | } 200 | */ 201 | /*---------------------------------------------------------------------------*/ 202 | 203 | /*------ set general link color (includes TOC links) ------------------------*/ 204 | /* 205 | a { 206 | color: #a6a6ff; 207 | } 208 | */ 209 | /*---------------------------------------------------------------------------*/ 210 | 211 | /*------ change the color of INTERNAL links ---------------------------------*/ 212 | /* 213 | a[data-resource-id] { 214 | color: #d28fff; 215 | } 216 | */ 217 | /*---------------------------------------------------------------------------*/ 218 | 219 | /*------ change other resource link icons color to internal link color ------*/ 220 | /* 221 | .resource-icon { 222 | background-color: #d28fff; 223 | } 224 | */ 225 | /*---------------------------------------------------------------------------*/ 226 | 227 | /*------ do not display the Joplin resource icon ----------------------------*/ 228 | /* 229 | .resource-icon.fa-joplin { 230 | display: none; 231 | } 232 | */ 233 | /*---------------------------------------------------------------------------*/ 234 | 235 | /*------ Better alignment for resource icons --------------------------------*/ 236 | .resource-icon { 237 | top: .4em !important; 238 | } 239 | /*---------------------------------------------------------------------------*/ 240 | 241 | /*------ thinner outline for links and sections -----------------------------*/ 242 | a, summary { 243 | outline-width: 3px; 244 | } 245 | /*---------------------------------------------------------------------------*/ 246 | 247 | /*------ no outline for sections --------------------------------------------*/ 248 | summary { 249 | outline: none; 250 | } 251 | /*---------------------------------------------------------------------------*/ 252 | 253 | /*------ Print: Adjustments for printing and PDF export ---------------------*/ 254 | @media print { 255 | 256 | /* reset background and padding for preformatted text */ 257 | pre { 258 | padding: unset; 259 | background: unset; 260 | } 261 | 262 | /* lighter background for headings */ 263 | h1, h2, h3, h4, h5, h6 { 264 | background-color: var(--heading-print-bgcolor); 265 | } 266 | 267 | /* do not print note title (or when exporting to PDF) */ 268 | /* 269 | .exported-note-title { 270 | display: none !important; 271 | } 272 | */ 273 | 274 | /* do not print the anchor link symbol when the "Copy Anchor Link" */ 275 | /* plugin is active */ 276 | .cai-gf { 277 | display: none; 278 | } 279 | 280 | } 281 | /*---------------------------------------------------------------------------*/ 282 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # K.C.'s custom styles for Joplin 2 | 3 | Inspired by [Devon's repo](https://github.com/devonzuegel/joplin-custom-css) I've created my own style for Joplin. It's nothing fancy, but should work with all dark themes. 4 | In the future I might add specific styles for other themes. 5 | 6 | I've also added a [`sample.md`](sample.md) markdown file, which I used for testing the css. 7 | 8 | ## How to install 9 | 10 | There are different ways you can install and use the theme. 11 | 12 | ### Theme Config Utility 13 | 14 | - Clone the repository 15 | - Run `./tcu` 16 | 17 | See the [section](#tcu) below for a more detailed description of the utility. 18 | 19 | ### Manual Install 20 | 21 | - Clone the repository into your Joplin profile directory. If you don't know where it is, go to `Preferences` and it will show you the location. 22 | - Create symlinks to the `.css` files. (Remove or rename your current css files, if they already exist.) 23 | - Create a new branch for your own changes. This will make it easier when new updates are available. 24 | 25 | ``` 26 | cd ~/.config/joplin-desktop 27 | git clone https://github.com/tessus/joplin-custom-css.git 28 | ln -s joplin-custom-css/Dark/userchrome.css 29 | ln -s joplin-custom-css/Dark/userstyle.css 30 | cd joplin-custom-css 31 | git checkout -b my-css 32 | # make changes to the css files and commit them 33 | # when a new update is available, merge or rebase 34 | git fetch origin master:master && git rebase master 35 | ``` 36 | 37 | ## Dark 38 | 39 | ![](images/Dark.png) 40 | 41 | ## tcu 42 | 43 | Currently there's only one theme in the repository, so there's no need to specify it. 44 | 45 | A backup of the css files will be created automatically in case data would be lost otherwise. 46 | 47 | ``` 48 | tcu - Theme Config Utility 49 | 50 | usage: tcu [-t|--theme THEME] [-p|--profile PROFILE_DIR] [-x|--no-theme] [-c|--copy] [-d|--debug] [-V|--version] [-h] [--help] 51 | 52 | -t, --theme THEME 53 | activate THEME 54 | available themes: 55 | dark 56 | none (same as -x, --no-theme) 57 | 58 | -p, --profile PROFILE_DIR 59 | Joplin profile directory 60 | 61 | -x, --no-theme 62 | deactivate current theme 63 | 64 | -d, --debug 65 | print debug information 66 | 67 | -c, --copy 68 | copy files instead of creating symbolic links 69 | 70 | -V, --version 71 | version information 72 | 73 | -h 74 | usage information 75 | 76 | --help 77 | this help 78 | ``` 79 | 80 | ## Credits 81 | 82 | Many of the CSS snippets were taken from different topics on the [Joplin forum](https://discourse.joplinapp.org/). A few of them I used ad verbatim, others I had to adjust to match my theme, and others served as an inspiration. 83 | -------------------------------------------------------------------------------- /images/Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tessus/joplin-custom-css/b5acbac6ba759a0834fe53c89d5c6a5a4fc44369/images/Dark.png -------------------------------------------------------------------------------- /sample.md: -------------------------------------------------------------------------------- 1 | # Custom CSS Sample 2 | 3 | Aurea prima sata est aetas, quae vindice nullo, sponte sua, sine lege fidem rectumque colebat. 4 | 5 | - List item 1 6 | - List item 1.1 7 | 8 | - [ ] Check box 1 9 | - [ ] Check box 1.1 10 | 11 | [Reference to other note](:/00112233445566778899aabbccddeeff) 12 | 13 | Aurea prima sata est aetas, quae vindice nullo, 14 | sponte sua, sine lege fidem rectumque colebat. 15 | 16 | Test **strong** and _italics_ markup. Here's a ==marked== text. 17 | 18 | Aurea prima sata est aetas, quae vindice nullo, sponte sua, sine lege fidem rectumque colebat. 19 | 20 | Here's the [link](https://github.com/tessus/joplin-custom-css) to my `joplin-custom-css` repo. 21 | 22 | ## Mermaid 23 | 24 | ```mermaid 25 | graph LR; 26 | A-->B; 27 | B-->C; 28 | B-->D; 29 | ``` 30 | 31 | ## Katex 32 | 33 | $$ 34 | \sigma = \sqrt{\frac 1 N \sum_{i=1}^N(x_i-\bar{x})^2} 35 | $$ 36 | 37 | ## Code block 38 | 39 | ``` 40 | #include 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | printf('Test\n'); 45 | return 0; 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /tcu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION=1.0.0 4 | 5 | BASH=`which bash` 6 | BASH_VERSION=`$BASH --version |head -1 |sed 's/.*version \(.*\)-release.*/\1/' |cut -c 1` 7 | if [ $BASH_VERSION -lt 4 ]; then 8 | echo "Error: bash must be at least version 4." 9 | exit 1 10 | fi 11 | 12 | # Retrieve script directory (not following link) 13 | SCRIPT="${BASH_SOURCE[0]}" 14 | SCRIPT_DIR="$( cd "$( dirname "${SCRIPT}" )" && pwd )" 15 | INVOCATION_DIR=`pwd` 16 | PDIR="$(dirname "$SCRIPT_DIR")" 17 | BDIR="$(basename "$SCRIPT_DIR")" 18 | 19 | # Retrieve script name (follow link) 20 | PROG=`basename "$0"` 21 | 22 | # Themes are stored in an array 23 | # key: lowercase theme, value: directory of the theme 24 | declare -A THEME 25 | THEME[dark]=Dark 26 | 27 | DFT_THEME=dark 28 | 29 | # on macOS, the default getopt is a useless piece of shit 30 | # install getopt via MacPorts or brew and put it in the PATH before /usr/bin 31 | if [ "`getopt -V |cut -d\" \" -f1`" != "getopt" ]; then 32 | echo "Error: getopt not compatible enough." 33 | exit 1 34 | fi 35 | 36 | function usage { 37 | echo "usage: ${PROG} [-t|--theme THEME] [-p|--profile PROFILE_DIR] [-x|--no-theme] [-c|--copy] [-d|--debug] [-V|--version] [-h] [--help]" 38 | } 39 | 40 | function long_usage { 41 | echo "${PROG} - Theme Config Utility " 42 | echo "" 43 | usage 44 | echo "" 45 | echo " -t, --theme THEME " 46 | echo " activate THEME " 47 | echo " available themes: " 48 | for i in ${!THEME[@]} 49 | do 50 | echo " $i" 51 | done 52 | echo " none (same as -x, --no-theme) " 53 | echo "" 54 | echo " -p, --profile PROFILE_DIR " 55 | echo " Joplin profile directory " 56 | echo "" 57 | echo " -x, --no-theme " 58 | echo " deactivate current theme " 59 | echo "" 60 | echo " -d, --debug " 61 | echo " print debug information " 62 | echo "" 63 | echo " -c, --copy " 64 | echo " copy files instead of creating symbolic links " 65 | echo "" 66 | echo " -V, --version " 67 | echo " version information " 68 | echo "" 69 | echo " -h " 70 | echo " usage information " 71 | echo "" 72 | echo " --help " 73 | echo " this help " 74 | echo "" 75 | } 76 | 77 | tflag=0 78 | targ=$DFT_THEME 79 | pflag=0 80 | xflag=0 81 | cflag=0 82 | dflag=0 83 | Vflag=0 84 | hflag=0 85 | hlflag=0 86 | 87 | options=$(getopt -n $PROG -q -o t:p:xcdVh -l help,version,debug,theme:,profile:,no-theme,copy -- "$@") 88 | if [ $? != 0 ] 89 | then 90 | echo "${PROG}: Error: unrecognized option $1" 91 | usage 92 | exit 1 93 | fi 94 | 95 | eval set -- "$options" 96 | 97 | while [ $# -gt 0 ] 98 | do 99 | case "$1" in 100 | -t|--theme) 101 | tflag=1 102 | targ=${2,,} 103 | shift;; 104 | -p|--profile) 105 | pflag=1 106 | parg=$2 107 | shift;; 108 | -x|--no-theme) 109 | xflag=1;; 110 | -c|--copy) 111 | cflag=1;; 112 | -V|--version) 113 | Vflag=1;; 114 | -d|--debug) 115 | dflag=1;; 116 | -h) 117 | hflag=1;; 118 | --help) 119 | hlflag=1;; 120 | --) 121 | shift; break;; 122 | *) 123 | exit; 124 | break;; 125 | esac 126 | shift 127 | done 128 | 129 | if [ "$hflag" == "1" ]; then 130 | usage 131 | exit 132 | fi 133 | 134 | if [ "$hlflag" == "1" ]; then 135 | long_usage 136 | exit 137 | fi 138 | 139 | if [ "$Vflag" == "1" ]; then 140 | echo "$PROG $VERSION" 141 | exit 142 | fi 143 | 144 | function debug { 145 | if [ "$dflag" == "1" ]; then 146 | echo "[debug] $@" 147 | fi 148 | } 149 | 150 | if [ "$xflag" == "1" ]; then 151 | tflag=1 152 | targ=none 153 | fi 154 | 155 | if [ "$tflag" == "0" ]; then 156 | debug "Using default theme: $DFT_THEME" 157 | fi 158 | 159 | if [[ ${THEME[$targ]+_} || $targ == "none" ]]; then 160 | if [ $targ == "none" ]; then 161 | THEME_DIR=None 162 | else 163 | THEME_DIR=${THEME[$targ]} 164 | fi 165 | else 166 | echo "Error: available themes: ${!THEME[@]} none" 167 | exit 168 | fi 169 | 170 | if [ $targ != "none" ]; then 171 | debug "Theme: $targ [$THEME_DIR]" 172 | else 173 | debug "Deactivate current theme" 174 | fi 175 | 176 | if [ "$pflag" == "1" ]; then 177 | if [ -d "$parg" ]; then 178 | PROFILE_DIR="$parg" 179 | else 180 | echo "Error: profile directory [$parg] does not exist." 181 | exit 1 182 | fi 183 | else 184 | # Check, if database.sqlite exists in parent dir -> then it's the profile dir 185 | if [ -f "$PDIR/database.sqlite" ]; then 186 | PROFILE_DIR="$PDIR" 187 | elif [ -d "$HOME/.config/joplin-desktop" ]; then 188 | PROFILE_DIR=$HOME/.config/joplin-desktop 189 | else 190 | echo "Error: No profile directory found. Please specify with -p or --profile" 191 | exit 1 192 | fi 193 | fi 194 | 195 | debug "Profile directory: $PROFILE_DIR" 196 | 197 | cd $PROFILE_DIR 198 | 199 | # extension for backup file (if target is different than source) 200 | EXT=`date +%Y%m%d%H%M%S` 201 | 202 | themefiles=("userchrome.css" "userstyle.css") 203 | 204 | # Deactivate theme 205 | if [ $targ == "none" ]; then 206 | for f in ${themefiles[*]} 207 | do 208 | if [ -f $f ]; then 209 | B=0 210 | if [ ! -f .theme ]; then 211 | B=1 212 | else 213 | installed=`cat .theme` 214 | 215 | # is the data in the file .theme really a valid theme (key)? 216 | if [ ! ${THEME[$installed]+_} ]; then 217 | B=1 218 | # now check if the current file differs from the one in the theme directory 219 | elif ! diff -q $f ${SCRIPT_DIR}/${THEME[$installed]}/$f >/dev/null; then 220 | B=1 221 | fi 222 | fi 223 | if [ $B == 1 ]; then 224 | debug "Backup $f -> $f.$EXT" 225 | cp $f $f.$EXT 226 | fi 227 | debug "Remove $f" 228 | rm -f $f 229 | fi 230 | done 231 | rm -f .theme 232 | echo "Current theme deactivated." 233 | exit 234 | fi 235 | 236 | # Activate theme 237 | for f in ${themefiles[*]} 238 | do 239 | if [ -f $f ]; then 240 | # check, if we have to backup 241 | if ! diff -q $f ${SCRIPT_DIR}/${THEME_DIR}/$f >/dev/null; then 242 | debug "Backup $f -> $f.$EXT" 243 | cp $f $f.$EXT 244 | fi 245 | rm -f $f 246 | fi 247 | # copy or create links 248 | if [ "$cflag" == "1" ]; then 249 | debug "copy ${SCRIPT_DIR}/${THEME_DIR}/$f -> $f" 250 | cp ${SCRIPT_DIR}/${THEME_DIR}/$f . 251 | else 252 | # check, if we can use relative links 253 | if [ -d $BDIR ]; then 254 | debug "create relative symbolic link [ $f -> $BDIR/${THEME_DIR}/$f]" 255 | ln -fs $BDIR/${THEME_DIR}/$f $f 256 | else 257 | debug "create absolute symbolic link [ $f -> $SCRIPT_DIR/${THEME_DIR}/$f]" 258 | ln -fs $SCRIPT_DIR/${THEME_DIR}/$f $f 259 | fi 260 | fi 261 | done 262 | 263 | echo "$targ" >.theme 264 | echo "Theme [$THEME_DIR] activated." 265 | --------------------------------------------------------------------------------