diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3dce414 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9308a4b..b6f8a7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,326 +1,16 @@ -## Core latex/pdflatex auxiliary files: -*.aux -*.lof +node_modules/ +out/ +dist/ +build/ +.env +.DS_Store +.idea/ +.vscode/ *.log -*.lot -*.fls -*.out -*.toc -*.fmt -*.fot -*.cb -*.cb2 -.*.lb - -## Intermediate documents: -*.dvi -*.xdv -*-converted-to.* -# these rules might exclude image files for figures etc. -# *.ps -# *.eps -# *.pdf - -## Generated if empty string is given at "Please type another file name for output:" -.pdf - -## Bibliography auxiliary files (bibtex/biblatex/biber): -*.bbl -*.bbl-SAVE-ERROR -*.bcf -*.bcf-SAVE-ERROR -*.blg -*-blx.aux -*-blx.bib -*.run.xml - -## Build tool auxiliary files: -*.fdb_latexmk -*.synctex -*.synctex(busy) -*.synctex.gz -*.synctex.gz(busy) -*.pdfsync -*.rubbercache -rubber.cache - -## Build tool directories for auxiliary files -# latexrun -latex.out/ - -## Auxiliary and intermediate files from other packages: -# algorithms -*.alg -*.loa - -# achemso -acs-*.bib - -# amsthm -*.thm - -# attachfile2 -*.atfi - -# beamer -*.nav -*.pre -*.snm -*.vrb - -# changes -*.soc -*.loc - -# comment -*.cut - -# cprotect -*.cpt - -# elsarticle (documentclass of Elsevier journals) -*.spl - -# endnotes -*.ent - -# fixme -*.lox - -# feynmf/feynmp -*.mf -*.mp -*.t[1-9] -*.t[1-9][0-9] -*.tfm - -#(r)(e)ledmac/(r)(e)ledpar -*.end -*.?end -*.[1-9] -*.[1-9][0-9] -*.[1-9][0-9][0-9] -*.[1-9]R -*.[1-9][0-9]R -*.[1-9][0-9][0-9]R -*.eledsec[1-9] -*.eledsec[1-9]R -*.eledsec[1-9][0-9] -*.eledsec[1-9][0-9]R -*.eledsec[1-9][0-9][0-9] -*.eledsec[1-9][0-9][0-9]R - -# glossaries -*.acn -*.acr -*.glg -*.glg-abr -*.glo -*.glo-abr -*.gls -*.gls-abr -*.glsdefs -*.lzo -*.lzs -*.slg -*.slo -*.sls - -# uncomment this for glossaries-extra (will ignore makeindex's style files!) -# *.ist - -# gnuplot -*.gnuplot -*.table - -# gnuplottex -*-gnuplottex-* - -# gregoriotex -*.gaux -*.glog -*.gtex - -# htlatex -*.4ct -*.4tc -*.idv -*.lg -*.trc -*.xref - -# hypdoc -*.hd - -# hyperref -*.brf - -# knitr -*-concordance.tex -# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files -# *.tikz -*-tikzDictionary - -# latexindent will create succesive backup files by default -#*.bak* - -# listings -*.lol - -# luatexja-ruby -*.ltjruby - -# makeidx -*.idx -*.ilg -*.ind - -# minitoc -*.maf -*.mlf -*.mlt -*.mtc[0-9]* -*.slf[0-9]* -*.slt[0-9]* -*.stc[0-9]* - -# minted -_minted* -*.data.minted -*.pyg - -# morewrites -*.mw - -# newpax -*.newpax - -# nomencl -*.nlg -*.nlo -*.nls - -# pax -*.pax - -# pdfpcnotes -*.pdfpc - -# sagetex -*.sagetex.sage -*.sagetex.py -*.sagetex.scmd - -# scrwfile -*.wrt - -# spelling -*.spell.bad -*.spell.txt - -# svg -svg-inkscape/ - -# sympy -*.sout -*.sympy -sympy-plots-for-*.tex/ - -# pdfcomment -*.upa -*.upb - -# pythontex -*.pytxcode -pythontex-files-*/ - -# tcolorbox -*.listing - -# thmtools -*.loe - -# TikZ & PGF -*.dpth -*.md5 -*.auxlock - -# titletoc -*.ptc - -# todonotes -*.tdo - -# vhistory -*.hst -*.ver - -# easy-todo -*.lod - -# xcolor -*.xcp - -# xmpincl -*.xmpi - -# xindy -*.xdy - -# xypic precompiled matrices and outlines -*.xyc -*.xyd - -# endfloat -*.ttt -*.fff - -# Latexian -TSWLatexianTemp* - -## Editors: -# WinEdt -*.bak -*.sav - -# latexindent.pl -*.bak[0-9]* - -# Texpad -.texpadtmp - -# LyX -*.lyx~ - -# Kile -*.backup - -# gummi -.*.swp - -# KBibTeX -*~[0-9]* - -# TeXnicCenter -*.tps - -# auto folder when using emacs and auctex -./auto/* -*.el - -# expex forward references with \gathertags -*-tags.tex - -# standalone packages -*.sta - -# Makeindex log files -*.lpz - -# xwatermark package -*.xwm - -# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib -# option is specified. Footnotes are the stored in a file with suffix Notes.bib. -# Uncomment the next line to have this generated file ignored. -#*Notes.bib +package-lock.json +yarn.locknode_modules +dist +out +.DS_Store +.eslintcache +*.log* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..9c6b791 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +out +dist +pnpm-lock.yaml +LICENSE.md +tsconfig.json +tsconfig.*.json diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..35893b3 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,4 @@ +singleQuote: true +semi: false +printWidth: 100 +trailingComma: none diff --git a/README.md b/README.md index 3c5adf2..541978a 100644 --- a/README.md +++ b/README.md @@ -184,9 +184,9 @@ TODO: Document main user flows: TODO: List what developers need installed -- Node.js 18+ / Python 3.9+ / Flutter SDK +- Node.js 18+ - npm / yarn / pnpm -- [Any specific tools or accounts needed] +- Git ### Installation @@ -211,7 +211,9 @@ pnpm install #### 3. Configure Environment Variables(.env.example) -Create a `.env` file in the root directory: +No environment variables are required for local development by default. + +If you add custom integrations later, create a `.env` file in the root directory: ```env # Add your environment variables here @@ -229,9 +231,30 @@ yarn dev pnpm dev ``` -#### 5. Open your Browser +This starts the Electron + Vite development environment and opens the desktop app window. + +#### 5. Run Preview/Production Build + +Preview the built app locally: + +```bash +npm run start +``` + +Create distributable builds: + +```bash +npm run build +npm run build:win +# or +npm run build:mac +# or +npm run build:linux +``` + +#### 6. Launch the App -Navigate to [http://localhost:3000](http://localhost:3000) to see the application. +After running `npm run dev` (or `npm run start`), the Electron desktop app should open automatically. For detailed setup instructions, please refer to our [Installation Guide](./docs/INSTALL_GUIDE.md) (if you have one). diff --git a/electron-builder.yml b/electron-builder.yml new file mode 100644 index 0000000..bcb5a91 --- /dev/null +++ b/electron-builder.yml @@ -0,0 +1,43 @@ +appId: com.electron.app +productName: my-smart-notes +directories: + buildResources: build +files: + - '!**/.vscode/*' + - '!src/*' + - '!electron.vite.config.{js,ts,mjs,cjs}' + - '!{.eslintcache,eslint.config.mjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' + - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' + - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' +asarUnpack: + - resources/** +win: + executableName: my-smart-notes +nsis: + artifactName: ${name}-${version}-setup.${ext} + shortcutName: ${productName} + uninstallDisplayName: ${productName} + createDesktopShortcut: always +mac: + entitlementsInherit: build/entitlements.mac.plist + extendInfo: + - NSCameraUsageDescription: Application requests access to the device's camera. + - NSMicrophoneUsageDescription: Application requests access to the device's microphone. + - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. + - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. + notarize: false +dmg: + artifactName: ${name}-${version}.${ext} +linux: + target: + - AppImage + - snap + - deb + maintainer: electronjs.org + category: Utility +appImage: + artifactName: ${name}-${version}.${ext} +npmRebuild: false +publish: + provider: generic + url: https://example.com/auto-updates diff --git a/electron.vite.config.ts b/electron.vite.config.ts new file mode 100644 index 0000000..80304cd --- /dev/null +++ b/electron.vite.config.ts @@ -0,0 +1,17 @@ +import { resolve } from 'path' +import { defineConfig } from 'electron-vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + main: {}, + preload: {}, + renderer: { + resolve: { + alias: { + '@renderer': resolve('src/renderer/src') + } + }, + plugins: [react(), tailwindcss()] + } +}) diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..aff5d3f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,32 @@ +import { defineConfig } from 'eslint/config' +import tseslint from '@electron-toolkit/eslint-config-ts' +import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier' +import eslintPluginReact from 'eslint-plugin-react' +import eslintPluginReactHooks from 'eslint-plugin-react-hooks' +import eslintPluginReactRefresh from 'eslint-plugin-react-refresh' + +export default defineConfig( + { ignores: ['**/node_modules', '**/dist', '**/out'] }, + tseslint.configs.recommended, + eslintPluginReact.configs.flat.recommended, + eslintPluginReact.configs.flat['jsx-runtime'], + { + settings: { + react: { + version: 'detect' + } + } + }, + { + files: ['**/*.{ts,tsx}'], + plugins: { + 'react-hooks': eslintPluginReactHooks, + 'react-refresh': eslintPluginReactRefresh + }, + rules: { + ...eslintPluginReactHooks.configs.recommended.rules, + ...eslintPluginReactRefresh.configs.vite.rules + } + }, + eslintConfigPrettier +) diff --git a/package.json b/package.json new file mode 100644 index 0000000..ef0268d --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "my-smart-notes", + "version": "1.0.0", + "description": "An Electron application with React and TypeScript", + "main": "./out/main/index.js", + "author": "example.com", + "homepage": "https://electron-vite.org", + "scripts": { + "format": "prettier --write .", + "lint": "eslint --cache .", + "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", + "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", + "typecheck": "npm run typecheck:node && npm run typecheck:web", + "start": "electron-vite preview", + "preview": "electron-vite preview", + "dev": "electron-vite dev", + "build": "npm run typecheck && electron-vite build", + "postinstall": "electron-builder install-app-deps", + "build:unpack": "npm run build && electron-builder --dir", + "build:win": "npm run build && electron-builder --win", + "build:mac": "electron-vite build && electron-builder --mac", + "build:linux": "electron-vite build && electron-builder --linux" + }, + "dependencies": { + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0" + }, + "devDependencies": { + "@electron-toolkit/eslint-config-prettier": "^3.0.0", + "@electron-toolkit/eslint-config-ts": "^3.1.0", + "@electron-toolkit/tsconfig": "^2.0.0", + "@tailwindcss/vite": "^4.2.2", + "@types/node": "^22.19.1", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "electron": "^39.2.6", + "electron-builder": "^26.0.12", + "electron-vite": "^5.0.0", + "eslint": "^9.39.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "prettier": "^3.7.4", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3", + "vite": "^7.2.6" + } +} diff --git a/public/stability.svg b/public/stability.svg deleted file mode 100644 index cd2d3a7..0000000 --- a/public/stability.svg +++ /dev/null @@ -1,14 +0,0 @@ - - diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000..cf9e8b2 Binary files /dev/null and b/resources/icon.png differ diff --git a/src/main/index.ts b/src/main/index.ts new file mode 100644 index 0000000..06e06b4 --- /dev/null +++ b/src/main/index.ts @@ -0,0 +1,74 @@ +import { app, shell, BrowserWindow, ipcMain } from 'electron' +import { join } from 'path' +import { electronApp, optimizer, is } from '@electron-toolkit/utils' +import icon from '../../resources/icon.png?asset' + +function createWindow(): void { + // Create the browser window. + const mainWindow = new BrowserWindow({ + width: 900, + height: 670, + show: false, + autoHideMenuBar: true, + ...(process.platform === 'linux' ? { icon } : {}), + webPreferences: { + preload: join(__dirname, '../preload/index.js'), + sandbox: false + } + }) + + mainWindow.on('ready-to-show', () => { + mainWindow.show() + }) + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url) + return { action: 'deny' } + }) + + // HMR for renderer base on electron-vite cli. + // Load the remote URL for development or the local html file for production. + if (is.dev && process.env['ELECTRON_RENDERER_URL']) { + mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) + } else { + mainWindow.loadFile(join(__dirname, '../renderer/index.html')) + } +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(() => { + // Set app user model id for windows + electronApp.setAppUserModelId('com.electron') + + // Default open or close DevTools by F12 in development + // and ignore CommandOrControl + R in production. + // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils + app.on('browser-window-created', (_, window) => { + optimizer.watchWindowShortcuts(window) + }) + + // IPC test + ipcMain.on('ping', () => console.log('pong')) + + createWindow() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts new file mode 100644 index 0000000..a153669 --- /dev/null +++ b/src/preload/index.d.ts @@ -0,0 +1,8 @@ +import { ElectronAPI } from '@electron-toolkit/preload' + +declare global { + interface Window { + electron: ElectronAPI + api: unknown + } +} diff --git a/src/preload/index.ts b/src/preload/index.ts new file mode 100644 index 0000000..2d18524 --- /dev/null +++ b/src/preload/index.ts @@ -0,0 +1,22 @@ +import { contextBridge } from 'electron' +import { electronAPI } from '@electron-toolkit/preload' + +// Custom APIs for renderer +const api = {} + +// Use `contextBridge` APIs to expose Electron APIs to +// renderer only if context isolation is enabled, otherwise +// just add to the DOM global. +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld('electron', electronAPI) + contextBridge.exposeInMainWorld('api', api) + } catch (error) { + console.error(error) + } +} else { + // @ts-ignore (define in dts) + window.electron = electronAPI + // @ts-ignore (define in dts) + window.api = api +} diff --git a/src/renderer/index.html b/src/renderer/index.html new file mode 100644 index 0000000..e198e05 --- /dev/null +++ b/src/renderer/index.html @@ -0,0 +1,17 @@ + + +
+ +
+ Please try pressing F12 to open the devTool
+