Skip to content

Commit dd4372b

Browse files
committed
Add custom theme import/export functionality and update README
1 parent cce884b commit dd4372b

File tree

5 files changed

+206
-14
lines changed

5 files changed

+206
-14
lines changed

README.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ Iota's Notepad is a simple note-taking application built with Electron. It allow
1717
- Save notes manually with `Ctrl+S` (or `Cmd+S` on macOS)
1818
- Settings modal
1919
- 12-hour and 24-hour time formats
20-
- Selectable Catppuccin Mocha, Frappe and Macchiato flavors.
20+
- Selectable Catppuccin Mocha, Frappe, and Macchiato flavors
21+
- **Import and apply custom themes**
2122

2223
## Installation
2324

@@ -42,6 +43,48 @@ Iota's Notepad automatically checks for updates when the application starts. If
4243
- Right-click on a note to open the context menu, where you can edit the title, delete the note, or save the note.
4344
- Notes are saved automatically after 10 seconds of inactivity or when you press `Ctrl+S` (or `Cmd+S` on macOS).
4445
- Sort notes using the dropdown menu in the sidebar by date created, date modified, alphabetical order, or index.
46+
- **Import and apply custom themes**:
47+
- Click the "Import Theme" button in the settings modal to import a custom theme from a JSON file.
48+
- Select the imported theme from the "Theme Flavor" dropdown to apply it.
49+
- Click the "Delete Selected Theme" button to remove a custom theme.
50+
51+
## Adding Custom Themes
52+
53+
You can add custom themes to Iota's Notepad by importing a JSON file with the theme definitions. Follow these steps:
54+
55+
1. **Create a JSON file** with your custom theme definitions. The JSON file should follow this structure:
56+
```json
57+
{
58+
"customThemeName": {
59+
"--color-bg-dark": "#yourColor",
60+
"--color-bg-darker": "#yourColor",
61+
"--color-bg-medium": "#yourColor",
62+
"--color-bg-light": "#yourColor",
63+
"--color-border": "#yourColor",
64+
"--color-text": "#yourColor",
65+
"--color-placeholder": "#yourColor",
66+
"--color-hover": "#yourColor",
67+
"--color-hover-light": "#yourColor",
68+
"--color-close-hover": "#yourColor",
69+
"--color-scrollbar-bg": "#yourColor",
70+
"--color-scrollbar-thumb": "#yourColor",
71+
"--color-scrollbar-thumb-hover": "#yourColor",
72+
"--color-button-download": "#yourColor",
73+
"--color-button-download-hover": "#yourColor",
74+
"--color-button-download-text": "#yourColor"
75+
}
76+
}
77+
```
78+
2. **Import the JSON file**:
79+
- Open the settings modal by clicking the "Settings" button.
80+
- Click the "Import theme" button and select your JSON file.
81+
- The custom theme will be added to the "Theme Flavor" dropdown.
82+
3. **Apply the custom theme**:
83+
- Select the imported theme from the "Theme Flavor" dropdown.
84+
- Click the "Save settings" button to apply the theme.
85+
4. **Delete a custom theme**:
86+
- Select the custom theme from the "Theme Flavor" dropdown.
87+
- Click the "Delete theme" button to remove the theme.
4588

4689
## Screenshots
4790

index.html

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,31 +61,34 @@ <h2 class="modal-h2">Click on an item to export</h2>
6161
<div class="modal-content">
6262
<span class="close" onclick="closeSettingsModal()">&times;</span>
6363
<div style="display: flex; justify-content: space-between;">
64-
<div>
64+
<div class="settings-section">
6565
<h2 class="modal-h2">Settings</h2>
6666
<label for="timeFormat">Time Format:</label>
6767
<select id="timeFormat" class="dropdown">
6868
<option value="12">12-hour</option>
6969
<option value="24">24-hour</option>
7070
</select>
7171
<label for="themeFlavor">Theme Flavor:</label>
72-
<select id="themeFlavor" class="dropdown">
72+
<select id="themeFlavor" class="dropdown" onchange="loadTheme(this.value)">
7373
<option value="mocha">Mocha</option>
7474
<!-- <option value="latte">Latte</option> -->
7575
<!-- Commented because i have no idea how to make the window controls symbol colors change based on contrast -->
7676
<option value="frappe">Frappe</option>
7777
<option value="macchiato">Macchiato</option>
7878
</select>
7979
<div class="settings-buttons">
80-
<button class="button" onclick="saveSettings()">Save settings</button>
80+
<button class="settings-button" onclick="document.getElementById('importThemeInput').click()">Import theme</button>
81+
<input type="file" accept=".json" id="importThemeInput" style="display:none" onchange="importTheme(event)">
82+
<button class="settings-button" onclick="deleteSelectedTheme()">Delete theme</button>
83+
<button class="settings-button" onclick="saveSettings()">Save settings</button>
8184
</div>
8285
</div>
8386
<div class="divider"></div>
84-
<div>
87+
<div class="about-section">
8588
<h2 class="modal-h2">About</h2>
8689
<p id="appVersion">Version: </p>
8790
<p id="electronVersion">Electron Version: </p>
88-
<button class="button" onclick="checkForUpdates()">Check for Updates</button>
91+
<button class="update-button" onclick="checkForUpdates()">Check for Updates</button>
8992
</div>
9093
</div>
9194
</div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "iotas-notepad",
3-
"version": "1.1.2",
3+
"version": "1.1.3",
44
"main": "index.js",
55
"scripts": {
66
"electron": "electron .",

src/globals.css

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,30 @@ body {
505505
margin-bottom: 10px;
506506
}
507507

508+
.settings-button, .update-button{
509+
background-color: var(--button-bg-color);
510+
color: var(--button-color);
511+
border: 1px solid var(--button-border-color);
512+
border-radius: var(--button-border-radius);
513+
padding: var(--button-padding);
514+
cursor: pointer;
515+
transition: var(--hover-transition);
516+
margin-bottom: 10px;
517+
}
518+
508519
.modal-content label,
509520
.modal-content select {
510521
display: block;
511522
width: 100%;
512523
margin-bottom: 10px;
513524
}
514525

515-
.button:hover {
526+
.settings-section,
527+
.about-section {
528+
width: 45%; /* Set fixed width for sections */
529+
}
530+
531+
.button:hover, .settings-button:hover, .update-button:hover {
516532
background-color: var(--button-bg-color-hover);
517533
}
518534

@@ -615,10 +631,6 @@ body {
615631
background-color: var(--updater-button-hover-background-color);
616632
}
617633

618-
.settings-buttons{
619-
margin-top: 10px;
620-
}
621-
622634
.context-menu {
623635
display: none;
624636
position: absolute;

src/script.js

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,71 @@
11
let saveTimeout;
22

3-
const version = "1.1.2";
3+
const version = "1.1.3";
44
const electronVersion = "33.2.1";
55

6+
const defaultThemes = {
7+
mocha: {
8+
'--color-bg-dark': '#1e1e2e',
9+
'--color-bg-darker': '#11111b',
10+
'--color-bg-medium': '#313244',
11+
'--color-bg-light': '#45475a',
12+
'--color-border': '#6c7086',
13+
'--color-text': '#cdd6f4',
14+
'--color-placeholder': '#a6adc8',
15+
'--color-hover': '#585b70',
16+
'--color-hover-light': '#6c7086',
17+
'--color-close-hover': '#f38ba8',
18+
'--color-scrollbar-bg': '#2e3440',
19+
'--color-scrollbar-thumb': '#4c566a',
20+
'--color-scrollbar-thumb-hover': '#5e81ac',
21+
'--color-button-download': '#b4befe',
22+
'--color-button-download-hover': '#e3e7ff',
23+
'--color-button-download-text': '#11111b'
24+
},
25+
macchiato: {
26+
'--color-bg-dark': '#24273a',
27+
'--color-bg-darker': '#181926',
28+
'--color-bg-medium': '#1e2030',
29+
'--color-bg-light': '#363a4f',
30+
'--color-border': '#494d64',
31+
'--color-text': '#cad3f5',
32+
'--color-placeholder': '#a5adcb',
33+
'--color-hover': '#363a4f',
34+
'--color-hover-light': '#494d64',
35+
'--color-close-hover': '#ed8796',
36+
'--color-scrollbar-bg': '#363a4f',
37+
'--color-scrollbar-thumb': '#494d64',
38+
'--color-scrollbar-thumb-hover': '#a5adcb',
39+
'--color-button-download': '#8aadf4',
40+
'--color-button-download-hover': '#b5bfe2',
41+
'--color-button-download-text': '#24273a'
42+
},
43+
frappe: {
44+
'--color-bg-dark': '#303446',
45+
'--color-bg-darker': '#232634',
46+
'--color-bg-medium': '#292c3c',
47+
'--color-bg-light': '#414559',
48+
'--color-border': '#51576d',
49+
'--color-text': '#c6d0f5',
50+
'--color-placeholder': '#a5adcb',
51+
'--color-hover': '#414559',
52+
'--color-hover-light': '#51576d',
53+
'--color-close-hover': '#e78284',
54+
'--color-scrollbar-bg': '#414559',
55+
'--color-scrollbar-thumb': '#51576d',
56+
'--color-scrollbar-thumb-hover': '#a5adcb',
57+
'--color-button-download': '#8caaee',
58+
'--color-button-download-hover': '#b5bfe2',
59+
'--color-button-download-text': '#303446'
60+
}
61+
};
62+
663
document.addEventListener("DOMContentLoaded", () => {
764
loadNotes();
865
displayReleases();
966
loadSettings();
1067
applyThemeFlavor(); // Apply the saved theme flavor on startup
68+
updateThemeDropdown();
1169

1270
document.getElementById('appVersion').textContent = `Version: ${version}`;
1371
document.getElementById('electronVersion').textContent = `Electron Version: ${electronVersion}`;
@@ -97,7 +155,83 @@ function loadSettings() {
97155

98156
function applyThemeFlavor() {
99157
const themeFlavor = localStorage.getItem('themeFlavor') || 'mocha';
100-
document.documentElement.setAttribute('data-theme', themeFlavor);
158+
loadTheme(themeFlavor);
159+
}
160+
161+
function importTheme(event) {
162+
const file = event.target.files[0];
163+
if (file) {
164+
const reader = new FileReader();
165+
reader.onload = function(e) {
166+
try {
167+
const customThemes = JSON.parse(e.target.result);
168+
for (const [name, theme] of Object.entries(customThemes)) {
169+
saveCustomTheme(name, theme);
170+
}
171+
updateThemeDropdown();
172+
alert('Themes imported successfully!');
173+
} catch (error) {
174+
alert('Invalid JSON file.');
175+
}
176+
};
177+
reader.readAsText(file);
178+
}
179+
}
180+
181+
function deleteSelectedTheme() {
182+
const themeDropdown = document.getElementById('themeFlavor');
183+
const selectedTheme = themeDropdown.value;
184+
const customThemes = getCustomThemes();
185+
if (customThemes[selectedTheme]) {
186+
delete customThemes[selectedTheme];
187+
localStorage.setItem('customThemes', JSON.stringify(customThemes));
188+
updateThemeDropdown();
189+
alert('Theme deleted successfully!');
190+
} else {
191+
alert('Cannot delete default themes.');
192+
}
193+
}
194+
195+
function updateThemeDropdown() {
196+
const themeDropdown = document.getElementById('themeFlavor');
197+
const customThemes = getCustomThemes();
198+
// Clear existing custom themes
199+
themeDropdown.querySelectorAll('.custom-theme').forEach(option => option.remove());
200+
// Append custom themes
201+
for (const name of Object.keys(customThemes)) {
202+
const option = document.createElement('option');
203+
option.value = name;
204+
option.textContent = name;
205+
option.classList.add('custom-theme');
206+
themeDropdown.appendChild(option);
207+
}
208+
}
209+
210+
function saveCustomTheme(name, theme) {
211+
const customThemes = JSON.parse(localStorage.getItem('customThemes')) || {};
212+
customThemes[name] = theme;
213+
localStorage.setItem('customThemes', JSON.stringify(customThemes));
214+
}
215+
216+
function getCustomThemes() {
217+
return JSON.parse(localStorage.getItem('customThemes')) || {};
218+
}
219+
220+
function applyTheme(theme) {
221+
const root = document.documentElement;
222+
for (const [key, value] of Object.entries(theme)) {
223+
root.style.setProperty(key, value);
224+
}
225+
}
226+
227+
function loadTheme(themeName) {
228+
const customThemes = getCustomThemes();
229+
const theme = customThemes[themeName] || defaultThemes[themeName];
230+
if (theme) {
231+
applyTheme(theme);
232+
} else {
233+
document.documentElement.setAttribute('data-theme', themeName);
234+
}
101235
}
102236

103237
async function checkForUpdates() {

0 commit comments

Comments
 (0)