A local-first note taking app
0

Configure Feed

Select the types of activity you want to include in your feed.

Add React

Ethan Graf (May 5, 2026, 8:11 PM EDT) 896bcbeb afa0c657

+627 -41
+4
.gitignore
··· 90 90 91 91 # Electron-Forge 92 92 out/ 93 + 94 + # VSCode settings 95 + .vscode 96 + .vscode
+3 -4
index.html
··· 2 2 <html> 3 3 <head> 4 4 <meta charset="UTF-8" /> 5 - <title>Hello World!</title> 5 + <title>textile</title> 6 6 </head> 7 7 <body> 8 - <h1>💖 Hello World!</h1> 9 - <p>Welcome to your Electron application.</p> 10 - <script type="module" src="/src/renderer.ts"></script> 8 + <div id="root"></div> 9 + <script type="module" src="/src/renderer.tsx"></script> 11 10 </body> 12 11 </html>
+533 -1
package-lock.json
··· 9 9 "version": "1.0.0", 10 10 "license": "MIT", 11 11 "dependencies": { 12 - "electron-squirrel-startup": "^1.0.1" 12 + "electron-squirrel-startup": "^1.0.1", 13 + "react": "^19.2.5", 14 + "react-dom": "^19.2.5", 15 + "react-router-dom": "^7.15.0" 13 16 }, 14 17 "devDependencies": { 15 18 "@electron-forge/cli": "^7.11.1", ··· 21 24 "@electron-forge/plugin-fuses": "^7.11.1", 22 25 "@electron-forge/plugin-vite": "^7.11.1", 23 26 "@electron/fuses": "^1.8.0", 27 + "@tailwindcss/vite": "^4.2.4", 24 28 "@types/electron-squirrel-startup": "^1.0.2", 29 + "@types/react": "^19.2.14", 30 + "@types/react-dom": "^19.2.3", 25 31 "@typescript-eslint/eslint-plugin": "^8.59.2", 26 32 "@typescript-eslint/parser": "^8.59.2", 33 + "@vitejs/plugin-react": "^6.0.1", 27 34 "electron": "41.5.0", 28 35 "eslint": "^8.57.1", 29 36 "eslint-config-prettier": "^10.1.8", 30 37 "eslint-import-resolver-typescript": "^4.4.4", 31 38 "eslint-plugin-import": "^2.32.0", 32 39 "prettier": "^3.8.3", 40 + "prettier-plugin-tailwindcss": "^0.8.0", 41 + "tailwindcss": "^4.2.4", 33 42 "typescript": "~6.0.3", 34 43 "vite": "^8.0.10" 35 44 } ··· 1428 1437 "@jridgewell/trace-mapping": "^0.3.24" 1429 1438 } 1430 1439 }, 1440 + "node_modules/@jridgewell/remapping": { 1441 + "version": "2.3.5", 1442 + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", 1443 + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", 1444 + "dev": true, 1445 + "license": "MIT", 1446 + "dependencies": { 1447 + "@jridgewell/gen-mapping": "^0.3.5", 1448 + "@jridgewell/trace-mapping": "^0.3.24" 1449 + } 1450 + }, 1431 1451 "node_modules/@jridgewell/resolve-uri": { 1432 1452 "version": "3.1.2", 1433 1453 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", ··· 1912 1932 "node": ">=10" 1913 1933 } 1914 1934 }, 1935 + "node_modules/@tailwindcss/node": { 1936 + "version": "4.2.4", 1937 + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz", 1938 + "integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==", 1939 + "dev": true, 1940 + "license": "MIT", 1941 + "dependencies": { 1942 + "@jridgewell/remapping": "^2.3.5", 1943 + "enhanced-resolve": "^5.19.0", 1944 + "jiti": "^2.6.1", 1945 + "lightningcss": "1.32.0", 1946 + "magic-string": "^0.30.21", 1947 + "source-map-js": "^1.2.1", 1948 + "tailwindcss": "4.2.4" 1949 + } 1950 + }, 1951 + "node_modules/@tailwindcss/oxide": { 1952 + "version": "4.2.4", 1953 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz", 1954 + "integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==", 1955 + "dev": true, 1956 + "license": "MIT", 1957 + "engines": { 1958 + "node": ">= 20" 1959 + }, 1960 + "optionalDependencies": { 1961 + "@tailwindcss/oxide-android-arm64": "4.2.4", 1962 + "@tailwindcss/oxide-darwin-arm64": "4.2.4", 1963 + "@tailwindcss/oxide-darwin-x64": "4.2.4", 1964 + "@tailwindcss/oxide-freebsd-x64": "4.2.4", 1965 + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4", 1966 + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4", 1967 + "@tailwindcss/oxide-linux-arm64-musl": "4.2.4", 1968 + "@tailwindcss/oxide-linux-x64-gnu": "4.2.4", 1969 + "@tailwindcss/oxide-linux-x64-musl": "4.2.4", 1970 + "@tailwindcss/oxide-wasm32-wasi": "4.2.4", 1971 + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4", 1972 + "@tailwindcss/oxide-win32-x64-msvc": "4.2.4" 1973 + } 1974 + }, 1975 + "node_modules/@tailwindcss/oxide-android-arm64": { 1976 + "version": "4.2.4", 1977 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz", 1978 + "integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==", 1979 + "cpu": [ 1980 + "arm64" 1981 + ], 1982 + "dev": true, 1983 + "license": "MIT", 1984 + "optional": true, 1985 + "os": [ 1986 + "android" 1987 + ], 1988 + "engines": { 1989 + "node": ">= 20" 1990 + } 1991 + }, 1992 + "node_modules/@tailwindcss/oxide-darwin-arm64": { 1993 + "version": "4.2.4", 1994 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.4.tgz", 1995 + "integrity": "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==", 1996 + "cpu": [ 1997 + "arm64" 1998 + ], 1999 + "dev": true, 2000 + "license": "MIT", 2001 + "optional": true, 2002 + "os": [ 2003 + "darwin" 2004 + ], 2005 + "engines": { 2006 + "node": ">= 20" 2007 + } 2008 + }, 2009 + "node_modules/@tailwindcss/oxide-darwin-x64": { 2010 + "version": "4.2.4", 2011 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.4.tgz", 2012 + "integrity": "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==", 2013 + "cpu": [ 2014 + "x64" 2015 + ], 2016 + "dev": true, 2017 + "license": "MIT", 2018 + "optional": true, 2019 + "os": [ 2020 + "darwin" 2021 + ], 2022 + "engines": { 2023 + "node": ">= 20" 2024 + } 2025 + }, 2026 + "node_modules/@tailwindcss/oxide-freebsd-x64": { 2027 + "version": "4.2.4", 2028 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.4.tgz", 2029 + "integrity": "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==", 2030 + "cpu": [ 2031 + "x64" 2032 + ], 2033 + "dev": true, 2034 + "license": "MIT", 2035 + "optional": true, 2036 + "os": [ 2037 + "freebsd" 2038 + ], 2039 + "engines": { 2040 + "node": ">= 20" 2041 + } 2042 + }, 2043 + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { 2044 + "version": "4.2.4", 2045 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.4.tgz", 2046 + "integrity": "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==", 2047 + "cpu": [ 2048 + "arm" 2049 + ], 2050 + "dev": true, 2051 + "license": "MIT", 2052 + "optional": true, 2053 + "os": [ 2054 + "linux" 2055 + ], 2056 + "engines": { 2057 + "node": ">= 20" 2058 + } 2059 + }, 2060 + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { 2061 + "version": "4.2.4", 2062 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.4.tgz", 2063 + "integrity": "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==", 2064 + "cpu": [ 2065 + "arm64" 2066 + ], 2067 + "dev": true, 2068 + "license": "MIT", 2069 + "optional": true, 2070 + "os": [ 2071 + "linux" 2072 + ], 2073 + "engines": { 2074 + "node": ">= 20" 2075 + } 2076 + }, 2077 + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { 2078 + "version": "4.2.4", 2079 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.4.tgz", 2080 + "integrity": "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==", 2081 + "cpu": [ 2082 + "arm64" 2083 + ], 2084 + "dev": true, 2085 + "license": "MIT", 2086 + "optional": true, 2087 + "os": [ 2088 + "linux" 2089 + ], 2090 + "engines": { 2091 + "node": ">= 20" 2092 + } 2093 + }, 2094 + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { 2095 + "version": "4.2.4", 2096 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.4.tgz", 2097 + "integrity": "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==", 2098 + "cpu": [ 2099 + "x64" 2100 + ], 2101 + "dev": true, 2102 + "license": "MIT", 2103 + "optional": true, 2104 + "os": [ 2105 + "linux" 2106 + ], 2107 + "engines": { 2108 + "node": ">= 20" 2109 + } 2110 + }, 2111 + "node_modules/@tailwindcss/oxide-linux-x64-musl": { 2112 + "version": "4.2.4", 2113 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.4.tgz", 2114 + "integrity": "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==", 2115 + "cpu": [ 2116 + "x64" 2117 + ], 2118 + "dev": true, 2119 + "license": "MIT", 2120 + "optional": true, 2121 + "os": [ 2122 + "linux" 2123 + ], 2124 + "engines": { 2125 + "node": ">= 20" 2126 + } 2127 + }, 2128 + "node_modules/@tailwindcss/oxide-wasm32-wasi": { 2129 + "version": "4.2.4", 2130 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.4.tgz", 2131 + "integrity": "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==", 2132 + "bundleDependencies": [ 2133 + "@napi-rs/wasm-runtime", 2134 + "@emnapi/core", 2135 + "@emnapi/runtime", 2136 + "@tybys/wasm-util", 2137 + "@emnapi/wasi-threads", 2138 + "tslib" 2139 + ], 2140 + "cpu": [ 2141 + "wasm32" 2142 + ], 2143 + "dev": true, 2144 + "license": "MIT", 2145 + "optional": true, 2146 + "dependencies": { 2147 + "@emnapi/core": "^1.8.1", 2148 + "@emnapi/runtime": "^1.8.1", 2149 + "@emnapi/wasi-threads": "^1.1.0", 2150 + "@napi-rs/wasm-runtime": "^1.1.1", 2151 + "@tybys/wasm-util": "^0.10.1", 2152 + "tslib": "^2.8.1" 2153 + }, 2154 + "engines": { 2155 + "node": ">=14.0.0" 2156 + } 2157 + }, 2158 + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { 2159 + "version": "4.2.4", 2160 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz", 2161 + "integrity": "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==", 2162 + "cpu": [ 2163 + "arm64" 2164 + ], 2165 + "dev": true, 2166 + "license": "MIT", 2167 + "optional": true, 2168 + "os": [ 2169 + "win32" 2170 + ], 2171 + "engines": { 2172 + "node": ">= 20" 2173 + } 2174 + }, 2175 + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { 2176 + "version": "4.2.4", 2177 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.4.tgz", 2178 + "integrity": "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==", 2179 + "cpu": [ 2180 + "x64" 2181 + ], 2182 + "dev": true, 2183 + "license": "MIT", 2184 + "optional": true, 2185 + "os": [ 2186 + "win32" 2187 + ], 2188 + "engines": { 2189 + "node": ">= 20" 2190 + } 2191 + }, 2192 + "node_modules/@tailwindcss/vite": { 2193 + "version": "4.2.4", 2194 + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.4.tgz", 2195 + "integrity": "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==", 2196 + "dev": true, 2197 + "license": "MIT", 2198 + "dependencies": { 2199 + "@tailwindcss/node": "4.2.4", 2200 + "@tailwindcss/oxide": "4.2.4", 2201 + "tailwindcss": "4.2.4" 2202 + }, 2203 + "peerDependencies": { 2204 + "vite": "^5.2.0 || ^6 || ^7 || ^8" 2205 + } 2206 + }, 1915 2207 "node_modules/@tootallnate/once": { 1916 2208 "version": "2.0.1", 1917 2209 "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", ··· 2042 2334 "license": "MIT", 2043 2335 "dependencies": { 2044 2336 "undici-types": "~7.19.0" 2337 + } 2338 + }, 2339 + "node_modules/@types/react": { 2340 + "version": "19.2.14", 2341 + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", 2342 + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", 2343 + "dev": true, 2344 + "license": "MIT", 2345 + "dependencies": { 2346 + "csstype": "^3.2.2" 2347 + } 2348 + }, 2349 + "node_modules/@types/react-dom": { 2350 + "version": "19.2.3", 2351 + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", 2352 + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", 2353 + "dev": true, 2354 + "license": "MIT", 2355 + "peerDependencies": { 2356 + "@types/react": "^19.2.0" 2045 2357 } 2046 2358 }, 2047 2359 "node_modules/@types/responselike": { ··· 2642 2954 "os": [ 2643 2955 "win32" 2644 2956 ] 2957 + }, 2958 + "node_modules/@vitejs/plugin-react": { 2959 + "version": "6.0.1", 2960 + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", 2961 + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", 2962 + "dev": true, 2963 + "license": "MIT", 2964 + "dependencies": { 2965 + "@rolldown/pluginutils": "1.0.0-rc.7" 2966 + }, 2967 + "engines": { 2968 + "node": "^20.19.0 || >=22.12.0" 2969 + }, 2970 + "peerDependencies": { 2971 + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", 2972 + "babel-plugin-react-compiler": "^1.0.0", 2973 + "vite": "^8.0.0" 2974 + }, 2975 + "peerDependenciesMeta": { 2976 + "@rolldown/plugin-babel": { 2977 + "optional": true 2978 + }, 2979 + "babel-plugin-react-compiler": { 2980 + "optional": true 2981 + } 2982 + } 2983 + }, 2984 + "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { 2985 + "version": "1.0.0-rc.7", 2986 + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", 2987 + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", 2988 + "dev": true, 2989 + "license": "MIT" 2645 2990 }, 2646 2991 "node_modules/@vscode/sudo-prompt": { 2647 2992 "version": "9.3.2", ··· 3812 4157 "dev": true, 3813 4158 "license": "MIT" 3814 4159 }, 4160 + "node_modules/cookie": { 4161 + "version": "1.1.1", 4162 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", 4163 + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", 4164 + "license": "MIT", 4165 + "engines": { 4166 + "node": ">=18" 4167 + }, 4168 + "funding": { 4169 + "type": "opencollective", 4170 + "url": "https://opencollective.com/express" 4171 + } 4172 + }, 3815 4173 "node_modules/cross-dirname": { 3816 4174 "version": "0.1.0", 3817 4175 "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", ··· 3857 4215 "engines": { 3858 4216 "node": ">=12.10" 3859 4217 } 4218 + }, 4219 + "node_modules/csstype": { 4220 + "version": "3.2.3", 4221 + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", 4222 + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", 4223 + "dev": true, 4224 + "license": "MIT" 3860 4225 }, 3861 4226 "node_modules/data-view-buffer": { 3862 4227 "version": "1.0.2", ··· 7563 7928 "node": ">=12" 7564 7929 } 7565 7930 }, 7931 + "node_modules/magic-string": { 7932 + "version": "0.30.21", 7933 + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", 7934 + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", 7935 + "dev": true, 7936 + "license": "MIT", 7937 + "dependencies": { 7938 + "@jridgewell/sourcemap-codec": "^1.5.5" 7939 + } 7940 + }, 7566 7941 "node_modules/make-fetch-happen": { 7567 7942 "version": "10.2.1", 7568 7943 "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", ··· 8643 9018 "url": "https://github.com/prettier/prettier?sponsor=1" 8644 9019 } 8645 9020 }, 9021 + "node_modules/prettier-plugin-tailwindcss": { 9022 + "version": "0.8.0", 9023 + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.8.0.tgz", 9024 + "integrity": "sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g==", 9025 + "dev": true, 9026 + "license": "MIT", 9027 + "engines": { 9028 + "node": ">=20.19" 9029 + }, 9030 + "peerDependencies": { 9031 + "@ianvs/prettier-plugin-sort-imports": "*", 9032 + "@prettier/plugin-hermes": "*", 9033 + "@prettier/plugin-oxc": "*", 9034 + "@prettier/plugin-pug": "*", 9035 + "@shopify/prettier-plugin-liquid": "*", 9036 + "@trivago/prettier-plugin-sort-imports": "*", 9037 + "@zackad/prettier-plugin-twig": "*", 9038 + "prettier": "^3.0", 9039 + "prettier-plugin-astro": "*", 9040 + "prettier-plugin-css-order": "*", 9041 + "prettier-plugin-jsdoc": "*", 9042 + "prettier-plugin-marko": "*", 9043 + "prettier-plugin-multiline-arrays": "*", 9044 + "prettier-plugin-organize-attributes": "*", 9045 + "prettier-plugin-organize-imports": "*", 9046 + "prettier-plugin-sort-imports": "*", 9047 + "prettier-plugin-svelte": "*" 9048 + }, 9049 + "peerDependenciesMeta": { 9050 + "@ianvs/prettier-plugin-sort-imports": { 9051 + "optional": true 9052 + }, 9053 + "@prettier/plugin-hermes": { 9054 + "optional": true 9055 + }, 9056 + "@prettier/plugin-oxc": { 9057 + "optional": true 9058 + }, 9059 + "@prettier/plugin-pug": { 9060 + "optional": true 9061 + }, 9062 + "@shopify/prettier-plugin-liquid": { 9063 + "optional": true 9064 + }, 9065 + "@trivago/prettier-plugin-sort-imports": { 9066 + "optional": true 9067 + }, 9068 + "@zackad/prettier-plugin-twig": { 9069 + "optional": true 9070 + }, 9071 + "prettier-plugin-astro": { 9072 + "optional": true 9073 + }, 9074 + "prettier-plugin-css-order": { 9075 + "optional": true 9076 + }, 9077 + "prettier-plugin-jsdoc": { 9078 + "optional": true 9079 + }, 9080 + "prettier-plugin-marko": { 9081 + "optional": true 9082 + }, 9083 + "prettier-plugin-multiline-arrays": { 9084 + "optional": true 9085 + }, 9086 + "prettier-plugin-organize-attributes": { 9087 + "optional": true 9088 + }, 9089 + "prettier-plugin-organize-imports": { 9090 + "optional": true 9091 + }, 9092 + "prettier-plugin-sort-imports": { 9093 + "optional": true 9094 + }, 9095 + "prettier-plugin-svelte": { 9096 + "optional": true 9097 + } 9098 + } 9099 + }, 8646 9100 "node_modules/proc-log": { 8647 9101 "version": "2.0.1", 8648 9102 "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", ··· 8739 9193 "url": "https://github.com/sponsors/sindresorhus" 8740 9194 } 8741 9195 }, 9196 + "node_modules/react": { 9197 + "version": "19.2.5", 9198 + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", 9199 + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", 9200 + "license": "MIT", 9201 + "engines": { 9202 + "node": ">=0.10.0" 9203 + } 9204 + }, 9205 + "node_modules/react-dom": { 9206 + "version": "19.2.5", 9207 + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", 9208 + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", 9209 + "license": "MIT", 9210 + "dependencies": { 9211 + "scheduler": "^0.27.0" 9212 + }, 9213 + "peerDependencies": { 9214 + "react": "^19.2.5" 9215 + } 9216 + }, 9217 + "node_modules/react-router": { 9218 + "version": "7.15.0", 9219 + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.15.0.tgz", 9220 + "integrity": "sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==", 9221 + "license": "MIT", 9222 + "dependencies": { 9223 + "cookie": "^1.0.1", 9224 + "set-cookie-parser": "^2.6.0" 9225 + }, 9226 + "engines": { 9227 + "node": ">=20.0.0" 9228 + }, 9229 + "peerDependencies": { 9230 + "react": ">=18", 9231 + "react-dom": ">=18" 9232 + }, 9233 + "peerDependenciesMeta": { 9234 + "react-dom": { 9235 + "optional": true 9236 + } 9237 + } 9238 + }, 9239 + "node_modules/react-router-dom": { 9240 + "version": "7.15.0", 9241 + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.15.0.tgz", 9242 + "integrity": "sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==", 9243 + "license": "MIT", 9244 + "dependencies": { 9245 + "react-router": "7.15.0" 9246 + }, 9247 + "engines": { 9248 + "node": ">=20.0.0" 9249 + }, 9250 + "peerDependencies": { 9251 + "react": ">=18", 9252 + "react-dom": ">=18" 9253 + } 9254 + }, 8742 9255 "node_modules/read-binary-file-arch": { 8743 9256 "version": "1.0.6", 8744 9257 "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", ··· 9251 9764 "dev": true, 9252 9765 "license": "MIT" 9253 9766 }, 9767 + "node_modules/scheduler": { 9768 + "version": "0.27.0", 9769 + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", 9770 + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", 9771 + "license": "MIT" 9772 + }, 9254 9773 "node_modules/schema-utils": { 9255 9774 "version": "4.3.3", 9256 9775 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", ··· 9359 9878 "funding": { 9360 9879 "url": "https://github.com/sponsors/sindresorhus" 9361 9880 } 9881 + }, 9882 + "node_modules/set-cookie-parser": { 9883 + "version": "2.7.2", 9884 + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", 9885 + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", 9886 + "license": "MIT" 9362 9887 }, 9363 9888 "node_modules/set-function-length": { 9364 9889 "version": "1.2.2", ··· 9921 10446 "funding": { 9922 10447 "url": "https://github.com/sponsors/ljharb" 9923 10448 } 10449 + }, 10450 + "node_modules/tailwindcss": { 10451 + "version": "4.2.4", 10452 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz", 10453 + "integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==", 10454 + "dev": true, 10455 + "license": "MIT" 9924 10456 }, 9925 10457 "node_modules/tapable": { 9926 10458 "version": "2.3.3",
+7 -1
package.json
··· 28 28 "@electron-forge/plugin-vite": "^7.11.1", 29 29 "@electron/fuses": "^1.8.0", 30 30 "@types/electron-squirrel-startup": "^1.0.2", 31 + "@types/react": "^19.2.14", 32 + "@types/react-dom": "^19.2.3", 31 33 "@typescript-eslint/eslint-plugin": "^8.59.2", 32 34 "@typescript-eslint/parser": "^8.59.2", 35 + "@vitejs/plugin-react": "^6.0.1", 33 36 "electron": "41.5.0", 34 37 "eslint": "^8.57.1", 35 38 "eslint-config-prettier": "^10.1.8", ··· 40 43 "vite": "^8.0.10" 41 44 }, 42 45 "dependencies": { 43 - "electron-squirrel-startup": "^1.0.1" 46 + "electron-squirrel-startup": "^1.0.1", 47 + "react": "^19.2.5", 48 + "react-dom": "^19.2.5", 49 + "react-router-dom": "^7.15.0" 44 50 } 45 51 }
+24
src/App.tsx
··· 1 + import { MemoryRouter, NavLink, Route, Routes } from 'react-router-dom'; 2 + import { AboutPage } from './pages/AboutPage'; 3 + import { HomePage } from './pages/HomePage'; 4 + 5 + export default function App() { 6 + return ( 7 + <MemoryRouter initialEntries={['/']}> 8 + <header> 9 + <nav> 10 + <NavLink to="/" end> 11 + Home 12 + </NavLink> 13 + <NavLink to="/about">About</NavLink> 14 + </nav> 15 + </header> 16 + <main> 17 + <Routes> 18 + <Route path="/" element={<HomePage />} /> 19 + <Route path="/about" element={<AboutPage />} /> 20 + </Routes> 21 + </main> 22 + </MemoryRouter> 23 + ); 24 + }
+16
src/index.css
··· 6 6 max-width: 38rem; 7 7 padding: 2rem; 8 8 } 9 + 10 + nav { 11 + display: flex; 12 + gap: 1rem; 13 + margin-bottom: 1.5rem; 14 + } 15 + 16 + nav a { 17 + color: inherit; 18 + text-decoration: none; 19 + } 20 + 21 + nav a.active { 22 + font-weight: 600; 23 + text-decoration: underline; 24 + }
+10
src/pages/AboutPage.tsx
··· 1 + export function AboutPage() { 2 + return ( 3 + <section> 4 + <h1>About</h1> 5 + <p> 6 + Routes use MemoryRouter so navigation does not depend on a server URL. 7 + </p> 8 + </section> 9 + ); 10 + }
+8
src/pages/HomePage.tsx
··· 1 + export function HomePage() { 2 + return ( 3 + <section> 4 + <h1>Home</h1> 5 + <p>Renderer is running React inside Electron.</p> 6 + </section> 7 + ); 8 + }
-33
src/renderer.ts
··· 1 - /** 2 - * This file will automatically be loaded by vite and run in the "renderer" context. 3 - * To learn more about the differences between the "main" and the "renderer" context in 4 - * Electron, visit: 5 - * 6 - * https://electronjs.org/docs/tutorial/process-model 7 - * 8 - * By default, Node.js integration in this file is disabled. When enabling Node.js integration 9 - * in a renderer process, please be aware of potential security implications. You can read 10 - * more about security risks here: 11 - * 12 - * https://electronjs.org/docs/tutorial/security 13 - * 14 - * To enable Node.js integration in this file, open up `main.ts` and enable the `nodeIntegration` 15 - * flag: 16 - * 17 - * ``` 18 - * // Create the browser window. 19 - * mainWindow = new BrowserWindow({ 20 - * width: 800, 21 - * height: 600, 22 - * webPreferences: { 23 - * nodeIntegration: true 24 - * } 25 - * }); 26 - * ``` 27 - */ 28 - 29 - import './index.css'; 30 - 31 - console.log( 32 - '👋 This message is being logged by "renderer.ts", included via Vite', 33 - );
+15
src/renderer.tsx
··· 1 + import { StrictMode } from 'react'; 2 + import { createRoot } from 'react-dom/client'; 3 + import App from './App'; 4 + import './index.css'; 5 + 6 + const rootEl = document.getElementById('root'); 7 + if (!rootEl) { 8 + throw new Error('Missing #root element'); 9 + } 10 + 11 + createRoot(rootEl).render( 12 + <StrictMode> 13 + <App /> 14 + </StrictMode>, 15 + );
+3 -1
tsconfig.json
··· 1 1 { 2 2 "compilerOptions": { 3 3 "target": "ESNext", 4 + "lib": ["ESNext", "DOM", "DOM.Iterable"], 4 5 "module": "ESNext", 5 6 "allowJs": true, 6 7 "skipLibCheck": true, ··· 9 10 "sourceMap": true, 10 11 "outDir": "dist", 11 12 "moduleResolution": "Bundler", 12 - "resolveJsonModule": true 13 + "resolveJsonModule": true, 14 + "jsx": "react-jsx" 13 15 } 14 16 }
+4 -1
vite.renderer.config.ts
··· 1 1 import { defineConfig } from 'vite'; 2 + import react from '@vitejs/plugin-react'; 2 3 3 4 // https://vitejs.dev/config 4 - export default defineConfig({}); 5 + export default defineConfig({ 6 + plugins: [react()], 7 + });