├── .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 | 
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 |
--------------------------------------------------------------------------------