Skip to content
Merged
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
11 changes: 11 additions & 0 deletions src/main/i18n/locales/en_US/preferences.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,17 @@
"label": "Markdown",
"codeRenderer": "Code block Renderer"
},
"math": {
"label": "Math Notebook",
"locale": {
"label": "Region",
"description": "Number and date display format."
},
"decimalPlaces": {
"label": "Decimal Places",
"description": "Maximum decimal places in results (0\u201314)."
}
},
"api": {
"label": "API Port",
"port": {
Expand Down
22 changes: 22 additions & 0 deletions src/main/store/module/preferences.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
EditorSettings,
MarkdownSettings,
MathSettings,
NotesEditorSettings,
PreferencesStore,
} from '../types'
Expand All @@ -20,6 +21,11 @@ const isWin = platform() === 'win32'

const storagePath = isWin ? `${homedir()}\\massCode` : `${homedir()}/massCode`

const MATH_DEFAULTS: MathSettings = {
locale: 'en-US',
decimalPlaces: 6,
}

const PREFERENCES_DEFAULTS: PreferencesStore = {
appearance: {
theme: 'auto',
Expand All @@ -41,6 +47,7 @@ const PREFERENCES_DEFAULTS: PreferencesStore = {
scale: 1,
},
},
math: MATH_DEFAULTS,
}

function sanitizeCodeEditorSettings(value: unknown): EditorSettings {
Expand Down Expand Up @@ -143,6 +150,19 @@ function sanitizeMarkdownSettings(value: unknown): MarkdownSettings {
}
}

function sanitizeMathSettings(value: unknown): MathSettings {
const source = asRecord(value)

return {
locale: readString(source, 'locale', MATH_DEFAULTS.locale),
decimalPlaces: readNumber(
source,
'decimalPlaces',
MATH_DEFAULTS.decimalPlaces,
),
}
}

function sanitizePreferences(value: unknown): PreferencesStore {
const source = asRecord(value)
const appearanceSource = asRecord(source.appearance)
Expand All @@ -162,6 +182,7 @@ function sanitizePreferences(value: unknown): PreferencesStore {
= Object.keys(asRecord(editorSource.markdown)).length > 0
? asRecord(editorSource.markdown)
: asRecord(source.markdown)
const mathSource = asRecord(source.math)

return {
appearance: {
Expand Down Expand Up @@ -210,6 +231,7 @@ function sanitizePreferences(value: unknown): PreferencesStore {
notes: sanitizeNotesEditorSettings(notesEditorSource),
markdown: sanitizeMarkdownSettings(markdownSource),
},
math: sanitizeMathSettings(mathSource),
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/main/store/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export interface NotesEditorSettings {
indentSize: number
}

export interface MathSettings {
locale: string
decimalPlaces: number
}

export interface PreferencesStore {
appearance: {
theme: string
Expand All @@ -96,6 +101,7 @@ export interface PreferencesStore {
notes: NotesEditorSettings
markdown: MarkdownSettings
}
math: MathSettings
}

export interface MathSheet {
Expand Down
12 changes: 8 additions & 4 deletions src/renderer/components/math-notebook/ResultsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
import type { LineResult } from '@/composables/math-notebook'
import { Button } from '@/components/ui/shadcn/button'
import { useCopyToClipboard } from '@/composables'
import { formatMathNumber } from '@/composables/math-notebook/math-engine/format'
import { i18n, ipc } from '@/electron'
import { LoaderCircle, Sigma } from 'lucide-vue-next'

interface Props {
results: LineResult[]
scrollTop: number
activeLine: number
locale: string
decimalPlaces: number
}

const props = defineProps<Props>()
Expand All @@ -21,7 +24,10 @@ const MATH_NOTEBOOK_DOCUMENTATION_URL
const total = computed(() => {
return props.results.reduce((sum, r) => {
if (r.type === 'number' || r.type === 'assignment') {
const num = Number.parseFloat((r.value || '').replace(/,/g, ''))
const raw = r.value || ''
if (raw.includes(':'))
return sum
const num = Number.parseFloat(raw.replace(/[^\d.\-e+]/gi, ''))
if (!Number.isNaN(num))
return sum + num
}
Expand All @@ -30,9 +36,7 @@ const total = computed(() => {
})

const formattedTotal = computed(() => {
return Number.isInteger(total.value)
? total.value.toLocaleString('en-US')
: total.value.toLocaleString('en-US', { maximumFractionDigits: 6 })
return formatMathNumber(total.value, props.locale, props.decimalPlaces)
})

const resultsStyle = computed(() => {
Expand Down
26 changes: 23 additions & 3 deletions src/renderer/components/math-notebook/Workspace.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script setup lang="ts">
import type { LineResult } from '@/composables/math-notebook'
import type { MathSettings } from '~/main/store/types'
import { useMathEngine, useMathNotebook } from '@/composables'
import { i18n, ipc } from '@/electron'
import { i18n, ipc, store } from '@/electron'
import { Calculator } from 'lucide-vue-next'

interface CurrencyRatesPayload {
Expand All @@ -10,8 +11,25 @@ interface CurrencyRatesPayload {
}

const { activeSheet, updateSheet } = useMathNotebook()
const { evaluateDocument, setCurrencyServiceState, updateCurrencyRates }
= useMathEngine()
const {
evaluateDocument,
setCurrencyServiceState,
setFormatSettings,
updateCurrencyRates,
} = useMathEngine()

const mathSettings = reactive(store.preferences.get('math') as MathSettings)

setFormatSettings(mathSettings.locale, mathSettings.decimalPlaces)

watch(
mathSettings,
() => {
store.preferences.set('math', JSON.parse(JSON.stringify(mathSettings)))
setFormatSettings(mathSettings.locale, mathSettings.decimalPlaces)
},
{ deep: true },
)

const scrollTop = ref(0)
const activeLine = ref(0)
Expand Down Expand Up @@ -98,6 +116,8 @@ function handleActiveLine(line: number) {
:results="results"
:scroll-top="scrollTop"
:active-line="activeLine"
:locale="mathSettings.locale"
:decimal-places="mathSettings.decimalPlaces"
/>
</div>

Expand Down
109 changes: 109 additions & 0 deletions src/renderer/components/preferences/Math.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<script setup lang="ts">
import type { MathSettings } from '~/main/store/types'
import * as Select from '@/components/ui/shadcn/select'
import {
formatMathDate,
formatMathNumber,
} from '@/composables/math-notebook/math-engine/format'
import { i18n, store } from '@/electron'

const settings = reactive(store.preferences.get('math') as MathSettings)

watch(
settings,
() => {
store.preferences.set('math', JSON.parse(JSON.stringify(settings)))
},
{ deep: true },
)

const localeOptions = [
{ label: 'English (US)', value: 'en-US' },
{ label: 'English (UK)', value: 'en-GB' },
{ label: 'Deutsch', value: 'de-DE' },
{ label: 'Fran\u00E7ais', value: 'fr-FR' },
{ label: '\u0420\u0443\u0441\u0441\u043A\u0438\u0439', value: 'ru-RU' },
{ label: 'Espa\u00F1ol', value: 'es-ES' },
{ label: 'Portugu\u00EAs (BR)', value: 'pt-BR' },
{ label: '\u65E5\u672C\u8A9E', value: 'ja-JP' },
{ label: '\u4E2D\u6587', value: 'zh-CN' },
{ label: '\uD55C\uAD6D\uC5B4', value: 'ko-KR' },
{ label: 'Italiano', value: 'it-IT' },
{ label: 'Polski', value: 'pl-PL' },
{
label: '\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430',
value: 'uk-UA',
},
{ label: 'T\u00FCrk\u00E7e', value: 'tr-TR' },
{ label: 'Nederlands', value: 'nl-NL' },
]

const decimalPlacesOptions = Array.from({ length: 15 }, (_, i) => ({
label: String(i),
value: String(i),
}))

const localePreview = computed(() => {
const num = formatMathNumber(
1234.5678,
settings.locale,
settings.decimalPlaces,
)
const date = formatMathDate(new Date(), settings.locale)
return `${num} \u00B7 ${date}`
})

const decimalPlacesPreview = computed(() => {
return `1/3 = ${formatMathNumber(1 / 3, settings.locale, settings.decimalPlaces)}`
})
</script>

<template>
<div class="space-y-4">
<UiMenuFormSection :label="i18n.t('preferences:math.label')">
<UiMenuFormItem :label="i18n.t('preferences:math.locale.label')">
<Select.Select v-model="settings.locale">
<Select.SelectTrigger class="w-64">
<Select.SelectValue />
</Select.SelectTrigger>
<Select.SelectContent>
<Select.SelectItem
v-for="option in localeOptions"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</Select.SelectItem>
</Select.SelectContent>
</Select.Select>
<template #description>
{{ i18n.t("preferences:math.locale.description") }}
{{ localePreview }}
</template>
</UiMenuFormItem>
<UiMenuFormItem :label="i18n.t('preferences:math.decimalPlaces.label')">
<Select.Select
:model-value="String(settings.decimalPlaces)"
@update:model-value="settings.decimalPlaces = Number($event)"
>
<Select.SelectTrigger class="w-64">
<Select.SelectValue />
</Select.SelectTrigger>
<Select.SelectContent>
<Select.SelectItem
v-for="option in decimalPlacesOptions"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</Select.SelectItem>
</Select.SelectContent>
</Select.Select>
<template #description>
{{ i18n.t("preferences:math.decimalPlaces.description") }}
{{ decimalPlacesPreview }}
</template>
</UiMenuFormItem>
</UiMenuFormSection>
</div>
</template>
18 changes: 11 additions & 7 deletions src/renderer/composables/__tests__/useMathEngine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ describe('prev', () => {
const results = evalLines('fromunix(1446587186)\nprev + 1 day')
expect(results[1].type).toBe('date')
expect(results[1].value).toBe(
new Date((1446587186 + 86400) * 1000).toLocaleString(),
new Date((1446587186 + 86400) * 1000).toLocaleString('en-US'),
)
})
})
Expand Down Expand Up @@ -658,7 +658,7 @@ describe('fromunix', () => {
const result = evalLine('fromunix(1446587186) + 2 day')
expect(result.type).toBe('date')
expect(result.value).toBe(
new Date((1446587186 + 2 * 86400) * 1000).toLocaleString(),
new Date((1446587186 + 2 * 86400) * 1000).toLocaleString('en-US'),
)
})

Expand All @@ -667,16 +667,20 @@ describe('fromunix', () => {
expect(results[0].type).toBe('assignment')
expect(results[1].type).toBe('date')
expect(results[1].value).toBe(
new Date((1446587186 + 2 * 86400) * 1000).toLocaleString(),
new Date((1446587186 + 2 * 86400) * 1000).toLocaleString('en-US'),
)
})

it('local dotted date assignment + 2 day', () => {
const results = evalLines('x = 12.03.2025\nx + 2 day')
expect(results[0].type).toBe('assignment')
expect(results[0].value).toBe(new Date(2025, 2, 12).toLocaleString())
expect(results[0].value).toBe(
new Date(2025, 2, 12).toLocaleString('en-US'),
)
expect(results[1].type).toBe('date')
expect(results[1].value).toBe(new Date(2025, 2, 14).toLocaleString())
expect(results[1].value).toBe(
new Date(2025, 2, 14).toLocaleString('en-US'),
)
})
})

Expand Down Expand Up @@ -706,7 +710,7 @@ describe('time zones', () => {
const result = evalLine('time() + 1 day')
expect(result.type).toBe('date')
expect(result.value).toBe(
new Date('2026-03-07T12:00:00Z').toLocaleString(),
new Date('2026-03-07T12:00:00Z').toLocaleString('en-US'),
)
})

Expand All @@ -720,7 +724,7 @@ describe('time zones', () => {
const result = evalLine('now + 1 day')
expect(result.type).toBe('date')
expect(result.value).toBe(
new Date('2026-03-07T12:00:00Z').toLocaleString(),
new Date('2026-03-07T12:00:00Z').toLocaleString('en-US'),
)
})

Expand Down
Loading