Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 38 additions & 36 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,53 +36,55 @@ Available for Mac, Windows, and Linux.
**On Mac**

```
⌘ + Enter Add new block below the current block
⌥ + Enter Add new block before the current block
⌘ + Shift + Enter Add new block at the end of the buffer
⌥ + Shift + Enter Add new block at the start of the buffer
⌘ + ⌥ + Enter Split the current block at cursor position
⌘ + L Change block language
⌘ + N Create a new note buffer
⌘ + S Move the current block to another (or new) buffer
⌘ + P Open note selector
⌘ + Shift + P Open command palette
⌘ + Down Goto next block
⌘ + Up Goto previous block
⌘ + A Select all text in a note block. Press again to select the whole buffer
⌘ + ⌥ + Up/Down Add additional cursor above/below
⌥ + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown)
⌘ + ⌥ + [ Fold block(s)
⌘ + ⌥ + ] Unfold block(s)
⌘ + ⌥ + . Toggle block fold
⌘ + Enter 在当前块下方添加新块
⌥ + Enter 在当前块上方添加新块
⌘ + Shift + Enter 在缓冲区末尾添加新块
⌥ + Shift + Enter 在缓冲区开头添加新块
⌘ + ⌥ + Enter 在光标位置拆分当前块
⌘ + L 更改块语言
⌘ + N 创建新的笔记缓冲区
⌘ + S 将当前块移动到另一个(或新的)缓冲区
⌘ + P 打开笔记选择器
⌘ + Shift + P 打开命令面板
⌘ + Down 转到下一个块
⌘ + Up 转到上一个块
⌘ + A 选择笔记块中的所有文本。再次按选择整个缓冲区
⌘ + ⌥ + Up/Down 在上方/下方添加额外光标
⌥ + Shift + F 格式化块内容(适用于 JSONJavaScriptHTMLCSS Markdown
⌘ + ⌥ + [ 折叠块
⌘ + ⌥ + ] 展开块
⌘ + ⌥ + . 切换块折叠状态
```

**On Windows and Linux**

```
Ctrl + Enter Add new block below the current block
Alt + Enter Add new block before the current block
Ctrl + Shift + Enter Add new block at the end of the buffer
Alt + Shift + Enter Add new block at the start of the buffer
Ctrl + Alt + Enter Split the current block at cursor position
Ctrl + L Change block language
Ctrl + N Create a new note buffer
Ctrl + S Move the current block to another (or new) buffer
Ctrl + P Open note selector
Ctrl + Shift + P Open command palette
Ctrl + Down Goto next block
Ctrl + Up Goto previous block
Ctrl + A Select all text in a note block. Press again to select the whole buffer
Ctrl + Alt + Up/Down Add additional cursor above/below
Alt + Shift + F Format block content (works for JSON, JavaScript, HTML, CSS and Markdown)
Ctrl + Alt + [ Fold block(s)
Ctrl + Alt + ] Unfold block(s)
Ctrl + Alt + . Toggle block fold
Ctrl + Enter 在当前块下方添加新块
Alt + Enter 在当前块上方添加新块
Ctrl + Shift + Enter 在缓冲区末尾添加新块
Alt + Shift + Enter 在缓冲区开头添加新块
Ctrl + Alt + Enter 在光标位置拆分当前块
Ctrl + L 更改块语言
Ctrl + N 创建新的笔记缓冲区
Ctrl + S 将当前块移动到另一个(或新的)缓冲区
Ctrl + P 打开笔记选择器
Ctrl + Shift + P 打开命令面板
Ctrl + Down 转到下一个块
Ctrl + Up 转到上一个块
Ctrl + A 选择笔记块中的所有文本。再次按选择整个缓冲区
Ctrl + Alt + Up/Down 在上方/下方添加额外光标
Alt + Shift + F 格式化块内容(适用于 JSONJavaScriptHTMLCSS Markdown
Ctrl + Alt + [ 折叠块
Ctrl + Alt + ] 展开块
Ctrl + Alt + . 切换块折叠状态
```

You can see all the key bindings in the command palette and in Settings under Key Bindings.





## Custom Key Bindings<a id="custom-key-bindings"></a>

Heynote supports custom key bindings which you can configure in the settings. The key bindings are evaluated from top to bottom, so a binding that comes before another one will take precedence. Most commands will stop the event from propagating, but some commands only applies in certain contexts and might not stop the event from propagating to a later key binding.
Expand Down
59 changes: 40 additions & 19 deletions electron/initial-content.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
import os from "os";
import { keyHelpStr } from "../shared-utils/key-helper";
import { safeTranslate } from "../src/locales/i18n-core";

// Get system locale or default to English
let systemLocale = 'en';

try {
// First try to get language from browser (works in both dev and production)
if (typeof navigator !== 'undefined' && navigator.language) {
let browserLang = navigator.language.split('-')[0];
if (navigator.language === 'zh-TW' || navigator.language === 'zh-HK' || navigator.language === 'zh-MO') {
systemLocale = 'zh-TW';
} else if (browserLang === 'zh' || browserLang === 'en' || browserLang === 'ja' || browserLang === 'ko') {
systemLocale = browserLang;
}
}
// Fallback to Electron system locale (only works in production)
else {
const { app } = require('electron');
if (app && app.getLocale) {
const locale = app.getLocale();
if (locale === 'zh-TW' || locale === 'zh-HK' || locale === 'zh-MO') {
systemLocale = 'zh-TW';
} else {
const lang = locale.split('-')[0];
if (lang === 'zh' || lang === 'en' || lang === 'ja' || lang === 'ko') {
systemLocale = lang;
}
}
}
}
} catch (e) {
// Ignore errors, default to English
}

const created = (new Date()).toISOString()

// Use safeTranslate directly without Vue dependency
const t = (key) => safeTranslate(systemLocale, key);

export const initialContent = `
{"formatVersion":"1.0.0","name":"Scratch"}
∞∞∞text;created=${created}
Welcome to Heynote! 👋
${t('initialContent.welcome')}

${keyHelpStr(os.platform())}
∞∞∞markdown;created=${created}
Read full documentation at https://heynote.com/docs
${t('initialContent.documentation')}
∞∞∞math;created=${created}
This is a Math block. Here, rows are evaluated as math expressions.

radius = 5
area = radius^2 * PI
sqrt(9)

It also supports some basic unit conversions, including currencies:

13 inches in cm
time = 3900 seconds to minutes
time * 2

1 EUR in USD
${t('initialContent.mathBlock')}
∞∞∞markdown;created=${created}
In Markdown blocks, lists with [x] and [ ] are rendered as checkboxes:

- [x] Download Heynote
- [ ] Try out Heynote
${t('initialContent.markdownBlock')}
∞∞∞text-a;created=${created}
`

Expand Down
76 changes: 58 additions & 18 deletions shared-utils/key-helper.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,70 @@
import { safeTranslate } from "../src/locales/i18n-core";

// Get system locale or default to English
function getSystemLocale() {
let systemLocale = 'en';

try {
// First try to get language from browser
if (typeof navigator !== 'undefined' && navigator.language) {
let browserLang = navigator.language.split('-')[0];
if (navigator.language === 'zh-TW' || navigator.language === 'zh-HK' || navigator.language === 'zh-MO') {
systemLocale = 'zh-TW';
} else if (browserLang === 'zh' || browserLang === 'en' || browserLang === 'ja' || browserLang === 'ko') {
systemLocale = browserLang;
}
}
// Fallback to Electron system locale
else {
const { app } = require('electron');
if (app && app.getLocale) {
const locale = app.getLocale();
if (locale === 'zh-TW' || locale === 'zh-HK' || locale === 'zh-MO') {
systemLocale = 'zh-TW';
} else {
const lang = locale.split('-')[0];
if (lang === 'zh' || lang === 'en' || lang === 'ja' || lang === 'ko') {
systemLocale = lang;
}
}
}
}
} catch (e) {
// Ignore errors, default to English
}

return systemLocale;
}

const t = (key: string) => safeTranslate(getSystemLocale(), key);

export const keyHelpStr = (platform: string, extended: boolean = false) => {
const modChar = platform === "darwin" ? "⌘" : "Ctrl"
const altChar = platform === "darwin" ? "⌥" : "Alt"

const keyHelp = [
[`${modChar} + Enter`, "Add new block below the current block"],
[`${altChar} + Enter`, "Add new block before the current block"],
[`${modChar} + Shift + Enter`, "Add new block at the end of the buffer"],
[`${altChar} + Shift + Enter`, "Add new block at the start of the buffer"],
[`${modChar} + ${altChar} + Enter`, "Split the current block at cursor position"],
[`${modChar} + L`, "Change block language"],
[`${modChar} + N`, "Create a new note buffer"],
[`${modChar} + S`, "Move the current block to another (or new) buffer"],
[`${modChar} + P`, "Open note selector"],
[`${modChar} + Shift + P`, "Open command palette"],
[`${modChar} + Down`, "Goto next block"],
[`${modChar} + Up`, "Goto previous block"],
[`${modChar} + A`, "Select all text in a note block. Press again to select the whole buffer"],
[`${modChar} + ${altChar} + Up/Down`, "Add additional cursor above/below"],
[`${altChar} + Shift + F`, "Format block content (works for JSON, JavaScript, HTML, CSS and Markdown)"],
[`${modChar} + Enter`, t('keybindings.addBlockBelow')],
[`${altChar} + Enter`, t('keybindings.addBlockBefore')],
[`${modChar} + Shift + Enter`, t('keybindings.addBlockEnd')],
[`${altChar} + Shift + Enter`, t('keybindings.addBlockStart')],
[`${modChar} + ${altChar} + Enter`, t('keybindings.splitBlock')],
[`${modChar} + L`, t('keybindings.changeLanguage')],
[`${modChar} + N`, t('keybindings.createBuffer')],
[`${modChar} + S`, t('keybindings.moveBlock')],
[`${modChar} + P`, t('keybindings.openSelector')],
[`${modChar} + Shift + P`, t('keybindings.openPalette')],
[`${modChar} + Down`, t('keybindings.nextBlock')],
[`${modChar} + Up`, t('keybindings.previousBlock')],
[`${modChar} + A`, t('keybindings.selectAll')],
[`${modChar} + ${altChar} + Up/Down`, t('keybindings.addCursor')],
[`${altChar} + Shift + F`, t('keybindings.formatBlock')],
]

if (extended) {
keyHelp.push(
[`${modChar} + ${altChar} + [`, "Fold block(s)"],
[`${modChar} + ${altChar} + ]`, "Unfold block(s)"],
[`${modChar} + ${altChar} + .`, "Toggle block fold"],
[`${modChar} + ${altChar} + [`, t('keybindings.foldBlock')],
[`${modChar} + ${altChar} + ]`, t('keybindings.unfoldBlock')],
[`${modChar} + ${altChar} + .`, t('keybindings.toggleFold')],
)
}

Expand Down
4 changes: 3 additions & 1 deletion src/components/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { toRaw } from 'vue'
import { mapState, mapActions } from 'pinia'
import { i18n } from "../locales/i18n"

import { mapWritableState, mapStores } from 'pinia'
import { useHeynoteStore } from "../stores/heynote-store"
Expand Down Expand Up @@ -82,7 +83,8 @@
})

window.heynote.mainProcess.on('tab:deleteBuffer', (event, tabPath) => {
if (confirm(`Are you sure you want to delete the buffer "${this.heynoteStore.getBufferTitle(tabPath)}"?`)) {
const title = this.heynoteStore.getBufferTitle(tabPath)
if (confirm(i18n.t('app.deleteConfirm', { title }))) {
this.deleteBuffer(tabPath)
}
this.focusEditor()
Expand Down
12 changes: 10 additions & 2 deletions src/components/BufferSelector.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script>
import fuzzysort from 'fuzzysort'
import { i18n } from "../locales/i18n"

import { mapState, mapActions } from 'pinia'
import { SCRATCH_FILE_NAME } from "../common/constants"
Expand Down Expand Up @@ -74,6 +75,10 @@
bindings: this.commandKeyBindingsMap[cmdKey],
}))
},

currentLocale() {
return i18n.locale
},

orderedItems() {
const sortKeys = Object.fromEntries(this.recentBufferPaths.map((item, idx) => [item, idx]))
Expand Down Expand Up @@ -101,8 +106,11 @@
},

filteredItems() {
// Access currentLocale to make this computed property depend on it
this.currentLocale

if (this.commandsEnabled && this.filter.startsWith(">")) {
// command mode if the first character is ">"
// command mode if the first character is ">
if (this.filter.length < 2) {
return this.commands
}
Expand Down Expand Up @@ -134,7 +142,7 @@
}

const newNoteItem = {
name: "Create new…",
name: i18n.t('bufferSelector.createNew'),
createNew:true,
}
return [
Expand Down
3 changes: 2 additions & 1 deletion src/components/EditBuffer.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { toRaw } from 'vue';
import { mapState, mapActions } from 'pinia'
import { i18n } from "../locales/i18n"
import { useHeynoteStore } from "../stores/heynote-store"
import { filenameSlug } from "@/src/common/sanitize-filename"

Expand Down Expand Up @@ -178,7 +179,7 @@
@input="errors.name = false"
/>

<label for="folder-select">Move to</label>
<label for="folder-select">{{ $t('editBuffer.moveTo') }}</label>
<FolderSelector
v-if="directoryTree"
:directoryTree="directoryTree"
Expand Down
3 changes: 2 additions & 1 deletion src/components/NewBuffer.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script>
import { mapState, mapActions } from 'pinia'
import { i18n } from "../locales/i18n"
import { useHeynoteStore } from "../stores/heynote-store"

import { filenameSlug } from "@/src/common/sanitize-filename"
Expand Down Expand Up @@ -204,7 +205,7 @@
data-1p-ignore
/>

<label for="folder-select">Create in</label>
<label for="folder-select">{{ $t('newBuffer.createIn') }}</label>
<FolderSelector
v-if="directoryTree"
:directoryTree="directoryTree"
Expand Down
14 changes: 8 additions & 6 deletions src/components/UpdateStatusItem.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script>
import { i18n } from "../locales/i18n"

export default {
props: [
"autoUpdate",
Expand Down Expand Up @@ -85,11 +87,11 @@
computed: {
statusText() {
if (this.downloading) {
return "Downloading update… " + this.updateProgress.percent.toFixed(0) + "%"
return i18n.t('update.downloading', { percent: this.updateProgress.percent.toFixed(0) })
} else if (this.updateDownloaded) {
return "Update & Restart"
return i18n.t('update.updateAndRestart')
} else if (this.updateAvailable) {
return "New version available!"
return i18n.t('update.newVersionAvailable')
} else {
return ""
}
Expand All @@ -99,11 +101,11 @@
if (this.downloading) {
return ""
} else if (this.updateDownloaded) {
return "Click to restart and update Heynote"
return i18n.t('update.clickToRestart')
} else if (this.updateAvailable) {
return "Update to version " + this.version + " (current version: " + this.currentVersion + ")"
return i18n.t('update.updateToVersion', { version: this.version, currentVersion: this.currentVersion })
} else {
return "Check for updates"
return i18n.t('update.checkForUpdates')
}
},

Expand Down
Loading