├── .env.example ├── .github └── workflows │ └── desktop-publish.yml ├── .gitignore ├── .npmrc ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── apps ├── desktop │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── components.json │ ├── index.html │ ├── package.json │ ├── postcss.config.mjs │ ├── public │ │ ├── tauri.svg │ │ └── vite.svg │ ├── src-tauri │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── capabilities │ │ │ └── default.json │ │ ├── gen │ │ │ └── apple │ │ │ │ ├── .gitignore │ │ │ │ ├── Assets.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ │ ├── AppIcon-29x29@1x.png │ │ │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ │ │ ├── AppIcon-29x29@2x.png │ │ │ │ │ ├── AppIcon-29x29@3x.png │ │ │ │ │ ├── AppIcon-40x40@1x.png │ │ │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ │ │ ├── AppIcon-40x40@2x.png │ │ │ │ │ ├── AppIcon-40x40@3x.png │ │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ │ ├── AppIcon-60x60@2x.png │ │ │ │ │ ├── AppIcon-60x60@3x.png │ │ │ │ │ ├── AppIcon-76x76@1x.png │ │ │ │ │ ├── AppIcon-76x76@2x.png │ │ │ │ │ ├── AppIcon-83.5x83.5@2x.png │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ │ ├── ExportOptions.plist │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ ├── Podfile │ │ │ │ ├── Sources │ │ │ │ └── penx-desktop │ │ │ │ │ ├── bindings │ │ │ │ │ └── bindings.h │ │ │ │ │ └── main.mm │ │ │ │ ├── penx-desktop.xcodeproj │ │ │ │ ├── project.pbxproj │ │ │ │ ├── project.xcworkspace │ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ │ └── xcshareddata │ │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ │ └── xcshareddata │ │ │ │ │ └── xcschemes │ │ │ │ │ └── penx-desktop_iOS.xcscheme │ │ │ │ ├── penx-desktop_iOS │ │ │ │ ├── Info.plist │ │ │ │ └── penx-desktop_iOS.entitlements │ │ │ │ └── project.yml │ │ ├── icons │ │ │ ├── 128x128.png │ │ │ ├── 128x128@2x.png │ │ │ ├── 32x32.png │ │ │ ├── Square107x107Logo.png │ │ │ ├── Square142x142Logo.png │ │ │ ├── Square150x150Logo.png │ │ │ ├── Square284x284Logo.png │ │ │ ├── Square30x30Logo.png │ │ │ ├── Square310x310Logo.png │ │ │ ├── Square44x44Logo.png │ │ │ ├── Square71x71Logo.png │ │ │ ├── Square89x89Logo.png │ │ │ ├── StoreLogo.png │ │ │ ├── android │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ ├── icon.png │ │ │ └── ios │ │ │ │ ├── AppIcon-20x20@1x.png │ │ │ │ ├── AppIcon-20x20@2x-1.png │ │ │ │ ├── AppIcon-20x20@2x.png │ │ │ │ ├── AppIcon-20x20@3x.png │ │ │ │ ├── AppIcon-29x29@1x.png │ │ │ │ ├── AppIcon-29x29@2x-1.png │ │ │ │ ├── AppIcon-29x29@2x.png │ │ │ │ ├── AppIcon-29x29@3x.png │ │ │ │ ├── AppIcon-40x40@1x.png │ │ │ │ ├── AppIcon-40x40@2x-1.png │ │ │ │ ├── AppIcon-40x40@2x.png │ │ │ │ ├── AppIcon-40x40@3x.png │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ ├── AppIcon-60x60@2x.png │ │ │ │ ├── AppIcon-60x60@3x.png │ │ │ │ ├── AppIcon-76x76@1x.png │ │ │ │ ├── AppIcon-76x76@2x.png │ │ │ │ └── AppIcon-83.5x83.5@2x.png │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── main.rs │ │ │ └── server.rs │ │ └── tauri.conf.json │ ├── src │ │ ├── App.tsx │ │ ├── Updater.ts │ │ ├── assets │ │ │ └── react.svg │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── extension │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── assets │ │ └── react.svg │ ├── components.json │ ├── components │ │ ├── Login.tsx │ │ ├── Logo.tsx │ │ ├── ThemeProvider.tsx │ │ ├── command-components.tsx │ │ ├── content │ │ │ ├── AddBookmark │ │ │ │ ├── AddBookmark.tsx │ │ │ │ ├── AddBookmarkForm.tsx │ │ │ │ └── Tags.tsx │ │ │ ├── ContentView.tsx │ │ │ ├── QuickAddEditor │ │ │ │ └── QuickAddEditor.tsx │ │ │ ├── Thumbnail.tsx │ │ │ ├── area-selector │ │ │ │ ├── common │ │ │ │ │ └── transform-dom.ts │ │ │ │ └── index.tsx │ │ │ ├── constants.ts │ │ │ ├── content.module.scss │ │ │ ├── hooks.ts │ │ │ ├── hooks │ │ │ │ ├── useAppType.ts │ │ │ │ └── useNote.ts │ │ │ ├── screen-shot │ │ │ │ ├── common │ │ │ │ │ └── screen-shot.ts │ │ │ │ ├── drag-line.tsx │ │ │ │ └── index.tsx │ │ │ └── stores │ │ │ │ ├── text.store.ts │ │ │ │ └── thumbnail.store.ts │ │ ├── icons │ │ │ ├── IconGoogle.tsx │ │ │ ├── loading-circle.tsx │ │ │ ├── loading-dots.tsx │ │ │ └── magic.tsx │ │ └── popup │ │ │ ├── FeatureEntry.tsx │ │ │ └── PopupContent.tsx │ ├── entrypoints │ │ ├── background.ts │ │ ├── content │ │ │ ├── App.tsx │ │ │ ├── index.tsx │ │ │ └── style.css │ │ ├── newtab │ │ │ ├── App.tsx │ │ │ ├── TabContent.tsx │ │ │ ├── appRouterI18n.ts │ │ │ ├── index.html │ │ │ ├── lingui.config.ts │ │ │ ├── main.tsx │ │ │ └── style.css │ │ └── popup │ │ │ ├── App.tsx │ │ │ ├── index.html │ │ │ ├── main.tsx │ │ │ └── style.css │ ├── hooks │ │ ├── useLocalAreas.ts │ │ └── useSession.ts │ ├── lib │ │ ├── api.ts │ │ ├── color-helper.ts │ │ ├── constants.ts │ │ ├── content-handler │ │ │ ├── content-handler.ts │ │ │ ├── index.ts │ │ │ ├── newsletters │ │ │ │ ├── axios-handler.ts │ │ │ │ ├── beehiiv-handler.ts │ │ │ │ ├── bloomberg-newsletter-handler.ts │ │ │ │ ├── convertkit-handler.ts │ │ │ │ ├── cooper-press-handler.ts │ │ │ │ ├── energy-world.ts │ │ │ │ ├── every-io-handler.ts │ │ │ │ ├── generic-handler.ts │ │ │ │ ├── ghost-handler.ts │ │ │ │ ├── golang-handler.ts │ │ │ │ ├── hey-world-handler.ts │ │ │ │ ├── india-times-handler.ts │ │ │ │ ├── morning-brew-handler.ts │ │ │ │ ├── revue-handler.ts │ │ │ │ └── substack-handler.ts │ │ │ └── websites │ │ │ │ ├── apple-news-handler.ts │ │ │ │ ├── ars-technica-handler.ts │ │ │ │ ├── bloomberg-handler.ts │ │ │ │ ├── derstandard-handler.ts │ │ │ │ ├── github-handler.ts │ │ │ │ ├── image-handler.ts │ │ │ │ ├── medium-handler.ts │ │ │ │ ├── pdf-handler.ts │ │ │ │ ├── piped-video-handler.ts │ │ │ │ ├── scrapingBee-handler.ts │ │ │ │ ├── stack-overflow-handler.ts │ │ │ │ ├── t-dot-co-handler.ts │ │ │ │ ├── the-atlantic-handler.ts │ │ │ │ ├── twitter-handler.ts │ │ │ │ ├── weixin-qq-handler.ts │ │ │ │ ├── wikipedia-handler.ts │ │ │ │ ├── wired-handler.ts │ │ │ │ ├── youtube-handler.ts │ │ │ │ └── zhihu-handler.ts │ │ ├── extractErrorMessage.ts │ │ ├── helper.ts │ │ ├── parser.ts │ │ ├── prepare-content.ts │ │ └── utils.ts │ ├── package.json │ ├── public │ │ ├── icon │ │ │ ├── 128.png │ │ │ ├── 16.png │ │ │ ├── 32.png │ │ │ ├── 48.png │ │ │ └── 96.png │ │ └── wxt.svg │ ├── style.css │ ├── tsconfig.json │ └── wxt.config.ts ├── mobile │ ├── .env │ ├── .gitignore │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── capacitor.build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── androidTest │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── getcapacitor │ │ │ │ │ └── myapp │ │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── assets │ │ │ │ │ ├── capacitor.config.json │ │ │ │ │ └── capacitor.plugins.json │ │ │ │ ├── java │ │ │ │ │ └── io │ │ │ │ │ │ └── penx │ │ │ │ │ │ └── app │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── res │ │ │ │ │ ├── drawable-land-hdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-ldpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-mdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-hdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-ldpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-mdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-xhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-xxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-night-xxxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-xhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-xxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-land-xxxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-night │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-hdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-ldpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-mdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-hdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-ldpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-mdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-xhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-xxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-night-xxxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-xhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-xxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-port-xxxhdpi │ │ │ │ │ └── splash.png │ │ │ │ │ ├── drawable-v24 │ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ │ ├── drawable │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ └── splash.png │ │ │ │ │ ├── layout │ │ │ │ │ └── activity_main.xml │ │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-ldpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_background.png │ │ │ │ │ ├── ic_launcher_foreground.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── values │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ │ └── xml │ │ │ │ │ ├── config.xml │ │ │ │ │ └── file_paths.xml │ │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── getcapacitor │ │ │ │ └── myapp │ │ │ │ └── ExampleUnitTest.java │ │ ├── build.gradle │ │ ├── capacitor.settings.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle │ │ └── variables.gradle │ ├── assets │ │ ├── logo-dark.png │ │ ├── logo.png │ │ ├── splash-dark.png │ │ └── splash.png │ ├── capacitor.config.ts │ ├── components.json │ ├── cypress.config.ts │ ├── icons │ │ ├── icon-128.webp │ │ ├── icon-192.webp │ │ ├── icon-256.webp │ │ ├── icon-48.webp │ │ ├── icon-512.webp │ │ ├── icon-72.webp │ │ └── icon-96.webp │ ├── index.html │ ├── ionic.config.json │ ├── ios │ │ ├── .gitignore │ │ └── App │ │ │ ├── App.xcodeproj │ │ │ └── project.pbxproj │ │ │ ├── App.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ ├── App │ │ │ ├── App.entitlements │ │ │ ├── AppDebug.entitlements │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── AppIcon-512@2x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── Splash.imageset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Default@1x~universal~anyany-dark.png │ │ │ │ │ ├── Default@1x~universal~anyany.png │ │ │ │ │ ├── Default@2x~universal~anyany-dark.png │ │ │ │ │ ├── Default@2x~universal~anyany.png │ │ │ │ │ ├── Default@3x~universal~anyany-dark.png │ │ │ │ │ └── Default@3x~universal~anyany.png │ │ │ ├── Base.lproj │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── capacitor.config.json │ │ │ └── config.xml │ │ │ ├── Podfile │ │ │ └── Podfile.lock │ ├── package-lock.json │ ├── package.json │ ├── pnpm-lock.yaml │ ├── postcss.config.mjs │ ├── public │ │ ├── favicon.png │ │ └── manifest.json │ ├── src │ │ ├── App.tsx │ │ ├── components │ │ │ ├── AllStructsHeader.tsx │ │ │ ├── AnimatedJournalInput.tsx │ │ │ ├── AreaList.tsx │ │ │ ├── CreationMenu.tsx │ │ │ ├── Drawer.tsx │ │ │ ├── FixedToolbar.tsx │ │ │ ├── Footer.tsx │ │ │ ├── HomeHeader.tsx │ │ │ ├── Login │ │ │ │ ├── AppleLoginButton.tsx │ │ │ │ ├── EmailLoginButton.tsx │ │ │ │ ├── GoogleLoginButton.tsx │ │ │ │ ├── LoginContent.tsx │ │ │ │ ├── LoginForm.tsx │ │ │ │ ├── PinCodeForm.tsx │ │ │ │ ├── ProfileContent.tsx │ │ │ │ └── RegisterForm.tsx │ │ │ ├── Menu.tsx │ │ │ ├── MobileAddCreationButton.tsx │ │ │ ├── MobileCreation.tsx │ │ │ ├── MobileModeToggle.tsx │ │ │ ├── MobileSearch │ │ │ │ ├── SearchButton.tsx │ │ │ │ └── SearchPanel.tsx │ │ │ ├── MobileTask │ │ │ │ ├── MobileTask.tsx │ │ │ │ └── TaskItem.tsx │ │ │ ├── MoreStructDrawer │ │ │ │ ├── MoreStructDrawer.tsx │ │ │ │ ├── PublishedStructList.tsx │ │ │ │ ├── StructList.tsx │ │ │ │ └── useMoreStructDrawer.tsx │ │ │ ├── NavContext.tsx │ │ │ ├── PlanList.tsx │ │ │ ├── Profile │ │ │ │ ├── AboutMenu.tsx │ │ │ │ ├── JournalLayoutMenu.tsx │ │ │ │ ├── LocaleMenu.tsx │ │ │ │ ├── MenuItem.tsx │ │ │ │ ├── Profile.tsx │ │ │ │ ├── SubscriptionMenu.tsx │ │ │ │ └── ThemeMenu.tsx │ │ │ ├── StructHeader.tsx │ │ │ ├── UpgradeDrawer │ │ │ │ ├── UpgradeContent.tsx │ │ │ │ ├── UpgradeDrawer.tsx │ │ │ │ └── useUpgradeDrawer.tsx │ │ │ ├── VoiceRecorderButton.tsx │ │ │ └── theme-provider.tsx │ │ ├── hooks │ │ │ ├── useHomeTab.ts │ │ │ ├── useKeyboard.ts │ │ │ └── useSidebar.ts │ │ ├── lib │ │ │ ├── activateLocale.ts │ │ │ ├── checkAndRequestPermission.ts │ │ │ ├── constants.ts │ │ │ ├── indexeddbHelder.ts │ │ │ ├── initializeRevenueCat.ts │ │ │ └── utils.ts │ │ ├── main.tsx │ │ ├── pages │ │ │ ├── PageAllStructs.tsx │ │ │ ├── PageCreation.tsx │ │ │ ├── PageEmailLogin.tsx │ │ │ ├── PageHome.tsx │ │ │ ├── PageLogin.tsx │ │ │ ├── PagePlan.tsx │ │ │ ├── PageProfile.tsx │ │ │ ├── PageStruct.tsx │ │ │ ├── PageStructInfo.tsx │ │ │ └── PageWidget.tsx │ │ ├── style.css │ │ ├── theme │ │ │ └── variables.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── web │ ├── .dockerignore │ ├── .env │ ├── .gitignore │ ├── .prettierignore │ ├── README.md │ ├── app │ ├── (editor) │ │ ├── WatchAppEvent.tsx │ │ ├── desktop-login │ │ │ ├── DesktopLogin.tsx │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ └── page.tsx │ ├── fonts │ │ ├── CalSans-SemiBold.otf │ │ ├── GeistMonoVF.woff │ │ ├── GeistVF.woff │ │ └── fonts.ts │ ├── manifest.ts │ ├── opengraph-image.tsx │ └── sitemap.ts │ ├── components.json │ ├── components │ ├── SubscriptionGuideDialog │ │ ├── SubscriptionGuideDialog.tsx │ │ ├── SubscriptionGuideDialogContent.tsx │ │ ├── index.tsx │ │ └── useSubscriptionGuideDialog.tsx │ └── UseCouponCode.tsx │ ├── fonts │ ├── CalSans-SemiBold.otf │ └── Inter-Bold.ttf │ ├── globals.css │ ├── index.d.ts │ ├── lib │ ├── SyncService.ts │ ├── addToIpfs.ts │ ├── aws-ses-client.ts │ ├── calculateSHA256FromFile.ts │ ├── catalogue │ │ ├── CatalogueNode.ts │ │ ├── CatalogueTree.ts │ │ ├── convertToValidHtmlId.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── chat.utils.ts │ ├── color-helper.ts │ ├── compareVersions.ts │ ├── dnd-projection │ │ ├── getProjection.tsx │ │ └── index.ts │ ├── extractErrorMessage.ts │ ├── extractTags.ts │ ├── generateAppleClientSecret.tsx │ ├── getBasePublicClient.ts │ ├── getDashboardPath.ts │ ├── getGoogleUserInfo.ts │ ├── google-drive │ │ ├── GoogleDrive.ts │ │ └── index.ts │ ├── i18n.tsx │ ├── local-session.ts │ ├── queryClient.ts │ ├── redirectTo404.ts │ ├── remark-plugins.tsx │ ├── remark-slate │ │ ├── ast-types.ts │ │ ├── deserialize.ts │ │ ├── index.ts │ │ ├── plugin.ts │ │ └── serialize.ts │ ├── revalidatePath.ts │ ├── serializer │ │ ├── index.ts │ │ ├── isMarkdown.ts │ │ └── markdownToNodes.ts │ ├── setStatusBarColor.tsx │ ├── shared │ │ ├── getConnectionState.ts │ │ ├── index.ts │ │ ├── md5.ts │ │ └── useCopyToClipboard.ts │ ├── slate-to-html.ts │ ├── stripe.ts │ ├── supportLanguages.ts │ ├── sync.ts │ ├── syncPostToHub.ts │ ├── syncSiteToHub.ts │ ├── theme.types.ts │ ├── uploadToGoogleDrive.ts │ ├── uploadthing.ts │ ├── utils.ts │ └── widget │ │ ├── ClientOnly.tsx │ │ ├── OptionTag.tsx │ │ ├── index.ts │ │ └── motion-components.tsx │ ├── next.config.mjs │ ├── package.json │ ├── pages │ └── api │ │ ├── install-github-app.ts │ │ ├── ipfs-upload.ts │ │ └── update-hosted-site-version.ts │ ├── postcss.config.mjs │ ├── public │ ├── empty-state.png │ ├── eth.png │ ├── favicon.ico │ ├── images │ │ ├── apple-touch-icon.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── logo-1024.png │ │ ├── logo-128.png │ │ ├── logo-192.png │ │ ├── logo-512.png │ │ ├── logo.png │ │ ├── screenshots │ │ │ ├── screenshot-1.png │ │ │ ├── screenshot-2.png │ │ │ ├── screenshot-3.png │ │ │ ├── screenshot-4.png │ │ │ └── screenshot-5.png │ │ ├── socials │ │ │ ├── behance.webp │ │ │ ├── buymeacoffee.webp │ │ │ ├── discord.webp │ │ │ ├── dribbble.webp │ │ │ ├── email.webp │ │ │ ├── facebook.webp │ │ │ ├── figma.webp │ │ │ ├── github.webp │ │ │ ├── gumroad.webp │ │ │ ├── image.webp │ │ │ ├── instagram.webp │ │ │ ├── kofi.webp │ │ │ ├── layers.webp │ │ │ ├── link.webp │ │ │ ├── linkedin.webp │ │ │ ├── mastodon.webp │ │ │ ├── medium.webp │ │ │ ├── patreon.webp │ │ │ ├── pinterest.webp │ │ │ ├── producthunt.webp │ │ │ ├── snapchat.webp │ │ │ ├── soundcloud.webp │ │ │ ├── spotify.webp │ │ │ ├── substack.webp │ │ │ ├── telegram.webp │ │ │ ├── threads.webp │ │ │ ├── tiktok.webp │ │ │ ├── twitter.webp │ │ │ └── youtube.webp │ │ ├── web-app-manifest-192x192.png │ │ └── web-app-manifest-512x512.png │ ├── logo.png │ ├── og-image.png │ └── placeholder.png │ └── tsconfig.json ├── lingui.config.ts ├── package.json ├── packages ├── components │ ├── icons.tsx │ ├── index.d.ts │ ├── package.json │ ├── src │ │ ├── AIChat │ │ │ ├── ai │ │ │ │ ├── entitlements.ts │ │ │ │ ├── models.test.ts │ │ │ │ ├── models.ts │ │ │ │ ├── prompts.ts │ │ │ │ ├── providers.ts │ │ │ │ └── tools │ │ │ │ │ ├── create-document.ts │ │ │ │ │ ├── get-weather.ts │ │ │ │ │ ├── request-suggestions.ts │ │ │ │ │ └── update-document.ts │ │ │ ├── artifact-actions.tsx │ │ │ ├── artifact-close-button.tsx │ │ │ ├── artifact-messages.tsx │ │ │ ├── artifact.tsx │ │ │ ├── artifacts │ │ │ │ ├── actions.ts │ │ │ │ ├── code │ │ │ │ │ ├── client.tsx │ │ │ │ │ └── server.ts │ │ │ │ ├── image │ │ │ │ │ ├── client.tsx │ │ │ │ │ └── server.ts │ │ │ │ ├── sheet │ │ │ │ │ ├── client.tsx │ │ │ │ │ └── server.ts │ │ │ │ └── text │ │ │ │ │ ├── client.tsx │ │ │ │ │ └── server.ts │ │ │ ├── chat.tsx │ │ │ ├── code-block.tsx │ │ │ ├── code-editor.tsx │ │ │ ├── console.tsx │ │ │ ├── create-artifact.tsx │ │ │ ├── data-stream-handler.tsx │ │ │ ├── diffview.tsx │ │ │ ├── document-preview.tsx │ │ │ ├── document-skeleton.tsx │ │ │ ├── document.tsx │ │ │ ├── editor │ │ │ │ ├── config.ts │ │ │ │ ├── diff.js │ │ │ │ ├── functions.tsx │ │ │ │ ├── react-renderer.tsx │ │ │ │ └── suggestions.tsx │ │ │ ├── greeting.tsx │ │ │ ├── icons.tsx │ │ │ ├── image-editor.tsx │ │ │ ├── knowledge-source-picker.tsx │ │ │ ├── markdown.tsx │ │ │ ├── message-actions.tsx │ │ │ ├── message-editor.tsx │ │ │ ├── message-reasoning.tsx │ │ │ ├── message.tsx │ │ │ ├── messages.tsx │ │ │ ├── multimodal-input.tsx │ │ │ ├── preview-attachment.tsx │ │ │ ├── provider-selector.tsx │ │ │ ├── sheet-editor.tsx │ │ │ ├── sidebar-history-item.tsx │ │ │ ├── sidebar-history.tsx │ │ │ ├── sidebar-toggle.tsx │ │ │ ├── sidebar-user-nav.tsx │ │ │ ├── submit-button.tsx │ │ │ ├── suggested-actions.tsx │ │ │ ├── suggestion.tsx │ │ │ ├── text-editor.tsx │ │ │ ├── theme-provider.tsx │ │ │ ├── toast.tsx │ │ │ ├── toolbar.tsx │ │ │ ├── use-scroll-to-bottom.ts │ │ │ ├── version-footer.tsx │ │ │ ├── visibility-selector.tsx │ │ │ └── weather.tsx │ │ ├── AISetting │ │ │ ├── icons.tsx │ │ │ ├── knowledge-setting.tsx │ │ │ ├── model-selector.tsx │ │ │ ├── provider-dropdown-menu.tsx │ │ │ ├── provider-editor-dialog.tsx │ │ │ └── provider-setting.tsx │ │ ├── AddCreationButton.tsx │ │ ├── AppProvider │ │ │ ├── AppProvider.tsx │ │ │ ├── AppService.ts │ │ │ └── lib │ │ │ │ ├── AsyncQueue.ts │ │ │ │ ├── checkUpdateAndInstall.ts │ │ │ │ ├── initLocalSite.ts │ │ │ │ ├── isRowsEqual.tsx │ │ │ │ ├── syncNodesToLocal.tsx │ │ │ │ └── syncState.ts │ │ ├── AreaDialog │ │ │ ├── AreaDialog.tsx │ │ │ ├── AreaForm.tsx │ │ │ └── useAreaDialog.tsx │ │ ├── AreaInfo.tsx │ │ ├── AreasPopover │ │ │ ├── AreaMenu.tsx │ │ │ ├── AreasPopover.tsx │ │ │ └── DeleteAreaDialog │ │ │ │ ├── DeleteAreaDialog.tsx │ │ │ │ └── useDeleteAreaDialog.ts │ │ ├── Bullet.tsx │ │ ├── ClientOnly.tsx │ │ ├── CommandPanel │ │ │ ├── CommandList.tsx │ │ │ ├── CommandPanel.tsx │ │ │ ├── CommandWrapper.tsx │ │ │ ├── CommonList.tsx │ │ │ ├── SearchCreationList.tsx │ │ │ ├── command-components.tsx │ │ │ ├── hooks │ │ │ │ ├── useOpen.tsx │ │ │ │ └── useSearch.ts │ │ │ └── useCommands.ts │ │ ├── Creation │ │ │ ├── AddPropButton.tsx │ │ │ ├── AudioCreationUpload.tsx │ │ │ ├── Authors.tsx │ │ │ ├── ChangeType.tsx │ │ │ ├── CoverUpload.tsx │ │ │ ├── Creation.tsx │ │ │ ├── CreationMoreMenu.tsx │ │ │ ├── DeleteCreationDialog │ │ │ │ ├── DeleteCreationDialog.tsx │ │ │ │ └── useDeleteCreationDialog.ts │ │ │ ├── ImageCreationUpload.tsx │ │ │ ├── MultipleSelectProp.tsx │ │ │ ├── PanelCreationProvider.tsx │ │ │ ├── PropItem.tsx │ │ │ ├── PropList.tsx │ │ │ ├── PublishDialog │ │ │ │ ├── PublishDialog.tsx │ │ │ │ ├── PublishForm.tsx │ │ │ │ └── usePublishDialog.ts │ │ │ ├── RateProp.tsx │ │ │ ├── SingleSelectProp.tsx │ │ │ ├── Tags.tsx │ │ │ ├── command-components.tsx │ │ │ └── index.tsx │ │ ├── CreationCard │ │ │ ├── CreationCard.tsx │ │ │ ├── Link.tsx │ │ │ ├── Tags.tsx │ │ │ ├── VoiceContent.tsx │ │ │ ├── getMotionConfig.ts │ │ │ └── uploadAudio.ts │ │ ├── DashboardLayout │ │ │ ├── ClosePanelButton.tsx │ │ │ ├── DashboardLayout.tsx │ │ │ ├── PanelHeaderWrapper.tsx │ │ │ ├── PanelItem.tsx │ │ │ ├── PanelLayout.tsx │ │ │ ├── PanelList.tsx │ │ │ ├── SettingsLayout.tsx │ │ │ ├── index.tsx │ │ │ └── panel-renderer │ │ │ │ ├── Bookmarks │ │ │ │ ├── BookmarkItem.tsx │ │ │ │ └── BookmarkList.tsx │ │ │ │ ├── LocalBackup │ │ │ │ ├── BackupInterval.tsx │ │ │ │ └── LocalBackup.tsx │ │ │ │ ├── ManageTags │ │ │ │ ├── ManageTags.tsx │ │ │ │ └── TagDialog │ │ │ │ │ ├── TagDialog.tsx │ │ │ │ │ ├── TagForm.tsx │ │ │ │ │ └── useTagDialog.tsx │ │ │ │ ├── PanelAISetting.tsx │ │ │ │ ├── PanelChat.tsx │ │ │ │ ├── PanelCreation.tsx │ │ │ │ ├── PanelJournal │ │ │ │ ├── JournalContent.tsx │ │ │ │ ├── JournalNav.tsx │ │ │ │ ├── JournalShortcut.tsx │ │ │ │ ├── JournalTitle.tsx │ │ │ │ ├── JournalTitleMobile.tsx │ │ │ │ ├── MenuItem.tsx │ │ │ │ ├── PanelJournal.tsx │ │ │ │ ├── PanelStruct.tsx │ │ │ │ └── StructTypeSelect.tsx │ │ │ │ ├── PanelStructs │ │ │ │ ├── PanelStructs.tsx │ │ │ │ ├── PublishedStructList.tsx │ │ │ │ └── StructList.tsx │ │ │ │ ├── PanelWidget.tsx │ │ │ │ └── PanelWidgetHeader.tsx │ │ ├── DeleteStructDialog │ │ │ ├── DeleteStructDialog.tsx │ │ │ └── useDeleteStructDialog.tsx │ │ ├── EngagementTracker.tsx │ │ ├── Fallback │ │ │ ├── Fallback.tsx │ │ │ └── ReloadAppBtn.tsx │ │ ├── FieldIcon.tsx │ │ ├── FileUpload.tsx │ │ ├── GoToDay.tsx │ │ ├── GoogleOauthDialog │ │ │ ├── GoogleOauthDialog.tsx │ │ │ └── useGoogleOauthDialog.tsx │ │ ├── Image.tsx │ │ ├── JournalInputToolbar.tsx │ │ ├── JournalQuickInput.tsx │ │ ├── Kbd.tsx │ │ ├── LangSwitcher.tsx │ │ ├── LinguiClientProvider.tsx │ │ ├── LoginButton.tsx │ │ ├── Logo.tsx │ │ ├── ModeToggle.tsx │ │ ├── Navbar │ │ │ └── NavbarWrapper.tsx │ │ ├── NoteInput.tsx │ │ ├── OptionTag.tsx │ │ ├── PageRender.tsx │ │ ├── PasswordDialog │ │ │ ├── PasswordDialog.tsx │ │ │ ├── PasswordForm.tsx │ │ │ └── usePasswordDialog.tsx │ │ ├── PlanList │ │ │ ├── BillingCycleSelect.tsx │ │ │ ├── PlanItem.tsx │ │ │ ├── PlanList.tsx │ │ │ ├── PlanListDialog.tsx │ │ │ ├── PricingSlogan.tsx │ │ │ ├── UpgradeButton.tsx │ │ │ ├── useBillingCycle.tsx │ │ │ └── usePlanListDialog.tsx │ │ ├── Profile │ │ │ ├── Profile.tsx │ │ │ ├── ProfileAvatar.tsx │ │ │ └── ProfilePopover.tsx │ │ ├── ProfileButton.tsx │ │ ├── PublishStructDialog │ │ │ ├── PublishStructContent.tsx │ │ │ ├── PublishStructDialog.tsx │ │ │ └── usePublishStructDialog.tsx │ │ ├── Sidebar │ │ │ ├── EnableWeb3Entry.tsx │ │ │ ├── ImportPostEntry.tsx │ │ │ ├── LinkAccountEntry.tsx │ │ │ ├── LinkGoogleEntry.tsx │ │ │ ├── QuickSearchTrigger.tsx │ │ │ ├── UpgradeButton.tsx │ │ │ ├── VisitSiteButton.tsx │ │ │ └── app-sidebar.tsx │ │ ├── SiteLink.tsx │ │ ├── SocialNav.tsx │ │ ├── StarSVG.tsx │ │ ├── StructDialog │ │ │ ├── ColorSelector.tsx │ │ │ ├── CreateStructForm.tsx │ │ │ ├── EditStructForm.tsx │ │ │ ├── StructDialog.tsx │ │ │ └── useStructDialog.tsx │ │ ├── StructTypeSelect.tsx │ │ ├── SwitchChainDialog │ │ │ ├── SwitchChainDialog.tsx │ │ │ └── useSwitchChainDialog.tsx │ │ ├── TaskInput.tsx │ │ ├── TextLogo.tsx │ │ ├── ThemeProvider.tsx │ │ ├── area-widgets │ │ │ ├── AddChatButton.tsx │ │ │ ├── AddCreationButton.tsx │ │ │ ├── AddWidgetButton.tsx │ │ │ ├── AllCreationCard.tsx │ │ │ ├── AreaWidgets.tsx │ │ │ ├── CreationItem.tsx │ │ │ ├── EditWidget │ │ │ │ ├── EditWidgetButton.tsx │ │ │ │ ├── SortableWidgetItem.tsx │ │ │ │ ├── WidgetItem.tsx │ │ │ │ └── WidgetList.tsx │ │ │ ├── IsAllContext.tsx │ │ │ ├── MobileWidgetList.tsx │ │ │ ├── SortableWidgetItem.tsx │ │ │ ├── StructCreationsCard.tsx │ │ │ ├── TitleContextMenu.tsx │ │ │ ├── ToggleButton.tsx │ │ │ ├── WidgetItem.tsx │ │ │ ├── WidgetList.tsx │ │ │ ├── WidgetRender.tsx │ │ │ ├── components │ │ │ │ └── NoCreationYet.tsx │ │ │ ├── index.tsx │ │ │ └── widgets │ │ │ │ ├── AIChatHistorys.tsx │ │ │ │ ├── AllCreations.tsx │ │ │ │ ├── CreationList.tsx │ │ │ │ ├── Favorites.tsx │ │ │ │ ├── RecentlyEdited.tsx │ │ │ │ ├── RecentlyOpened.tsx │ │ │ │ └── StructList.tsx │ │ ├── blur-image.tsx │ │ ├── cells │ │ │ ├── date-cell.tsx │ │ │ ├── draw-fns.ts │ │ │ ├── file-cell.tsx │ │ │ ├── image-cell.tsx │ │ │ ├── index.tsx │ │ │ ├── lib │ │ │ │ └── select-cell-components.tsx │ │ │ ├── multiple-select-cell.tsx │ │ │ ├── password-cell.tsx │ │ │ ├── primary-cell.tsx │ │ │ ├── rate-cell.tsx │ │ │ ├── single-select-cell.tsx │ │ │ └── system-date-cell.tsx │ │ ├── database-ui │ │ │ ├── DatabaseProvider.tsx │ │ │ ├── FullPageDatabase.tsx │ │ │ ├── InlineDatabase.tsx │ │ │ ├── RowForm.tsx │ │ │ ├── TableInfo.tsx │ │ │ ├── ViewNav │ │ │ │ ├── AddViewBtn.tsx │ │ │ │ ├── ViewIcon.tsx │ │ │ │ ├── ViewItem.tsx │ │ │ │ ├── ViewList.tsx │ │ │ │ └── ViewMenu.tsx │ │ │ ├── ViewRenderer.tsx │ │ │ ├── ViewToolBar │ │ │ │ ├── FilterField │ │ │ │ │ ├── FieldSelect.tsx │ │ │ │ │ ├── FilterBtns.tsx │ │ │ │ │ ├── FilterItem.tsx │ │ │ │ │ ├── OperatorSelect.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useFilterField.tsx │ │ │ │ ├── GroupField │ │ │ │ │ ├── AddGroupBtn.tsx │ │ │ │ │ ├── GroupItem.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── HideField │ │ │ │ │ ├── HideField.tsx │ │ │ │ │ ├── HideFieldOverlay.tsx │ │ │ │ │ ├── Item.tsx │ │ │ │ │ └── SortableItem.tsx │ │ │ │ ├── SortField │ │ │ │ │ ├── AddSortBtn.tsx │ │ │ │ │ ├── SortItem.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TableField │ │ │ │ │ └── index.tsx │ │ │ │ ├── ToolbarBtn.tsx │ │ │ │ └── ViewToolBar.tsx │ │ │ ├── columnWidthMotion.ts │ │ │ ├── index.ts │ │ │ └── views │ │ │ │ ├── GalleryView │ │ │ │ ├── GalleryView.tsx │ │ │ │ └── Notes │ │ │ │ │ ├── NoteGalleryView.tsx │ │ │ │ │ ├── NoteInput.tsx │ │ │ │ │ ├── NoteItem.tsx │ │ │ │ │ └── NoteList.tsx │ │ │ │ ├── ListView │ │ │ │ ├── CreationItem.tsx │ │ │ │ ├── CreationList.tsx │ │ │ │ ├── ListView.tsx │ │ │ │ └── Tasks │ │ │ │ │ ├── TaskItem.tsx │ │ │ │ │ └── TasksList.tsx │ │ │ │ └── TableView │ │ │ │ ├── AddColumnBtn.tsx │ │ │ │ ├── CellMenu.tsx │ │ │ │ ├── ColumnMenu │ │ │ │ ├── ColumnMenu.tsx │ │ │ │ └── EditField.tsx │ │ │ │ ├── ConfigColumnDialog │ │ │ │ ├── ConfigColumnDialog.tsx │ │ │ │ └── useConfigColumnDialog.ts │ │ │ │ ├── DeleteColumnDialog │ │ │ │ ├── DeleteColumnDialog.tsx │ │ │ │ └── useDeleteColumnDialog.ts │ │ │ │ ├── FieldSelectPopover.tsx │ │ │ │ ├── TableView.tsx │ │ │ │ ├── hooks │ │ │ │ ├── useCellMenu.tsx │ │ │ │ ├── useColumnMenu.tsx │ │ │ │ ├── useFieldTypeSelectPopover.ts │ │ │ │ └── useTableView │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useTableView.tsx │ │ │ │ ├── use-undo-redo.ts │ │ │ │ └── useEditColumnForm.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── placeholder-card.tsx │ │ ├── providers │ │ │ ├── DashboardProviders.tsx │ │ │ └── RootProviders.tsx │ │ └── styles │ │ │ └── tailwind.css │ ├── tailwind.css │ └── tsconfig.json ├── constants │ ├── package.json │ ├── src │ │ ├── basic.constants.ts │ │ ├── element-type.ts │ │ ├── index.ts │ │ ├── redisKeys.ts │ │ ├── schema.constants.ts │ │ └── urls.constants.ts │ └── tsconfig.json ├── content-render │ ├── package.json │ ├── src │ │ ├── ContentRender.tsx │ │ ├── index.tsx │ │ └── styles │ │ │ └── tailwind.css │ └── tsconfig.json ├── contexts │ ├── package.json │ ├── src │ │ ├── CreationContext.tsx │ │ ├── CreationsContext.tsx │ │ ├── FriendsContext.tsx │ │ ├── ProjectsContext.tsx │ │ ├── SiteContext.tsx │ │ └── index.ts │ └── tsconfig.json ├── domain │ ├── package.json │ ├── src │ │ ├── Area.ts │ │ ├── Creation.ts │ │ ├── CreationTag.ts │ │ ├── EthBalance.ts │ │ ├── Journal.ts │ │ ├── Node.ts │ │ ├── Site.ts │ │ ├── Struct.ts │ │ ├── Subscription.ts │ │ ├── Tag.ts │ │ └── index.ts │ └── tsconfig.json ├── emitter │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── encryption │ ├── package.json │ ├── src │ │ ├── calculateSHA256FromFile.ts │ │ ├── calculateSHA256FromString.ts │ │ ├── decryptString.ts │ │ ├── encryptString.ts │ │ └── index.ts │ └── tsconfig.json ├── eslint-config │ ├── README.md │ ├── base.js │ ├── next.js │ ├── package.json │ └── react-internal.js ├── hooks │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── use-artifact.ts │ │ ├── use-chat-visibility.ts │ │ ├── use-debounce.ts │ │ ├── use-domain-status.ts │ │ ├── use-is-touch-device.ts │ │ ├── use-mobile.ts │ │ ├── use-mounted.ts │ │ ├── use-window-size.ts │ │ ├── useActiveStruct.ts │ │ ├── useAddCreation.ts │ │ ├── useAppLoading.ts │ │ ├── useArea.ts │ │ ├── useAreas.ts │ │ ├── useAuthStatus.ts │ │ ├── useBulletDrawer.ts │ │ ├── useCommands.ts │ │ ├── useCopyToClipboard.ts │ │ ├── useCreation.ts │ │ ├── useCreationId.ts │ │ ├── useCreationStruct.ts │ │ ├── useCreationTags.ts │ │ ├── useCreations.ts │ │ ├── useDetectClickOutside.ts │ │ ├── useJournal.ts │ │ ├── useJournalLayout.ts │ │ ├── useJournals.ts │ │ ├── useMessages.ts │ │ ├── useMobileMenu.ts │ │ ├── useMobileNav.ts │ │ ├── useMySite.ts │ │ ├── useNotes.ts │ │ ├── usePaletteDrawer.ts │ │ ├── usePanels.ts │ │ ├── usePostEngagement.ts │ │ ├── usePostImport.ts │ │ ├── usePostImportTask.ts │ │ ├── usePostLoading.ts │ │ ├── usePostSaving.ts │ │ ├── usePublishPost.ts │ │ ├── useQuickAdd.ts │ │ ├── useRouterName.ts │ │ ├── useSidebarDrawer.ts │ │ ├── useSpaces.ts │ │ ├── useStructId.ts │ │ ├── useStructs.ts │ │ └── useTags.ts │ └── tsconfig.json ├── libs │ ├── package.json │ ├── src │ │ ├── ai │ │ │ └── helper.ts │ │ ├── cache-header.ts │ │ ├── color-helper.ts │ │ ├── decodeAppleToken.ts │ │ ├── domains.ts │ │ ├── getCreationIcon.tsx │ │ ├── getDefaultStructs.ts │ │ ├── getGoogleUserInfo.ts │ │ ├── getInitialWidgets.ts │ │ ├── getOrInitLocalBackupDir.ts │ │ ├── getSiteDomain.ts │ │ ├── hashPassword.ts │ │ ├── i18n.tsx │ │ ├── index.ts │ │ ├── revalidateTag.ts │ │ ├── session.ts │ │ ├── slate-to-html.ts │ │ ├── stripe.ts │ │ └── styles │ │ │ └── tailwind.css │ └── tsconfig.json ├── local-db │ ├── package.json │ ├── src │ │ ├── domains │ │ │ └── node.domain.ts │ │ ├── emitter.ts │ │ ├── index.ts │ │ ├── libs │ │ │ ├── array-sorter.ts │ │ │ ├── formatTagName.ts │ │ │ ├── formatToDate.ts │ │ │ └── getRandomColor.ts │ │ ├── local-db.ts │ │ └── types.ts │ └── tsconfig.json ├── locales │ ├── package.json │ ├── src │ │ ├── LocaleProvider.tsx │ │ ├── dynamicActivate.ts │ │ ├── index.ts │ │ └── locales │ │ │ ├── de.po │ │ │ ├── en.po │ │ │ ├── fr.po │ │ │ ├── ja.po │ │ │ ├── ko.po │ │ │ ├── pseudo.po │ │ │ ├── ru.po │ │ │ └── zh-CN.po │ └── tsconfig.json ├── math │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── math.ts │ │ └── precision.ts │ └── tsconfig.json ├── model-type │ ├── package.json │ ├── src │ │ ├── IAISetting.ts │ │ ├── IAsset.ts │ │ ├── ICatalogueNode.ts │ │ ├── IChange.ts │ │ ├── IChat.ts │ │ ├── IColumn.ts │ │ ├── IDatabase.ts │ │ ├── IDocument.ts │ │ ├── IDomain.ts │ │ ├── IField.ts │ │ ├── IFile.ts │ │ ├── IMessage.ts │ │ ├── INode.ts │ │ ├── IRecord.ts │ │ ├── ISite.ts │ │ ├── ISuggestion.ts │ │ ├── IView.ts │ │ ├── IVoice.ts │ │ └── index.ts │ └── tsconfig.json ├── novel-editor │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── FocusHelper.tsx │ │ │ ├── extensions.ts │ │ │ ├── generative │ │ │ │ ├── ai-completion-command.tsx │ │ │ │ ├── ai-selector-commands.tsx │ │ │ │ ├── ai-selector.tsx │ │ │ │ └── generative-menu-switch.tsx │ │ │ ├── image-upload.ts │ │ │ ├── novel-editor.tsx │ │ │ ├── selectors │ │ │ │ ├── color-selector.tsx │ │ │ │ ├── link-selector.tsx │ │ │ │ ├── math-selector.tsx │ │ │ │ ├── node-selector.tsx │ │ │ │ └── text-buttons.tsx │ │ │ ├── slash-command.tsx │ │ │ └── ui │ │ │ │ ├── command.tsx │ │ │ │ ├── icons │ │ │ │ ├── crazy-spinner.tsx │ │ │ │ ├── font-default.tsx │ │ │ │ ├── font-mono.tsx │ │ │ │ ├── font-serif.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── loading-circle.tsx │ │ │ │ └── magic.tsx │ │ │ │ └── menu.tsx │ │ ├── hooks │ │ │ └── use-local-storage.ts │ │ ├── lib │ │ │ ├── uploadFile.ts │ │ │ └── utils.ts │ │ └── styles │ │ │ ├── prosemirror.css │ │ │ └── tailwind.css │ └── tsconfig.json ├── query-client │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── services │ ├── package.json │ ├── src │ │ ├── SyncService.ts │ │ ├── index.ts │ │ ├── sync.ts │ │ ├── syncPostToHub.ts │ │ ├── syncSiteToHub.ts │ │ ├── uploadFile.ts │ │ └── uploadthing.ts │ └── tsconfig.json ├── session │ ├── package.json │ ├── src │ │ ├── SessionContext.tsx │ │ ├── index.ts │ │ └── useQuerySession.ts │ └── tsconfig.json ├── store │ ├── package.json │ ├── src │ │ ├── JotaiNexus.ts │ │ ├── StoreProvider.tsx │ │ ├── index.ts │ │ ├── store-types.ts │ │ ├── store.ts │ │ └── stores │ │ │ ├── AppStore.ts │ │ │ ├── AreaStore.ts │ │ │ ├── AreasStore.ts │ │ │ ├── CreationTagsStore.ts │ │ │ ├── CreationsStore.ts │ │ │ ├── JournalsStore.ts │ │ │ ├── PanelsStore.ts │ │ │ ├── SiteStore.ts │ │ │ ├── StructsStore.ts │ │ │ ├── TagsStore.ts │ │ │ └── VisitStore.ts │ └── tsconfig.json ├── types │ ├── package.json │ ├── src │ │ ├── ai │ │ │ └── llm-provider-type.ts │ │ ├── database-types.ts │ │ ├── index.ts │ │ ├── session.types.ts │ │ └── types.ts │ └── tsconfig.json ├── typescript-config │ ├── base.json │ ├── internal-package.json │ └── package.json ├── uikit │ ├── components.json │ ├── globals.css │ ├── package.json │ ├── postcss.config.mjs │ ├── src │ │ ├── components │ │ │ ├── AddNodeBtn.tsx │ │ │ ├── FileUpload.tsx │ │ │ ├── Image.tsx │ │ │ ├── NumberInput.tsx │ │ │ ├── icons │ │ │ │ ├── IconGoogle.tsx │ │ │ │ ├── loading-circle.tsx │ │ │ │ ├── loading-dots.tsx │ │ │ │ └── magic.tsx │ │ │ └── uploadFile.ts │ │ ├── hooks │ │ │ ├── use-debounce.ts │ │ │ ├── use-is-touch-device.ts │ │ │ ├── use-mobile.ts │ │ │ ├── use-mounted.ts │ │ │ └── use-window-size.ts │ │ ├── index.ts │ │ ├── lib │ │ │ └── utils.ts │ │ ├── styles │ │ │ └── tailwind.css │ │ └── ui │ │ │ ├── accordion.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── alert.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button.tsx │ │ │ ├── calendar.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── context-menu.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── form.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── input-otp.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── menu │ │ │ ├── Menu.tsx │ │ │ ├── MenuGroup.tsx │ │ │ ├── MenuItem.tsx │ │ │ ├── context.ts │ │ │ └── index.tsx │ │ │ ├── popover.tsx │ │ │ ├── progress.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── sidebar.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ ├── toggle-group.tsx │ │ │ ├── toggle.tsx │ │ │ └── tooltip.tsx │ ├── tailwind.css │ └── tsconfig.json ├── unique-id │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── utils │ ├── package.json │ ├── src │ │ ├── base64StringToFile.ts │ │ ├── calculateSHA256FromFile.ts │ │ ├── editorHelper.ts │ │ ├── extractErrorMessage.ts │ │ ├── generateGradient.ts │ │ ├── generateNonce.ts │ │ ├── getDataEditorTheme.ts │ │ ├── i18n.utils.ts │ │ └── index.ts │ └── tsconfig.json ├── widgets │ ├── package.json │ ├── postcss.config.mjs │ ├── src │ │ ├── AppleOauthButton.tsx │ │ ├── ConfirmDialog.tsx │ │ ├── GoogleOauthButton.tsx │ │ ├── LoginDialog │ │ │ ├── LoginDialog.tsx │ │ │ ├── LoginDialogContent.tsx │ │ │ ├── LoginForm.tsx │ │ │ ├── PinCodeForm.tsx │ │ │ ├── RegisterForm.tsx │ │ │ └── useLoginDialog.tsx │ │ ├── Logo.tsx │ │ ├── LogoSpinner.tsx │ │ ├── StructIcon.tsx │ │ ├── StructName.tsx │ │ ├── UserAvatar.tsx │ │ ├── WidgetIcon.tsx │ │ ├── WidgetName.tsx │ │ ├── index.ts │ │ └── style │ │ │ └── tailwind.css │ ├── tailwind.css │ └── tsconfig.json └── worker │ ├── package.json │ ├── src │ ├── index.ts │ ├── pollingBackupToGoogle.ts │ ├── pollingCheckTodayJournal.ts │ ├── pollingCloudSync.ts │ ├── pollingSyncToRemote.ts │ ├── runWorker.ts │ └── worker.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── replaceTransId.js └── turbo.json /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="postgresql://penx_electric_user:Penx_dev@43.154.135.183:6001/penx_electric_dev?sslmode=disable" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | .cache/ 30 | 31 | 32 | # Debug 33 | npm-debug.log* 34 | yarn-debug.log* 35 | yarn-error.log* 36 | 37 | # Misc 38 | .DS_Store 39 | *.pem 40 | 41 | .output 42 | 43 | tsconfig.tsbuildinfo 44 | 45 | packages/locales/**/*.ts -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/.npmrc -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "printWidth": 80, 7 | "plugins": [ 8 | "@ianvs/prettier-plugin-sort-imports", 9 | "prettier-plugin-tailwindcss" 10 | ], 11 | "tailwindFunctions": ["cn", "cva", "withCn"], 12 | "tailwindStylesheet": "./app/globals.css", 13 | "importOrder": [ 14 | "^react", 15 | "", 16 | "", 17 | "^@penx/(.*)$", 18 | "^~(.*)$", 19 | "^[./]" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer","ionic.ionic"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.linkedProjects": ["./apps/desktop/src-tauri/Cargo.toml"], 3 | "eslint.workingDirectories": [ 4 | { 5 | "mode": "auto" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /apps/desktop/.env: -------------------------------------------------------------------------------- 1 | VITE_ROOT_HOST=https://penx.io 2 | # VITE_ROOT_HOST=http://localhost:4000 3 | 4 | VITE_PLATFORM=DESKTOP 5 | -------------------------------------------------------------------------------- /apps/desktop/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | !.env -------------------------------------------------------------------------------- /apps/desktop/README.md: -------------------------------------------------------------------------------- 1 | # Tauri + React + Typescript 2 | 3 | This template should help get you started developing with Tauri, React and Typescript in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | - [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) 8 | -------------------------------------------------------------------------------- /apps/desktop/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/style.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "hooks": "@/hooks", 15 | "lib": "@/lib", 16 | "utils": "@penx/uikit/lib/utils", 17 | "ui": "@penx/uikit/components" 18 | }, 19 | "iconLibrary": "lucide" 20 | } 21 | -------------------------------------------------------------------------------- /apps/desktop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tauri + React + Typescript 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/desktop/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@penx/uikit/postcss.config"; -------------------------------------------------------------------------------- /apps/desktop/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen/schemas 8 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata/ 2 | build/ 3 | Externals/ 4 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | method 6 | debugging 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Sources/penx-desktop/bindings/bindings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ffi { 4 | extern "C" { 5 | void start_app(); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/Sources/penx-desktop/main.mm: -------------------------------------------------------------------------------- 1 | #include "bindings/bindings.h" 2 | 3 | int main(int argc, char * argv[]) { 4 | ffi::start_app(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/penx-desktop.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/penx-desktop.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | DisableBuildSystemDeprecationDiagnostic 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/gen/apple/penx-desktop_iOS/penx-desktop_iOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | penx_desktop_lib::run() 6 | } 7 | -------------------------------------------------------------------------------- /apps/desktop/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | 5 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 6 | 7 | 8 | , 9 | ) 10 | -------------------------------------------------------------------------------- /apps/desktop/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/desktop/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/extension/.env: -------------------------------------------------------------------------------- 1 | # WXT_ROOT_HOST=https://penx.io 2 | WXT_ROOT_HOST=http://localhost:4000 3 | 4 | WXT_PLATFORM=EXTENSION -------------------------------------------------------------------------------- /apps/extension/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .output 12 | stats.html 13 | stats-*.json 14 | .wxt 15 | web-ext.config.ts 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | !.env -------------------------------------------------------------------------------- /apps/extension/README.md: -------------------------------------------------------------------------------- 1 | # WXT + React 2 | 3 | This template should help get you started developing with React in WXT. 4 | -------------------------------------------------------------------------------- /apps/extension/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "hooks": "@/hooks", 15 | "lib": "@/lib", 16 | "utils": "@penx/uikit/lib/utils", 17 | "ui": "@penx/uikit/components" 18 | }, 19 | "iconLibrary": "lucide" 20 | } 21 | -------------------------------------------------------------------------------- /apps/extension/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@penx/utils' 2 | 3 | interface Props { 4 | className?: string 5 | } 6 | export function Logo({ className }: Props) { 7 | return ( 8 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /apps/extension/components/content/constants.ts: -------------------------------------------------------------------------------- 1 | // selection container id 2 | export const PENX_SELECTION_CONTAINER = 'penx-selection-container' 3 | 4 | // sandbox iframe id 5 | export const PENX_SANDBOX_BOARD_IFRAME = 'penx-sandbox-board-iframe' 6 | 7 | export enum SandBoxMessageType { 8 | getSelectedHtml = 'getSelectedHtml', 9 | 10 | initSandbox = 'initSandbox', 11 | 12 | startOcr = 'startOcr', 13 | } 14 | 15 | export enum ClippingTypeEnum { 16 | // selection content 17 | area = 'area', 18 | // selection website 19 | website = 'website', 20 | } 21 | -------------------------------------------------------------------------------- /apps/extension/components/content/hooks/useAppType.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { hideThumbnail } from '../stores/thumbnail.store' 3 | 4 | const appTypeAtom = atom('') 5 | 6 | export function useAppType() { 7 | const [appType, setAppType] = useAtom(appTypeAtom) 8 | function destroy() { 9 | setAppType('') 10 | hideThumbnail() 11 | } 12 | 13 | return { appType, setAppType, destroy } 14 | } 15 | -------------------------------------------------------------------------------- /apps/extension/components/content/hooks/useNote.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const noteAtom = atom('') 4 | 5 | export function useNote() { 6 | const [note, setNote] = useAtom(noteAtom) 7 | return { note, setNote } 8 | } 9 | -------------------------------------------------------------------------------- /apps/extension/components/content/stores/text.store.ts: -------------------------------------------------------------------------------- 1 | import { mutate, useStore } from 'stook' 2 | 3 | const key = 'TEXT_SELECTED' 4 | 5 | type State = { 6 | text: string 7 | selected?: boolean 8 | } 9 | 10 | export function useText() { 11 | const [state, setState] = useStore(key, { text: '' } as State) 12 | const setText = (value: string) => { 13 | setState((state) => { 14 | state.text = value 15 | }) 16 | } 17 | return { 18 | ...state, 19 | setText, 20 | } 21 | } 22 | 23 | export function updateText(text: string) { 24 | mutate(key, { text }) 25 | } 26 | -------------------------------------------------------------------------------- /apps/extension/components/icons/loading-dots.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@penx/utils' 2 | 3 | interface LoadingDotsProps { 4 | className?: string 5 | } 6 | 7 | export const LoadingDots = ({ className }: LoadingDotsProps) => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /apps/extension/entrypoints/newtab/TabContent.tsx: -------------------------------------------------------------------------------- 1 | import { Trans } from '@lingui/react/macro' 2 | import { useSession } from '@penx/session' 3 | 4 | export function TabContent() { 5 | const { session } = useSession() 6 | console.log('=======session:', session) 7 | 8 | return ( 9 |
10 |
11 | Hello 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /apps/extension/entrypoints/newtab/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './style.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /apps/extension/entrypoints/popup/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './style.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /apps/extension/hooks/useLocalAreas.ts: -------------------------------------------------------------------------------- 1 | import { BACKGROUND_EVENTS } from '@/lib/constants' 2 | import { AREAS_KEY } from '@/lib/helper' 3 | import { useStorage } from '@plasmohq/storage/hook' 4 | import { useQuery } from '@tanstack/react-query' 5 | 6 | export function useLocalAreas() { 7 | return useQuery({ 8 | queryKey: ['localAreas'], 9 | queryFn: async () => { 10 | const data = await chrome.runtime.sendMessage({ 11 | type: BACKGROUND_EVENTS.QUERY_AREAS, 12 | }) 13 | console.log('========>>>data:', data) 14 | 15 | return data?.areas as any[] 16 | }, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /apps/extension/lib/content-handler/websites/pdf-handler.ts: -------------------------------------------------------------------------------- 1 | import { ContentHandler, type PreHandleResult } from '../content-handler' 2 | 3 | export class PdfHandler extends ContentHandler { 4 | constructor() { 5 | super() 6 | this.name = 'PDF' 7 | } 8 | 9 | shouldPreHandle(url: string): boolean { 10 | const u = new URL(url) 11 | const path = u.pathname.replace(u.search, '') 12 | return path.endsWith('.pdf') 13 | } 14 | 15 | async preHandle(url: string): Promise { 16 | return Promise.resolve({ contentType: 'application/pdf' }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/extension/public/icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/extension/public/icon/128.png -------------------------------------------------------------------------------- /apps/extension/public/icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/extension/public/icon/16.png -------------------------------------------------------------------------------- /apps/extension/public/icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/extension/public/icon/32.png -------------------------------------------------------------------------------- /apps/extension/public/icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/extension/public/icon/48.png -------------------------------------------------------------------------------- /apps/extension/public/icon/96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/extension/public/icon/96.png -------------------------------------------------------------------------------- /apps/extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.wxt/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "strictNullChecks": false, 6 | "baseUrl": ".", 7 | "paths": { 8 | "@/*": ["./*"], 9 | "@penx/uikit/*": ["../../packages/uikit/src/*"] 10 | }, 11 | "allowImportingTsExtensions": true, 12 | "jsx": "react-jsx" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/mobile/.env: -------------------------------------------------------------------------------- 1 | VITE_ROOT_HOST=https://penx.io 2 | # VITE_ROOT_HOST=http://localhost:4000 3 | 4 | VITE_PLATFORM=MOBILE 5 | -------------------------------------------------------------------------------- /apps/mobile/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /dist 13 | 14 | # misc 15 | .DS_Store 16 | !.env 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | /.nx 22 | /.nx/cache 23 | /.vscode/* 24 | !/.vscode/extensions.json 25 | .idea 26 | 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | 31 | # Optional eslint cache 32 | .eslintcache 33 | -------------------------------------------------------------------------------- /apps/mobile/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | !/build/.npmkeep 3 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/assets/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "io.penx.app", 3 | "appName": "PenX", 4 | "webDir": "dist", 5 | "plugins": { 6 | "SplashScreen": { 7 | "androidSplashResourceName": "splash", 8 | "androidScaleType": "CENTER_CROP", 9 | "backgroundColor": "#ffffffff", 10 | "showSpinner": false 11 | }, 12 | "Keyboard": { 13 | "resize": "none", 14 | "resizeOnFullScreen": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-hdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-ldpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-ldpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-mdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-hdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-ldpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-ldpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-mdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-xhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-xxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-night-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-night-xxxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-xhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-xxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-land-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-land-xxxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-night/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-night/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-hdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-ldpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-ldpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-mdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-hdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-ldpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-ldpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-mdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-xhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-xxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-night-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-night-xxxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-xhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-xxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable-port-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable-port-xxxhdpi/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-ldpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | PenX 4 | PenX 5 | io.penx.app 6 | io.penx.app 7 | 8 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /apps/mobile/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/mobile/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/mobile/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/mobile/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':capacitor-cordova-android-plugins' 3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') 4 | 5 | apply from: 'capacitor.settings.gradle' -------------------------------------------------------------------------------- /apps/mobile/android/variables.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | minSdkVersion = 23 3 | compileSdkVersion = 35 4 | targetSdkVersion = 35 5 | androidxActivityVersion = '1.9.2' 6 | androidxAppCompatVersion = '1.7.0' 7 | androidxCoordinatorLayoutVersion = '1.2.0' 8 | androidxCoreVersion = '1.15.0' 9 | androidxFragmentVersion = '1.8.4' 10 | coreSplashScreenVersion = '1.0.1' 11 | androidxWebkitVersion = '1.12.1' 12 | junitVersion = '4.13.2' 13 | androidxJunitVersion = '1.2.1' 14 | androidxEspressoCoreVersion = '3.6.1' 15 | cordovaAndroidVersion = '10.1.1' 16 | } -------------------------------------------------------------------------------- /apps/mobile/assets/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/assets/logo-dark.png -------------------------------------------------------------------------------- /apps/mobile/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/assets/logo.png -------------------------------------------------------------------------------- /apps/mobile/assets/splash-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/assets/splash-dark.png -------------------------------------------------------------------------------- /apps/mobile/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/assets/splash.png -------------------------------------------------------------------------------- /apps/mobile/capacitor.config.ts: -------------------------------------------------------------------------------- 1 | import type { CapacitorConfig } from '@capacitor/cli' 2 | 3 | const config: CapacitorConfig = { 4 | appId: 'io.penx.app', 5 | appName: 'PenX', 6 | webDir: 'dist', 7 | 8 | plugins: { 9 | SplashScreen: { 10 | androidSplashResourceName: 'splash', 11 | androidScaleType: 'CENTER_CROP', 12 | backgroundColor: '#ffffffff', 13 | showSpinner: false, 14 | }, 15 | 16 | Keyboard: { 17 | resize: 'none', 18 | resizeOnFullScreen: true, 19 | }, 20 | }, 21 | } 22 | 23 | export default config 24 | -------------------------------------------------------------------------------- /apps/mobile/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/style.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "hooks": "@/hooks", 15 | "lib": "@/lib", 16 | "utils": "@penx/uikit/lib/utils", 17 | "ui": "@penx/uikit/components" 18 | }, 19 | "iconLibrary": "lucide" 20 | } 21 | -------------------------------------------------------------------------------- /apps/mobile/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress' 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | baseUrl: 'http://localhost:5173', 6 | setupNodeEvents(on, config) { 7 | // implement node event listeners here 8 | }, 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /apps/mobile/icons/icon-128.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-128.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-192.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-192.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-256.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-256.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-48.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-48.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-512.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-512.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-72.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-72.webp -------------------------------------------------------------------------------- /apps/mobile/icons/icon-96.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/icons/icon-96.webp -------------------------------------------------------------------------------- /apps/mobile/ionic.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PenX", 3 | "integrations": { 4 | "capacitor": {} 5 | }, 6 | "type": "react-vite" 7 | } 8 | -------------------------------------------------------------------------------- /apps/mobile/ios/.gitignore: -------------------------------------------------------------------------------- 1 | App/build 2 | App/Pods 3 | App/output 4 | App/App/public 5 | DerivedData 6 | xcuserdata 7 | 8 | # Cordova plugins for Capacitor 9 | capacitor-cordova-ios-plugins 10 | 11 | # Generated Config files 12 | App/App/capacitor.config.json 13 | App/App/config.xml 14 | -------------------------------------------------------------------------------- /apps/mobile/ios/App/App.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/mobile/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/App.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.applesignin 6 | 7 | Default 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/AppDebug.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.applesignin 6 | 7 | Default 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "universal", 5 | "size": "1024x1024", 6 | "filename": "AppIcon-512@2x.png", 7 | "platform": "ios" 8 | } 9 | ], 10 | "info": { 11 | "author": "xcode", 12 | "version": 1 13 | } 14 | } -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png -------------------------------------------------------------------------------- /apps/mobile/ios/App/App/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/mobile/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@penx/uikit/postcss.config"; -------------------------------------------------------------------------------- /apps/mobile/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/mobile/public/favicon.png -------------------------------------------------------------------------------- /apps/mobile/src/components/Login/EmailLoginButton.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React from 'react' 4 | import { PageEmailLogin } from '@/pages/PageEmailLogin' 5 | import { IonNavLink } from '@ionic/react' 6 | import { MailIcon } from 'lucide-react' 7 | import { Button } from '@penx/uikit/button' 8 | 9 | interface Props {} 10 | export function EmailLoginButton({}: Props) { 11 | return ( 12 | }> 13 | 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /apps/mobile/src/components/MoreStructDrawer/useMoreStructDrawer.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const drawerAtom = atom(false) 6 | 7 | export function useMoreStructDrawer() { 8 | const [isOpen, setIsOpen] = useAtom(drawerAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /apps/mobile/src/components/NavContext.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { createContext, PropsWithChildren, useContext } from 'react' 4 | 5 | export const NavContext = createContext({} as HTMLIonNavElement) 6 | 7 | interface Props { 8 | nav: HTMLIonNavElement 9 | } 10 | 11 | export const NavProvider = ({ nav, children }: PropsWithChildren) => { 12 | return {children} 13 | } 14 | 15 | export function useNavContext() { 16 | const nav = useContext(NavContext) 17 | return nav 18 | } 19 | -------------------------------------------------------------------------------- /apps/mobile/src/components/UpgradeDrawer/useUpgradeDrawer.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const upgradeDrawerAtom = atom(false) 6 | 7 | export function useUpgradeDrawer() { 8 | const [isOpen, setIsOpen] = useAtom(upgradeDrawerAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /apps/mobile/src/hooks/useHomeTab.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { atom, useAtom } from 'jotai' 3 | 4 | const homeTabAtom = atom<'HOME' | 'TASK' | 'NOTE' | 'PROFILE'>('HOME') 5 | 6 | export function useHomeTab() { 7 | const [type, setType] = useAtom(homeTabAtom) 8 | 9 | return { 10 | isHome: type === 'HOME', 11 | isTask: type === 'TASK', 12 | type, 13 | setType, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /apps/mobile/src/hooks/useSidebar.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { atom, useAtom } from 'jotai' 3 | 4 | const sidebarAtom = atom(false) 5 | 6 | export function useSidebar() { 7 | const [isOpen, setIsOpen] = useAtom(sidebarAtom) 8 | const status = useMemo(() => { 9 | if (isOpen) return true 10 | return false 11 | }, [isOpen]) 12 | console.log('=====status:', status) 13 | 14 | return { 15 | status, 16 | isOpen, 17 | setIsOpen, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/mobile/src/lib/activateLocale.ts: -------------------------------------------------------------------------------- 1 | import { i18n } from '@lingui/core' 2 | 3 | export async function activateLocale(locale: string = 'en') { 4 | const { messages } = await import(`../locales/${locale}.po`) 5 | console.log('======>>>>>>>>>messages:', messages) 6 | i18n.load(locale, messages) 7 | i18n.activate(locale) 8 | } 9 | -------------------------------------------------------------------------------- /apps/mobile/src/lib/checkAndRequestPermission.ts: -------------------------------------------------------------------------------- 1 | import { VoiceRecorder } from 'capacitor-voice-recorder' 2 | 3 | export const checkAndRequestPermission = async () => { 4 | const canRecord = await VoiceRecorder.canDeviceVoiceRecord() 5 | if (!canRecord.value) { 6 | return false 7 | } 8 | 9 | const hasPermission = await VoiceRecorder.hasAudioRecordingPermission() 10 | if (!hasPermission.value) { 11 | const permissionResult = 12 | await VoiceRecorder.requestAudioRecordingPermission() 13 | return permissionResult.value 14 | } 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /apps/mobile/src/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const mainBackgroundLight = '#f6f6f6' 2 | export const mainBackgroundDark = '#222222' 3 | -------------------------------------------------------------------------------- /apps/mobile/src/lib/initializeRevenueCat.ts: -------------------------------------------------------------------------------- 1 | import { Capacitor } from '@capacitor/core' 2 | import { LOG_LEVEL, Purchases } from '@revenuecat/purchases-capacitor' 3 | 4 | export async function initializeRevenueCat() { 5 | try { 6 | await Purchases.setLogLevel({ level: LOG_LEVEL.DEBUG }) 7 | 8 | if (Capacitor.getPlatform() === 'ios') { 9 | await Purchases.configure({ 10 | apiKey: 'appl_CioLamReqEDMuGMBQXyHhPjELYv', 11 | }) 12 | } 13 | 14 | console.log('RevenueCat inited') 15 | } catch (error) { 16 | console.error('RevenueCat init fail:', error) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/mobile/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { Capacitor } from '@capacitor/core' 2 | 3 | const platform = Capacitor.getPlatform() 4 | 5 | export const isIOS = platform === 'ios' 6 | export const isAndroid = platform === 'android' 7 | -------------------------------------------------------------------------------- /apps/mobile/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './style.css' 5 | 6 | const container = document.getElementById('root') 7 | const root = createRoot(container!) 8 | root.render( 9 | 10 | 11 | , 12 | ) 13 | -------------------------------------------------------------------------------- /apps/mobile/src/theme/variables.css: -------------------------------------------------------------------------------- 1 | /* For information on how to create your own theme, please see: 2 | http://ionicframework.com/docs/theming/ */ 3 | -------------------------------------------------------------------------------- /apps/mobile/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/mobile/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | node_modules 4 | npm-debug.log 5 | .pnpm-debug.log 6 | README.md 7 | .next 8 | .git -------------------------------------------------------------------------------- /apps/web/.env: -------------------------------------------------------------------------------- 1 | NEXTAUTH_SECRET="v6gbkGrJDTVQOneUGZ/Sufk1Jq7Fy33nTP6ximB4C+U=" 2 | 3 | NEXT_PUBLIC_ROOT_DOMAIN=penx.io 4 | 5 | NEXT_PUBLIC_ROOT_HOST=https://penx.io 6 | 7 | NEXT_PUBLIC_UMAMIC_WEBSITE_ID= 8 | 9 | DEPLOY_CI_HOST=http://localhost:9000 10 | 11 | REVALIDATE_TIME=86400 12 | 13 | NEXT_PUBLIC_SOCKETURL=wss://ws.penx.io 14 | 15 | NEXT_PUBLIC_CAN_SUBSCRIBE=yes 16 | 17 | NEXT_PUBLIC_MIN_WITHDRAW_LIMIT=100 18 | 19 | IGNORE_DURING_BUILDS=true 20 | IGNORE_BUILD_ERRORS=true 21 | 22 | NEXT_PUBLIC_PLATFORM=WEB 23 | 24 | NEXT_PUBLIC_SYNC_URL=https://sync-dev.penx.io/api/shape-proxy -------------------------------------------------------------------------------- /apps/web/.prettierignore: -------------------------------------------------------------------------------- 1 | cache 2 | .cache 3 | package.json 4 | package-lock.json 5 | public 6 | CHANGELOG.md 7 | .yarn 8 | dist 9 | node_modules 10 | .next 11 | build 12 | .contentlayer -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | # 2 | -------------------------------------------------------------------------------- /apps/web/app/(editor)/WatchAppEvent.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect } from 'react' 4 | import { useRouter } from '@/lib/i18n' 5 | import { appEmitter } from '@penx/emitter' 6 | 7 | export function WatchAppEvent() { 8 | const { push } = useRouter() 9 | useEffect(() => { 10 | appEmitter.on('ON_LOGOUT_SUCCESS', () => { 11 | push('/') 12 | }) 13 | 14 | appEmitter.on('ROUTE_TO_SETTINGS', () => { 15 | location.href = '/~/settings' 16 | }) 17 | 18 | appEmitter.on('ROUTE_TO_DESIGN', () => { 19 | push('/~/design') 20 | }) 21 | }, [push]) 22 | return null 23 | } 24 | -------------------------------------------------------------------------------- /apps/web/app/(editor)/desktop-login/page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSession } from '@penx/session' 3 | import { DesktopLogin } from './DesktopLogin' 4 | 5 | export const dynamic = 'force-static' 6 | export const revalidate = 86400 // 3600 * 24 7 | 8 | export default function Page() { 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/app/(editor)/not-found.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import { ROOT_DOMAIN } from '@penx/constants' 3 | 4 | export default function NotFound() { 5 | return ( 6 | 7 | 8 |
9 |

Not Found

10 |

Could not find requested resource

11 | Return Home 12 |
13 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/app/(editor)/page.tsx: -------------------------------------------------------------------------------- 1 | export const dynamic = 'force-static' 2 | 3 | export default function Page() { 4 | return
Hello
5 | } 6 | -------------------------------------------------------------------------------- /apps/web/app/fonts/CalSans-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/app/fonts/CalSans-SemiBold.otf -------------------------------------------------------------------------------- /apps/web/app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /apps/web/app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /apps/web/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "../../packages/uikit/src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "hooks": "@/hooks", 15 | "lib": "@/lib", 16 | "utils": "@penx/uikit/lib/utils", 17 | "ui": "@penx/uikit/components" 18 | }, 19 | "iconLibrary": "lucide" 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/components/SubscriptionGuideDialog/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './SubscriptionGuideDialog' 2 | export * from './useSubscriptionGuideDialog' 3 | -------------------------------------------------------------------------------- /apps/web/components/SubscriptionGuideDialog/useSubscriptionGuideDialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const subscriptionGuideDialogAtom = atom(false) 6 | 7 | export function useSubscriptionGuideDialog() { 8 | const [isOpen, setIsOpen] = useAtom(subscriptionGuideDialogAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/fonts/CalSans-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/fonts/CalSans-SemiBold.otf -------------------------------------------------------------------------------- /apps/web/fonts/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/fonts/Inter-Bold.ttf -------------------------------------------------------------------------------- /apps/web/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'shikwasa' 2 | 3 | declare global { 4 | interface Window { 5 | __SITE__: any 6 | __SITE_ID__: string 7 | __USER_ID__: string 8 | __PLAYER__: any 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/lib/addToIpfs.ts: -------------------------------------------------------------------------------- 1 | import { IPFS_ADD_URL } from '@penx/constants' 2 | 3 | export async function addToIpfs(value: string) { 4 | const res = await fetch(IPFS_ADD_URL, { 5 | method: 'POST', 6 | body: value, 7 | headers: { 'Content-Type': 'application/json' }, 8 | }).then((d) => d.json()) 9 | return res.cid 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/lib/calculateSHA256FromFile.ts: -------------------------------------------------------------------------------- 1 | export async function calculateSHA256FromFile(file: File): Promise { 2 | const buffer: ArrayBuffer = await file.arrayBuffer() 3 | const hashBuffer: ArrayBuffer = await crypto.subtle.digest('SHA-256', buffer) 4 | const hashArray: Uint8Array = new Uint8Array(hashBuffer) 5 | const hashHex: string = Array.from(hashArray) 6 | .map((byte) => byte.toString(16).padStart(2, '0')) 7 | .join('') 8 | return hashHex 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/lib/catalogue/convertToValidHtmlId.ts: -------------------------------------------------------------------------------- 1 | export function convertToValidHtmlId(title: string) { 2 | const sanitizedTitle = title 3 | .toLowerCase() 4 | .replace(/[^\w\s-]/g, '') 5 | .replace(/\s+/g, '-') 6 | .replace(/-+/g, '-') 7 | .trim() 8 | 9 | return sanitizedTitle 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/lib/catalogue/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CatalogueNode' 2 | export * from './CatalogueTree' 3 | export * from './convertToValidHtmlId' 4 | export * from './types' 5 | -------------------------------------------------------------------------------- /apps/web/lib/catalogue/types.ts: -------------------------------------------------------------------------------- 1 | import { ICatalogueNode } from '@penx/model-type' 2 | 3 | export type WithFlattenProps = T & { 4 | parentId: string | null 5 | depth: number 6 | index: number 7 | } 8 | 9 | export interface CreateCatalogueNodeOptions 10 | extends Omit { 11 | folded?: boolean 12 | } 13 | -------------------------------------------------------------------------------- /apps/web/lib/compareVersions.ts: -------------------------------------------------------------------------------- 1 | export function compareVersions(version1: string, version2: string) { 2 | const v1Parts = version1.split('.').map(Number) 3 | const v2Parts = version2.split('.').map(Number) 4 | 5 | for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) { 6 | const v1 = v1Parts[i] || 0 7 | const v2 = v2Parts[i] || 0 8 | 9 | if (v1 < v2) return -1 10 | if (v1 > v2) return 1 11 | } 12 | 13 | return 0 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/lib/dnd-projection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getProjection' 2 | -------------------------------------------------------------------------------- /apps/web/lib/extractTags.ts: -------------------------------------------------------------------------------- 1 | export function extractTags(element: any[]): string[] { 2 | if (!Array.isArray(element)) return [] 3 | 4 | let tags: string[] = [] 5 | 6 | for (const item of element) { 7 | if (!item?.children?.length) continue 8 | const result = item.children 9 | .filter((item: any) => item.type === 'tag') 10 | .map((i: any) => i.name.replace('#', '')) 11 | tags = [...tags, ...result] 12 | } 13 | return tags 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/lib/getBasePublicClient.ts: -------------------------------------------------------------------------------- 1 | import { createPublicClient, http } from 'viem' 2 | import { base, baseSepolia } from 'viem/chains' 3 | import { NetworkNames } from '@penx/constants' 4 | 5 | export function getBasePublicClient(network: string) { 6 | const baseClient = createPublicClient({ 7 | chain: network === NetworkNames.BASE ? base : baseSepolia, 8 | transport: http( 9 | network === NetworkNames.BASE 10 | ? 'https://base-mainnet.g.alchemy.com/v2/gk85VnszAKLshOjVjaQyb_XyQxH93HTq' 11 | : 'https://base-sepolia.g.alchemy.com/v2/gk85VnszAKLshOjVjaQyb_XyQxH93HTq', 12 | ), 13 | }) 14 | return baseClient 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/lib/getDashboardPath.ts: -------------------------------------------------------------------------------- 1 | interface Features { 2 | journal: boolean 3 | gallery: boolean 4 | page: boolean 5 | database: boolean 6 | } 7 | 8 | export function getDashboardPath(site: any) { 9 | if (!site) return '/~/creations?type=ARTICLE' 10 | const { features } = (site.config || {}) as any as { 11 | features: Features 12 | } 13 | 14 | if (features?.journal) { 15 | return '/~/page?id=today' 16 | } else { 17 | return '/~/creations?type=ARTICLE' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/lib/google-drive/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GoogleDrive' 2 | -------------------------------------------------------------------------------- /apps/web/lib/queryClient.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query' 2 | 3 | export const queryClient = new QueryClient() 4 | -------------------------------------------------------------------------------- /apps/web/lib/redirectTo404.ts: -------------------------------------------------------------------------------- 1 | import { notFound, redirect } from 'next/navigation' 2 | import { ROOT_DOMAIN } from '@penx/constants' 3 | 4 | export function redirectTo404() { 5 | notFound() 6 | // redirect(`https://${ROOT_DOMAIN}/404`) 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/lib/remark-slate/index.ts: -------------------------------------------------------------------------------- 1 | import deserialize from './deserialize' 2 | import plugin from './plugin' 3 | import serialize from './serialize' 4 | 5 | export * from './ast-types' 6 | 7 | export { deserialize, serialize } 8 | 9 | export default plugin 10 | -------------------------------------------------------------------------------- /apps/web/lib/remark-slate/plugin.ts: -------------------------------------------------------------------------------- 1 | import { MdastNode, OptionType } from './ast-types' 2 | import transform from './deserialize' 3 | 4 | export default function plugin(opts?: OptionType) { 5 | const compiler = (node: { children: Array }) => { 6 | return node.children.map((c) => transform(c, opts)) 7 | } 8 | 9 | // @ts-ignore 10 | this.Compiler = compiler 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/lib/revalidatePath.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { revalidatePath as nextRevalidatePath } from 'next/cache' 4 | 5 | export async function revalidatePath( 6 | originalPath: string, 7 | type?: 'layout' | 'page', 8 | ) { 9 | nextRevalidatePath(originalPath, type) 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/lib/serializer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './isMarkdown' 2 | -------------------------------------------------------------------------------- /apps/web/lib/serializer/isMarkdown.ts: -------------------------------------------------------------------------------- 1 | export function isMarkdown(text: string): boolean { 2 | const markdownRegex = 3 | /^[\s\S]*?(?:\n\s*[-*]\s+.*|\n\s*#+\s+.*|\n\s*>\s+.*|\n\s*`{3}.*\n[\s\S]*?\n\s*`{3}|\n\s*`.*`|\n\s*!\[.*\]\(.*\)|\n\s*\[.*\]\(.*\)|\n\s*[-*]\s+.*|\n\s*\d+\.\s+.*|\n\s*.*\n\s*[-=]+\n|\n\s*.*\n\s*[-=]+\n\s*)*$/ 4 | return markdownRegex.test(text) 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/lib/serializer/markdownToNodes.ts: -------------------------------------------------------------------------------- 1 | export function markdownToNodes() {} 2 | -------------------------------------------------------------------------------- /apps/web/lib/setStatusBarColor.tsx: -------------------------------------------------------------------------------- 1 | export const setStatusBarColor = (color = '#ffffff') => { 2 | setTimeout(() => { 3 | if (window.matchMedia('(display-mode: standalone)').matches) { 4 | const metaTag = document.querySelector('meta[name="theme-color"]') 5 | if (metaTag) { 6 | metaTag.setAttribute('content', color) 7 | } 8 | } 9 | }, 0) 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/lib/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useCopyToClipboard' 2 | export * from './md5' 3 | export * from './getConnectionState' 4 | -------------------------------------------------------------------------------- /apps/web/lib/shared/md5.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js' 2 | 3 | export function md5(str: string) { 4 | return CryptoJS.MD5(str).toString() 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/lib/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe' 2 | 3 | export const stripe = new Stripe(process.env.STRIPE_API_KEY!, { 4 | apiVersion: '2025-02-24.acacia', 5 | typescript: true, 6 | }) 7 | -------------------------------------------------------------------------------- /apps/web/lib/sync.ts: -------------------------------------------------------------------------------- 1 | import { WorkerEvents } from '@penx/constants' 2 | 3 | export async function sync(isWorker = false) {} 4 | 5 | async function pushToServer(remoteLastUpdatedAt: number) {} 6 | 7 | async function pullFromServer(localLastUpdatedAt: number, isWorker = false) {} 8 | -------------------------------------------------------------------------------- /apps/web/lib/syncPostToHub.ts: -------------------------------------------------------------------------------- 1 | import { NetworkNames } from '@penx/constants' 2 | import { SyncService } from './SyncService' 3 | 4 | export async function syncPostToHub( 5 | site: Site, 6 | creation: Creation, 7 | markdown = '', 8 | ) { 9 | // const token = await api.github.getGitHubToken.query({ 10 | // installationId: site.installationId!, 11 | // }) 12 | // const sync = await SyncService.init(token, site) 13 | // await sync.pushPost(creation, markdown) 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/lib/syncSiteToHub.ts: -------------------------------------------------------------------------------- 1 | import { NetworkNames } from '@penx/constants' 2 | import { SyncService } from './SyncService' 3 | 4 | export async function syncSiteToHub(site: any) { 5 | // const token = await getTokenByInstallationId(site.installationId!) 6 | // const sync = await SyncService.init(token, site) 7 | // await sync.pushSite(site) 8 | } 9 | -------------------------------------------------------------------------------- /apps/web/lib/widget/ClientOnly.tsx: -------------------------------------------------------------------------------- 1 | import React, { PropsWithChildren, useEffect, useState } from 'react' 2 | 3 | export function ClientOnly({ children }: PropsWithChildren) { 4 | // State / Props 5 | const [hasMounted, setHasMounted] = useState(false) 6 | 7 | // Hooks 8 | useEffect(() => { 9 | setHasMounted(true) 10 | }, []) 11 | 12 | // Render 13 | if (!hasMounted) return null 14 | 15 | return <>{children} 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/lib/widget/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ClientOnly' 2 | export * from './motion-components' 3 | export * from './OptionTag' 4 | -------------------------------------------------------------------------------- /apps/web/lib/widget/motion-components.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | import { HTMLMotionProps, motion } from 'motion/react' 3 | import { Button, ButtonProps } from '@penx/uikit/button' 4 | 5 | export const MotionButton: ( 6 | props: HTMLMotionProps<'button'> & ButtonProps, 7 | ) => ReactNode = motion(Button) as any 8 | 9 | export const MotionBox: ( 10 | props: HTMLMotionProps<'div'> & ButtonProps, 11 | ) => ReactNode = motion.div as any 12 | -------------------------------------------------------------------------------- /apps/web/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@penx/uikit/postcss.config"; -------------------------------------------------------------------------------- /apps/web/public/empty-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/empty-state.png -------------------------------------------------------------------------------- /apps/web/public/eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/eth.png -------------------------------------------------------------------------------- /apps/web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/favicon.ico -------------------------------------------------------------------------------- /apps/web/public/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/web/public/images/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/favicon-96x96.png -------------------------------------------------------------------------------- /apps/web/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/favicon.ico -------------------------------------------------------------------------------- /apps/web/public/images/logo-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/logo-1024.png -------------------------------------------------------------------------------- /apps/web/public/images/logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/logo-128.png -------------------------------------------------------------------------------- /apps/web/public/images/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/logo-192.png -------------------------------------------------------------------------------- /apps/web/public/images/logo-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/logo-512.png -------------------------------------------------------------------------------- /apps/web/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/logo.png -------------------------------------------------------------------------------- /apps/web/public/images/screenshots/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/screenshots/screenshot-1.png -------------------------------------------------------------------------------- /apps/web/public/images/screenshots/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/screenshots/screenshot-2.png -------------------------------------------------------------------------------- /apps/web/public/images/screenshots/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/screenshots/screenshot-3.png -------------------------------------------------------------------------------- /apps/web/public/images/screenshots/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/screenshots/screenshot-4.png -------------------------------------------------------------------------------- /apps/web/public/images/screenshots/screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/screenshots/screenshot-5.png -------------------------------------------------------------------------------- /apps/web/public/images/socials/behance.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/behance.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/buymeacoffee.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/buymeacoffee.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/discord.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/discord.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/dribbble.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/dribbble.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/email.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/email.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/facebook.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/facebook.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/figma.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/figma.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/github.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/github.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/gumroad.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/gumroad.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/image.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/image.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/instagram.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/instagram.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/kofi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/kofi.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/layers.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/layers.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/link.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/link.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/linkedin.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/linkedin.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/mastodon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/mastodon.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/medium.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/medium.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/patreon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/patreon.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/pinterest.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/pinterest.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/producthunt.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/producthunt.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/snapchat.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/snapchat.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/soundcloud.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/soundcloud.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/spotify.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/spotify.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/substack.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/substack.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/telegram.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/telegram.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/threads.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/threads.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/tiktok.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/tiktok.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/twitter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/twitter.webp -------------------------------------------------------------------------------- /apps/web/public/images/socials/youtube.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/socials/youtube.webp -------------------------------------------------------------------------------- /apps/web/public/images/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /apps/web/public/images/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/images/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /apps/web/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/logo.png -------------------------------------------------------------------------------- /apps/web/public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/og-image.png -------------------------------------------------------------------------------- /apps/web/public/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/penxio/penx/478cd33532ad8d0742e0c0e61adaa55b9ad82419/apps/web/public/placeholder.png -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "declarationMap": false, 6 | "sourceMap": true, 7 | "lib": ["ESNext", "dom", "dom.iterable"], 8 | "jsx": "preserve", 9 | "baseUrl": ".", 10 | "paths": { 11 | "@/*": ["./*"] 12 | }, 13 | "plugins": [ 14 | { 15 | "name": "next" 16 | } 17 | ], 18 | "module": "esnext" 19 | }, 20 | "include": ["./**/*.ts", "./**/*.tsx", ".next/types/**/*.ts"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'shikwasa' 2 | 3 | declare global { 4 | interface Window { 5 | __SITE__: any 6 | __SITE_ID__: string 7 | __USER_ID__: string 8 | __PLAYER__: any 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/ai/models.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_CHAT_MODEL: string = 'chat-model' 2 | 3 | export interface ChatModel { 4 | id: string 5 | name: string 6 | description: string 7 | } 8 | 9 | export const chatModels: Array = [ 10 | { 11 | id: 'chat-model', 12 | name: 'Chat model', 13 | description: 'Primary model for all-purpose chat', 14 | }, 15 | { 16 | id: 'chat-model-reasoning', 17 | name: 'Reasoning model', 18 | description: 'Uses advanced reasoning', 19 | }, 20 | ] 21 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/ai/tools/create-document.ts: -------------------------------------------------------------------------------- 1 | import { DataStreamWriter, tool } from 'ai' 2 | import { z } from 'zod' 3 | import { uniqueId } from '@penx/unique-id' 4 | 5 | // import { 6 | // artifactKinds, 7 | // documentHandlersByArtifactKind, 8 | // } from '../../../artifacts/server' 9 | 10 | type Session = any 11 | 12 | interface CreateDocumentProps { 13 | session: Session 14 | dataStream: DataStreamWriter 15 | } 16 | 17 | export const createDocument = ({ session, dataStream }: CreateDocumentProps) => 18 | tool({} as any) 19 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/ai/tools/get-weather.ts: -------------------------------------------------------------------------------- 1 | import { tool } from 'ai' 2 | import { z } from 'zod' 3 | 4 | export const getWeather = tool({ 5 | description: 'Get the current weather at a location', 6 | parameters: z.object({ 7 | latitude: z.number(), 8 | longitude: z.number(), 9 | }), 10 | execute: async ({ latitude, longitude }) => { 11 | const response = await fetch( 12 | `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&hourly=temperature_2m&daily=sunrise,sunset&timezone=auto`, 13 | ) 14 | 15 | const weatherData = await response.json() 16 | return weatherData 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/artifacts/actions.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | // import { getSuggestionsByDocumentId } from '@/lib/db/queries'; 4 | 5 | export async function getSuggestions({ documentId }: { documentId: string }) { 6 | // const suggestions = await getSuggestionsByDocumentId({ documentId }); 7 | // return suggestions ?? []; 8 | return [] 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/editor/react-renderer.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from 'react-dom/client' 2 | 3 | export class ReactRenderer { 4 | static render(component: React.ReactElement, dom: HTMLElement) { 5 | const root = createRoot(dom) 6 | root.render(component) 7 | 8 | return { 9 | destroy: () => root.unmount(), 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/src/AIChat/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 4 | import type { ThemeProviderProps } from 'next-themes/dist/types' 5 | 6 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 7 | return {children} 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/src/AISetting/knowledge-setting.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardContent, CardHeader, CardTitle } from '@penx/uikit/card' 2 | 3 | export function KnowledgeSetting() { 4 | return ( 5 | 6 | 7 | Your Knowledge 8 | 9 | 10 |
KnowledgeSetting
11 |
12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /packages/components/src/AreaDialog/useAreaDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { Area } from '@penx/domain' 3 | 4 | type State = { 5 | isOpen: boolean 6 | area: Area 7 | } 8 | 9 | const dialogAtom = atom({ 10 | isOpen: false, 11 | area: null as any, 12 | } as State) 13 | 14 | export function useAreaDialog() { 15 | const [state, setState] = useAtom(dialogAtom) 16 | return { 17 | ...state, 18 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 19 | setState, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/components/src/AreasPopover/DeleteAreaDialog/useDeleteAreaDialog.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | import { Area } from '@penx/domain' 5 | 6 | type State = { 7 | isOpen: boolean 8 | area: Area 9 | } 10 | 11 | const dialogAtom = atom({ 12 | isOpen: false, 13 | area: null as any, 14 | } as State) 15 | 16 | export function useDeleteAreaDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/ClientOnly.tsx: -------------------------------------------------------------------------------- 1 | import React, { PropsWithChildren, useEffect, useState } from 'react' 2 | 3 | export function ClientOnly({ children }: PropsWithChildren) { 4 | // State / Props 5 | const [hasMounted, setHasMounted] = useState(false) 6 | 7 | // Hooks 8 | useEffect(() => { 9 | setHasMounted(true) 10 | }, []) 11 | 12 | // Render 13 | if (!hasMounted) return null 14 | 15 | return <>{children} 16 | } 17 | -------------------------------------------------------------------------------- /packages/components/src/CommandPanel/CommonList.tsx: -------------------------------------------------------------------------------- 1 | import { SearchCreationList } from './SearchCreationList' 2 | 3 | interface Props {} 4 | 5 | export function CommonList({}: Props) { 6 | return ( 7 | <> 8 | 9 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/CommandPanel/hooks/useOpen.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | export const openAtom = atom(false) 4 | 5 | export function useOpen() { 6 | const [open, setOpen] = useAtom(openAtom) 7 | 8 | return { 9 | open, 10 | setOpen, 11 | close: () => setOpen(false), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/src/CommandPanel/hooks/useSearch.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | export const searchAtom = atom('') 4 | export function useSearch() { 5 | const [search, setSearch] = useAtom(searchAtom) 6 | 7 | return { search, setSearch } 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/src/CommandPanel/useCommands.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { ICommandItem } from '@penx/types' 3 | 4 | export const commands: ICommandItem[] = [] 5 | 6 | export const commandsAtom = atom(commands) 7 | 8 | export function useCommands() { 9 | const [commands] = useAtom(commandsAtom) 10 | return { commands } 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/Creation/DeleteCreationDialog/useDeleteCreationDialog.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | import { Creation } from '@penx/domain' 5 | 6 | type State = { 7 | isOpen: boolean 8 | creation: Creation 9 | } 10 | 11 | const dialogAtom = atom({ 12 | isOpen: false, 13 | creation: null as any, 14 | } as State) 15 | 16 | export function useDeleteCreationDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/Creation/PublishDialog/usePublishDialog.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | type State = { 4 | isOpen: boolean 5 | creation: any 6 | } 7 | 8 | const priceDialogAtom = atom({ 9 | isOpen: false, 10 | creation: null as any, 11 | } as State) 12 | 13 | export function usePublishDialog() { 14 | const [state, setState] = useAtom(priceDialogAtom) 15 | return { 16 | ...state, 17 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 18 | setState, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/components/src/Creation/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './PanelCreationProvider' 2 | -------------------------------------------------------------------------------- /packages/components/src/DashboardLayout/SettingsLayout.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ReactNode } from 'react' 4 | 5 | export function SettingsLayout({ children }: { children: ReactNode }) { 6 | return <>{children} 7 | } 8 | -------------------------------------------------------------------------------- /packages/components/src/DashboardLayout/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './DashboardLayout' 2 | -------------------------------------------------------------------------------- /packages/components/src/DashboardLayout/panel-renderer/ManageTags/TagDialog/useTagDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { Tag } from '@penx/domain' 3 | 4 | type State = { 5 | isOpen: boolean 6 | index: number 7 | tag: Tag 8 | } 9 | 10 | const dialogAtom = atom({ 11 | isOpen: false, 12 | index: 0, 13 | tag: null as any, 14 | } as State) 15 | 16 | export function useTagDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/DashboardLayout/panel-renderer/PanelJournal/JournalNav.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@penx/utils' 2 | import { GoToDay } from '../../../GoToDay' 3 | import { JournalShortcut } from './JournalShortcut' 4 | 5 | export const JournalNav = ({ date }: { date: string }) => { 6 | const currentDate = new Date(date ?? Date.now()) 7 | 8 | return ( 9 |
14 | 15 | 16 |
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /packages/components/src/DashboardLayout/panel-renderer/PanelJournal/PanelStruct.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useStructs } from '@penx/hooks/useStructs' 4 | import { Panel } from '@penx/types' 5 | import { FullPageDatabase } from '../../../database-ui' 6 | 7 | interface Props { 8 | panel: Panel 9 | index: number 10 | } 11 | 12 | export function PanelStruct({ panel, index }: Props) { 13 | const { structs } = useStructs() 14 | const struct = structs.find((m) => m.id === panel.structId)! 15 | if (!struct) return null 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /packages/components/src/DeleteStructDialog/useDeleteStructDialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | import { Struct } from '@penx/domain' 5 | 6 | type State = { 7 | isOpen: boolean 8 | struct: Struct 9 | } 10 | 11 | const dialogAtom = atom({ 12 | isOpen: false, 13 | struct: undefined as any, 14 | } as State) 15 | 16 | export function useDeleteStructDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/EngagementTracker.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { usePostEngagement } from '@penx/hooks/usePostEngagement' 4 | 5 | export function EngagementTracker({ creationId }: { creationId: string }) { 6 | usePostEngagement({ 7 | creationId, 8 | }) 9 | 10 | return null 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/Fallback/ReloadAppBtn.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@penx/uikit/ui/button' 2 | 3 | export const ReloadAppBtn = () => { 4 | async function reloadApp() { 5 | window.location.reload() 6 | } 7 | 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/src/GoogleOauthDialog/useGoogleOauthDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const googleOauthDialogAtom = atom(false) 4 | 5 | export function useGoogleOauthDialog() { 6 | const [isOpen, setIsOpen] = useAtom(googleOauthDialogAtom) 7 | return { isOpen, setIsOpen } 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/src/Image.tsx: -------------------------------------------------------------------------------- 1 | import NextImage, { ImageProps } from 'next/image' 2 | import { STATIC_URL } from '@penx/constants' 3 | 4 | const basePath = process.env.BASE_PATH 5 | 6 | export const Image = ({ src, ...rest }: ImageProps) => { 7 | if (typeof src === 'string' && src.startsWith(STATIC_URL)) { 8 | return 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/Logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | interface Props { 4 | className?: string 5 | } 6 | export function Logo({ className }: Props) { 7 | return ( 8 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /packages/components/src/PageRender.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import Image from 'next/image' 4 | import { getUrl } from '@penx/utils' 5 | 6 | interface Props { 7 | content: any 8 | } 9 | 10 | export function PageRender({ content }: Props) { 11 | return null 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/src/PasswordDialog/usePasswordDialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const passwordDialogAtom = atom(false) 6 | 7 | export function usePasswordDialog() { 8 | const [isOpen, setIsOpen] = useAtom(passwordDialogAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/src/PlanList/PricingSlogan.tsx: -------------------------------------------------------------------------------- 1 | export function PricingSlogan() { 2 | return ( 3 |
4 |
5 |
Pricing
6 |
7 |
8 | Become a member of PenX 9 |
10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/src/PlanList/useBillingCycle.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | export enum BillingCycle { 6 | MONTHLY = 'MONTHLY', 7 | YEARLY = 'YEARLY', 8 | } 9 | 10 | const billingCycleAtom = atom(BillingCycle.MONTHLY) 11 | 12 | export function useBillingCycle() { 13 | const [cycle, setCycle] = useAtom(billingCycleAtom) 14 | return { 15 | cycle, 16 | isMonthly: cycle === BillingCycle.MONTHLY, 17 | setCycle, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/components/src/PlanList/usePlanListDialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const planListDialogAtom = atom(false) 6 | 7 | export function usePlanListDialog() { 8 | const [isOpen, setIsOpen] = useAtom(planListDialogAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/src/PublishStructDialog/usePublishStructDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { Struct } from '@penx/domain' 3 | 4 | type State = { 5 | isOpen: boolean 6 | struct: Struct 7 | } 8 | 9 | const dialogAtom = atom({ 10 | isOpen: false, 11 | struct: null as any, 12 | } as State) 13 | 14 | export function usePublishStructDialog() { 15 | const [state, setState] = useAtom(dialogAtom) 16 | return { 17 | ...state, 18 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 19 | setState, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/components/src/Sidebar/LinkAccountEntry.tsx: -------------------------------------------------------------------------------- 1 | import { LinkGoogleEntry } from './LinkGoogleEntry' 2 | 3 | export default function LinkAccountEntry() { 4 | return ( 5 | <> 6 | 7 | 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/src/StructDialog/useStructDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { Struct } from '@penx/domain' 3 | 4 | type State = { 5 | isOpen: boolean 6 | struct: Struct 7 | } 8 | 9 | const dialogAtom = atom({ 10 | isOpen: false, 11 | struct: null as any, 12 | } as State) 13 | 14 | export function useStructDialog() { 15 | const [state, setState] = useAtom(dialogAtom) 16 | return { 17 | ...state, 18 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 19 | setState, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/components/src/SwitchChainDialog/useSwitchChainDialog.tsx: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const switchChainDialogAtom = atom(false) 4 | export function useSwitchChainDialog() { 5 | const [isOpen, setIsOpen] = useAtom(switchChainDialogAtom) 6 | return { isOpen, setIsOpen } 7 | } 8 | -------------------------------------------------------------------------------- /packages/components/src/TextLogo.tsx: -------------------------------------------------------------------------------- 1 | import { Philosopher } from 'next/font/google' 2 | import { cn } from '@penx/utils' 3 | 4 | const logoFont = Philosopher({ 5 | weight: ['400', '700'], 6 | subsets: ['latin'], 7 | display: 'swap', 8 | }) 9 | 10 | interface Props { 11 | className?: string 12 | } 13 | 14 | export function TextLogo({ className }: Props) { 15 | return ( 16 |
19 | PenX 20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/src/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 5 | import { type ThemeProviderProps } from 'next-themes/dist/types' 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/src/area-widgets/components/NoCreationYet.tsx: -------------------------------------------------------------------------------- 1 | import { Trans } from '@lingui/react/macro' 2 | 3 | export function NoCreationYet() { 4 | return ( 5 |
6 |
7 | No creation yet! 8 |
9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/area-widgets/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './AreaWidgets' 2 | -------------------------------------------------------------------------------- /packages/components/src/area-widgets/widgets/AIChatHistorys.tsx: -------------------------------------------------------------------------------- 1 | import { Trans } from '@lingui/react/macro' 2 | 3 | export function AIChatHistorys() { 4 | return ( 5 |
6 |
7 | No chat history yet! 8 |
9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/src/blur-image.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useState } from 'react' 4 | import type { ComponentProps } from 'react' 5 | import cn from 'clsx' 6 | import Image from 'next/image' 7 | 8 | export default function BlurImage(props: ComponentProps) { 9 | const [isLoading, setLoading] = useState(true) 10 | 11 | return ( 12 | {props.alt} setLoading(false)} 21 | /> 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/InlineDatabase.tsx: -------------------------------------------------------------------------------- 1 | import { DATABASE_TOOLBAR_HEIGHT, WORKBENCH_NAV_HEIGHT } from '@penx/constants' 2 | import { Separator } from '@penx/uikit/separator' 3 | import { DatabaseProvider } from './DatabaseProvider' 4 | import { ViewList } from './ViewNav/ViewList' 5 | import { TableView } from './views/TableView/TableView' 6 | import { ViewToolBar } from './ViewToolBar/ViewToolBar' 7 | 8 | interface Props { 9 | node: Node 10 | } 11 | 12 | export const InlineDatabase = ({ node }: Props) => { 13 | return null 14 | } 15 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/RowForm.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { forwardRef } from 'react' 4 | import { FieldIcon } from '../FieldIcon' 5 | 6 | interface Props { 7 | databaseId: string 8 | rowId: string 9 | } 10 | 11 | export const RowForm = forwardRef(function RowForm( 12 | { databaseId, rowId }, 13 | ref, 14 | ) { 15 | return null 16 | }) 17 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/ViewToolBar/TableField/index.tsx: -------------------------------------------------------------------------------- 1 | export const TableField = () => { 2 | const onUndo = () => { 3 | // TODO 4 | /* 5 | if(canUndo){ 6 | undo() 7 | } 8 | */ 9 | } 10 | 11 | const onRedo = () => { 12 | // TODO 13 | /* 14 | if(canRedo){ 15 | redo() 16 | } 17 | */ 18 | } 19 | 20 | return ( 21 |
22 |
23 | Undo 24 |
25 | 26 |
27 | Redo 28 |
29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/columnWidthMotion.ts: -------------------------------------------------------------------------------- 1 | import { MotionValue } from 'motion/react' 2 | 3 | export const columnWidthMotion: Record = {} 4 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/index.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export * from './FullPageDatabase' 4 | export * from './InlineDatabase' 5 | export * from './ViewToolBar/FilterField/OperatorSelect' 6 | export * from './ViewToolBar/ToolbarBtn' 7 | export * from './RowForm' 8 | export * from './DatabaseProvider' 9 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/views/GalleryView/Notes/NoteList.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useQuery } from '@tanstack/react-query' 4 | import { useNotes } from '@penx/hooks/useNotes' 5 | import { NoteItem } from './NoteItem' 6 | 7 | export function NoteList() { 8 | const notes = useNotes() 9 | 10 | // TODO: 11 | const { isLoading, isFetching } = useQuery({ 12 | queryKey: ['notes', 'loading'], 13 | queryFn: async () => 0, 14 | }) 15 | 16 | if (isLoading || isFetching) return
17 | 18 | return ( 19 | <> 20 | {notes.map((note) => { 21 | return 22 | })} 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/views/TableView/ConfigColumnDialog/useConfigColumnDialog.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | import { IColumn } from '@penx/model-type' 5 | 6 | type State = { 7 | isOpen: boolean 8 | column: IColumn 9 | } 10 | 11 | const dialogAtom = atom({ 12 | isOpen: false, 13 | column: null as any, 14 | } as State) 15 | 16 | export function useConfigColumnDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/views/TableView/DeleteColumnDialog/useDeleteColumnDialog.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | import { IColumn } from '@penx/model-type' 5 | 6 | type State = { 7 | isOpen: boolean 8 | column: IColumn 9 | } 10 | 11 | const dialogAtom = atom({ 12 | isOpen: false, 13 | column: null as any, 14 | } as State) 15 | 16 | export function useDeleteColumnDialog() { 17 | const [state, setState] = useAtom(dialogAtom) 18 | return { 19 | ...state, 20 | setIsOpen: (isOpen: boolean) => setState({ ...state, isOpen }), 21 | setState, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/views/TableView/hooks/useFieldTypeSelectPopover.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const fieldTypeSelectPopover = atom(false) 4 | 5 | export function useFieldTypeSelectPopover() { 6 | const [isOpen, setIsOpen] = useAtom(fieldTypeSelectPopover) 7 | return { isOpen, setIsOpen } 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/src/database-ui/views/TableView/hooks/useTableView/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './useTableView' 2 | -------------------------------------------------------------------------------- /packages/components/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'shikwasa' 2 | -------------------------------------------------------------------------------- /packages/components/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ThemeProvider' 2 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "moduleResolution": "bundler", 7 | "declarationMap": false, 8 | "declaration": false, 9 | "strict": true, 10 | "strictNullChecks": true, 11 | "outDir": "dist" 12 | }, 13 | "include": ["."], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/constants/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/constants", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": { 20 | "@penx/types": "workspace:*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/constants/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './basic.constants' 2 | export * from './element-type' 3 | export * from './urls.constants' 4 | export * from './redisKeys' 5 | export * from './schema.constants' 6 | -------------------------------------------------------------------------------- /packages/constants/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "lib": ["DOM"], 5 | "outDir": "dist" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/content-render/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ContentRender' 2 | -------------------------------------------------------------------------------- /packages/content-render/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/contexts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/contexts", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | "./*": "./src/*.tsx" 11 | }, 12 | "scripts": { 13 | "brl": "barrelsby --delete -d ./src", 14 | "lint": "eslint . --max-warnings 0", 15 | "check-types": "tsc --noEmit" 16 | }, 17 | "devDependencies": { 18 | "@penx/typescript-config": "workspace:*" 19 | }, 20 | "dependencies": { 21 | "@penx/constants": "workspace:*", 22 | "@penx/model-type": "workspace:*", 23 | "@penx/types": "workspace:*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/contexts/src/CreationContext.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { createContext, PropsWithChildren, useContext } from 'react' 4 | 5 | export const CreationContext = createContext({} as any) 6 | 7 | interface Props { 8 | creation: any 9 | } 10 | 11 | export const CreationProvider = ({ 12 | creation, 13 | children, 14 | }: PropsWithChildren) => { 15 | return ( 16 | 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | export function useCreationContext() { 23 | const creation = useContext(CreationContext) 24 | return creation 25 | } 26 | -------------------------------------------------------------------------------- /packages/contexts/src/FriendsContext.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { createContext, PropsWithChildren, useContext } from 'react' 4 | import { Friend } from '@penx/types' 5 | 6 | export const FriendsContext = createContext({} as Friend[]) 7 | 8 | interface Props { 9 | friends: Friend[] 10 | } 11 | 12 | export const FriendsProvider = ({ 13 | friends, 14 | children, 15 | }: PropsWithChildren) => { 16 | return ( 17 | 18 | {children} 19 | 20 | ) 21 | } 22 | 23 | export function useFriendsContext() { 24 | const friends = useContext(FriendsContext) 25 | return friends 26 | } 27 | -------------------------------------------------------------------------------- /packages/contexts/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Automatically generated by barrelsby. 3 | */ 4 | 5 | export * from './CreationContext' 6 | export * from './CreationsContext' 7 | export * from './FriendsContext' 8 | export * from './ProjectsContext' 9 | export * from './SiteContext' 10 | -------------------------------------------------------------------------------- /packages/contexts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "declarationMap": false, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src"], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/domain/src/EthBalance.ts: -------------------------------------------------------------------------------- 1 | import { precision } from '@penx/math' 2 | 3 | export class EthBalance { 4 | constructor(private _value: bigint) {} 5 | 6 | get value() { 7 | return this._value 8 | } 9 | 10 | get valueDecimal() { 11 | return precision.toDecimal(this.value) 12 | } 13 | 14 | get valueFormatted() { 15 | return this.valueDecimal.toFixed(4) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/domain/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Creation' 2 | export * from './EthBalance' 3 | export * from './Subscription' 4 | export * from './Site' 5 | export * from './Node' 6 | export * from './Area' 7 | export * from './Struct' 8 | export * from './Creation' 9 | export * from './Tag' 10 | export * from './CreationTag' 11 | export * from './Journal' 12 | -------------------------------------------------------------------------------- /packages/domain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/emitter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/emitter", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": { 20 | "@penx/types": "workspace:*", 21 | "@penx/model-type": "workspace:*" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/emitter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/encryption/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/encryption", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/encryption/src/calculateSHA256FromFile.ts: -------------------------------------------------------------------------------- 1 | export async function calculateSHA256FromFile(file: File): Promise { 2 | const buffer: ArrayBuffer = await file.arrayBuffer() 3 | const hashBuffer: ArrayBuffer = await crypto.subtle.digest('SHA-256', buffer) 4 | const hashArray: Uint8Array = new Uint8Array(hashBuffer) 5 | const hashHex: string = Array.from(hashArray) 6 | .map((byte) => byte.toString(16).padStart(2, '0')) 7 | .join('') 8 | return hashHex 9 | } 10 | -------------------------------------------------------------------------------- /packages/encryption/src/decryptString.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js' 2 | 3 | /** Decryption function */ 4 | export function decryptString(cipherTextWithIV: string, secretKey: string) { 5 | const key = CryptoJS.enc.Utf8.parse(secretKey) 6 | const iv = CryptoJS.enc.Hex.parse(cipherTextWithIV.slice(0, 32)) 7 | const encryptedText = cipherTextWithIV.slice(32) 8 | const decrypted = CryptoJS.AES.decrypt(encryptedText, key, { 9 | iv, 10 | mode: CryptoJS.mode.CFB, 11 | padding: CryptoJS.pad.Pkcs7, 12 | }) 13 | 14 | return decrypted.toString(CryptoJS.enc.Utf8) 15 | } 16 | -------------------------------------------------------------------------------- /packages/encryption/src/encryptString.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js' 2 | 3 | export function encryptString(plainText: string, secretKey: string) { 4 | const key = CryptoJS.enc.Utf8.parse(secretKey) 5 | // random IV 6 | const iv = CryptoJS.lib.WordArray.random(16) 7 | const encrypted = CryptoJS.AES.encrypt( 8 | CryptoJS.enc.Utf8.parse(plainText), 9 | key, 10 | { 11 | iv, 12 | mode: CryptoJS.mode.CFB, 13 | padding: CryptoJS.pad.Pkcs7, 14 | }, 15 | ) 16 | 17 | return iv.toString() + encrypted.toString() 18 | } 19 | -------------------------------------------------------------------------------- /packages/encryption/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './calculateSHA256FromFile' 2 | export * from './calculateSHA256FromString' 3 | export * from './encryptString' 4 | export * from './decryptString' 5 | -------------------------------------------------------------------------------- /packages/encryption/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-debounce' 2 | -------------------------------------------------------------------------------- /packages/hooks/src/use-debounce.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export const useDebounce = (value: T, delay = 500) => { 4 | const [debouncedValue, setDebouncedValue] = React.useState(value) 5 | 6 | React.useEffect(() => { 7 | const handler: NodeJS.Timeout = setTimeout(() => { 8 | setDebouncedValue(value) 9 | }, delay) 10 | 11 | // Cancel the timeout if value changes (also on delay change or unmount) 12 | return () => { 13 | clearTimeout(handler) 14 | } 15 | }, [value, delay]) 16 | 17 | return debouncedValue 18 | } 19 | -------------------------------------------------------------------------------- /packages/hooks/src/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener('change', onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener('change', onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /packages/hooks/src/use-mounted.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export function useMounted() { 4 | const [mounted, setMounted] = React.useState(false) 5 | 6 | React.useEffect(() => { 7 | setMounted(true) 8 | }, []) 9 | 10 | return mounted 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useActiveStruct.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | import { Struct } from '@penx/domain' 3 | 4 | const activeAtom = atom(null) 5 | 6 | export function useActiveStruct() { 7 | const [struct, setStruct] = useAtom(activeAtom) 8 | 9 | return { 10 | struct, 11 | setStruct, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/hooks/src/useAppLoading.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | export const appLoading = atom(false) 4 | export function useAppLoading() { 5 | const [loading, setLoading] = useAtom(appLoading) 6 | return { loading, setLoading } 7 | } 8 | -------------------------------------------------------------------------------- /packages/hooks/src/useArea.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Area } from '@penx/domain' 3 | import { areaAtom } from '@penx/store' 4 | 5 | export function useArea() { 6 | const raw = useAtomValue(areaAtom) 7 | return { 8 | raw, 9 | area: new Area(raw), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useAreas.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Area } from '@penx/domain' 3 | import { areasAtom } from '@penx/store' 4 | 5 | export function useAreas() { 6 | const raw = useAtomValue(areasAtom) 7 | return { 8 | raw, 9 | areas: raw.map((area) => new Area(area)), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useAuthStatus.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | type State = { 6 | type: 'login' | 'register' | 'register-email-sent' 7 | data?: Record 8 | } 9 | const authStatusAtom = atom({ 10 | type: 'login', 11 | data: {}, 12 | } as State) 13 | 14 | export function useAuthStatus() { 15 | const [authStatus, setAuthStatus] = useAtom(authStatusAtom) 16 | return { authStatus, setAuthStatus } 17 | } 18 | -------------------------------------------------------------------------------- /packages/hooks/src/useCommands.ts: -------------------------------------------------------------------------------- 1 | import { useAtom } from 'jotai' 2 | import { commandsAtom } from '@penx/store' 3 | 4 | export function useCommands() { 5 | const [commands] = useAtom(commandsAtom) 6 | return { commands } 7 | } 8 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreationId.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | export const creationIdAtom = atom('') 4 | 5 | export function useCreationId() { 6 | const [creationId, setCreationId] = useAtom(creationIdAtom) 7 | return { creationId, setCreationId } 8 | } 9 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreationStruct.ts: -------------------------------------------------------------------------------- 1 | import { Creation } from '@penx/domain' 2 | import { useStructs } from '@penx/hooks/useStructs' 3 | 4 | export function useCreationStruct(creation: Creation) { 5 | const { structs } = useStructs() 6 | const struct = structs.find((m) => m.id === creation.structId) 7 | return struct! 8 | } 9 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreationTags.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { CreationTag } from '@penx/domain' 3 | import { creationTagsAtom } from '@penx/store' 4 | 5 | export function useCreationTags() { 6 | const raw = useAtomValue(creationTagsAtom) 7 | 8 | const creationTags = raw.map((i) => new CreationTag(i)) 9 | return { 10 | creationTags, 11 | queryByCreation(creationId: string) { 12 | return creationTags 13 | .filter((tag) => tag.creationId === creationId) 14 | .sort( 15 | (a, b) => 16 | new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(), 17 | ) 18 | }, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreations.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Creation } from '@penx/domain' 3 | import { creationsAtom } from '@penx/store' 4 | 5 | export function useCreations() { 6 | const raw = useAtomValue(creationsAtom) 7 | 8 | const creations = raw 9 | .map((i) => new Creation(i)) 10 | .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) 11 | 12 | function creationsByStruct(structId: string) { 13 | return creations.filter((creation) => creation.structId === structId) 14 | } 15 | 16 | return { 17 | raw, 18 | creationsByStruct, 19 | creations, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/hooks/src/useDetectClickOutside.ts: -------------------------------------------------------------------------------- 1 | import { RefObject, useEffect } from 'react' 2 | 3 | export function useDetectClickOutside( 4 | ref: RefObject, 5 | callback: () => void, 6 | ) { 7 | useEffect(() => { 8 | function handleClickOutside(event: MouseEvent) { 9 | if (ref.current && !ref.current.contains(event.target as Node)) { 10 | callback() 11 | } 12 | } 13 | document.addEventListener('mousedown', handleClickOutside) 14 | return () => { 15 | document.removeEventListener('mousedown', handleClickOutside) 16 | } 17 | }, [ref, callback]) 18 | } 19 | 20 | export default useDetectClickOutside 21 | -------------------------------------------------------------------------------- /packages/hooks/src/useJournals.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Journal } from '@penx/domain' 3 | import { journalsAtom } from '@penx/store' 4 | 5 | export function useJournals() { 6 | const raw = useAtomValue(journalsAtom) 7 | return { 8 | raw, 9 | journals: raw.map((r) => new Journal(r) as Journal), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useMobileMenu.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom, useAtomValue } from 'jotai' 2 | 3 | export const mobileMenuAtom = atom({} as any) 4 | 5 | export function useMobileMenu() { 6 | const [menu, setMenu] = useAtom(mobileMenuAtom) 7 | return { 8 | close: () => { 9 | return menu.current?.close() 10 | }, 11 | open: () => menu.current?.open(), 12 | menu, 13 | setMenu, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hooks/src/useMobileNav.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom, useAtomValue } from 'jotai' 2 | 3 | export const mobileNavAtom = atom({} as any) 4 | 5 | export function useMobileNav() { 6 | const [nav, setNav] = useAtom(mobileNavAtom) 7 | return { 8 | routeToHome: () => { 9 | nav.current?.popToRoot() 10 | }, 11 | open: () => nav.current?.open(), 12 | nav, 13 | setNav, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/hooks/src/useMySite.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Site } from '@penx/domain' 3 | import { siteAtom } from '@penx/store' 4 | 5 | export function useMySite() { 6 | const raw = useAtomValue(siteAtom) 7 | return { 8 | raw, 9 | site: new Site(raw), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useNotes.ts: -------------------------------------------------------------------------------- 1 | import { produce } from 'immer' 2 | import { useCreations } from '@penx/hooks/useCreations' 3 | import { StructType } from '@penx/types' 4 | 5 | export function useNotes() { 6 | const { creations } = useCreations() 7 | const notes = produce(creations, (draft) => { 8 | return draft 9 | .filter((creation) => creation.type === StructType.NOTE) 10 | .sort((a, b) => { 11 | return new Date(b.updatedAt).getTime() - a.updatedAt.getTime() 12 | }) 13 | }) 14 | return notes 15 | } 16 | -------------------------------------------------------------------------------- /packages/hooks/src/usePaletteDrawer.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const paletteDrawerAtom = atom(false) 4 | 5 | export function usePaletteDrawer() { 6 | const [isOpen, setIsOpen] = useAtom(paletteDrawerAtom) 7 | return { 8 | isOpen, 9 | open: () => setIsOpen(true), 10 | close: () => setIsOpen(false), 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/hooks/src/usePanels.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { panelsAtom } from '@penx/store' 3 | import { PanelType } from '@penx/types' 4 | 5 | export function usePanels() { 6 | const panels = useAtomValue(panelsAtom) 7 | const isCreationInPanels = (creationId: string) => { 8 | return panels.some( 9 | (p) => p.type === PanelType.CREATION && p?.creationId === creationId, 10 | ) 11 | } 12 | return { 13 | panels, 14 | isCreationInPanels, 15 | journalPanel: panels.find((p) => p.type === PanelType.JOURNAL)!, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/hooks/src/usePostLoading.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | export const postLoadingAtom = atom(false) 6 | 7 | export function usePostLoading() { 8 | const [isPostLoading, setPostLoading] = useAtom(postLoadingAtom) 9 | return { isPostLoading, setPostLoading } 10 | } 11 | -------------------------------------------------------------------------------- /packages/hooks/src/usePostSaving.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | export const postSavingAtom = atom(false) 6 | 7 | export function usePostSaving() { 8 | const [isPostSaving, setPostSaving] = useAtom(postSavingAtom) 9 | return { isPostSaving, setPostSaving } 10 | } 11 | -------------------------------------------------------------------------------- /packages/hooks/src/useQuickAdd.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const quickAddAtom = atom(false) 4 | const colorNameAtom = atom('#ffffff') 5 | 6 | export function useQuickAdd() { 7 | const [isOpen, setIsOpen] = useAtom(quickAddAtom) 8 | const [colorName, setColorName] = useAtom(colorNameAtom) 9 | return { 10 | isOpen, 11 | setIsOpen, 12 | colorName, 13 | setColorName, 14 | open: () => setIsOpen(true), 15 | close: () => setIsOpen(false), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/hooks/src/useRouterName.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { routerAtom } from '@penx/store' 3 | 4 | export function useRouterName() { 5 | const { name } = useAtomValue(routerAtom) 6 | return name 7 | } 8 | -------------------------------------------------------------------------------- /packages/hooks/src/useSidebarDrawer.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | const sidebarDrawerAtom = atom(false) 4 | 5 | export function useSidebarDrawer() { 6 | const [isOpen, setIsOpen] = useAtom(sidebarDrawerAtom) 7 | return { 8 | isOpen, 9 | open: () => setIsOpen(true), 10 | close: () => setIsOpen(false), 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/hooks/src/useSpaces.ts: -------------------------------------------------------------------------------- 1 | import { getSpaces } from '@/lib/getSpaces' 2 | import { useQuery } from '@tanstack/react-query' 3 | 4 | export function useSpaces() { 5 | return useQuery({ 6 | queryKey: ['spaces'], 7 | queryFn: async () => { 8 | return getSpaces() 9 | }, 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/src/useStructId.ts: -------------------------------------------------------------------------------- 1 | import { atom, useAtom } from 'jotai' 2 | 3 | export const structIdAtom = atom('') 4 | 5 | export function useStructId() { 6 | const [structId, setStructId] = useAtom(structIdAtom) 7 | return { structId, setStructId } 8 | } 9 | -------------------------------------------------------------------------------- /packages/hooks/src/useTags.ts: -------------------------------------------------------------------------------- 1 | import { useAtomValue } from 'jotai' 2 | import { Tag } from '@penx/domain' 3 | import { tagsAtom } from '@penx/store' 4 | 5 | export function useTags() { 6 | const raw = useAtomValue(tagsAtom) 7 | return { 8 | raw, 9 | tags: raw.map((t) => new Tag(t)), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "declarationMap": false, 6 | "strict": true, 7 | "strictNullChecks": true, 8 | "outDir": "dist" 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/libs/src/hashPassword.ts: -------------------------------------------------------------------------------- 1 | import { genSaltSync, hashSync } from 'bcrypt-edge' 2 | 3 | export async function hashPassword(password: string) { 4 | const salt = genSaltSync(10) 5 | return hashSync(password, salt) 6 | } 7 | -------------------------------------------------------------------------------- /packages/libs/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cache-header' 2 | -------------------------------------------------------------------------------- /packages/libs/src/revalidateTag.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { revalidateTag } from 'next/cache' 4 | 5 | export async function revalidateMetadata(key: string) { 6 | revalidateTag(key) 7 | } 8 | -------------------------------------------------------------------------------- /packages/libs/src/stripe.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe' 2 | 3 | export const stripe = new Stripe(process.env.STRIPE_API_KEY!, { 4 | apiVersion: '2025-02-24.acacia', 5 | typescript: true, 6 | }) 7 | -------------------------------------------------------------------------------- /packages/libs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "declarationMap": false, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src"], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/local-db/src/emitter.ts: -------------------------------------------------------------------------------- 1 | import mitt from 'mitt' 2 | import { INode } from '@penx/model-type' 3 | 4 | export type DBEvents = { 5 | REF_NODE_UPDATED: INode 6 | } 7 | 8 | export const emitter = mitt() 9 | -------------------------------------------------------------------------------- /packages/local-db/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './local-db' 2 | export * from './emitter' 3 | export * from './libs/getRandomColor' 4 | export * from './libs/array-sorter' 5 | export * from './libs/formatTagName' 6 | -------------------------------------------------------------------------------- /packages/local-db/src/libs/formatTagName.ts: -------------------------------------------------------------------------------- 1 | export function formatTagName(name = '') { 2 | return name.trim().replace(/\s+/g, '-').toLowerCase() 3 | } 4 | -------------------------------------------------------------------------------- /packages/local-db/src/libs/formatToDate.ts: -------------------------------------------------------------------------------- 1 | import { format } from 'date-fns' 2 | 3 | export function formatToDate(date: Date): string { 4 | return format(date, 'yyyy-MM-dd') 5 | } 6 | -------------------------------------------------------------------------------- /packages/local-db/src/libs/getRandomColor.ts: -------------------------------------------------------------------------------- 1 | export function getColorNames(postfix = '500') { 2 | // const keys = Object.keys(colors).filter( 3 | // (i) => 4 | // i.endsWith(postfix) && 5 | // !/gray|slate|zinc|neutral|stone/i.test(i.toLowerCase()), 6 | // ) 7 | 8 | // return keys 9 | return [] as string[] 10 | } 11 | 12 | export function getRandomColor(postfix = '500'): string { 13 | const keys = getColorNames(postfix) 14 | const index = Math.floor(Math.random() * keys.length) 15 | 16 | return keys[index]! 17 | } 18 | -------------------------------------------------------------------------------- /packages/local-db/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface AddRowOptions { 2 | databaseId: string 3 | 4 | type?: 'common' | 'todo' | 'file' 5 | 6 | ref?: string // first column id 7 | 8 | sourceId?: string // todo source id 9 | 10 | fileHash?: string // file hash 11 | 12 | googleDriveFileId?: string // google drive file id 13 | } 14 | 15 | export interface AddRowByFieldNameOptions { 16 | databaseId: string 17 | [key: string]: any 18 | } 19 | 20 | export interface CreateFileRowOptions { 21 | userId: string 22 | 23 | ref: string // first column id 24 | 25 | fileHash: string // file hash 26 | 27 | googleDriveFileId: string // google drive file id 28 | } 29 | -------------------------------------------------------------------------------- /packages/local-db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "declarationMap": false, 5 | "declaration": false, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src"], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/locales/src/LocaleProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect, useMemo } from 'react' 4 | import { i18n } from '@lingui/core' 5 | import { I18nProvider } from '@lingui/react' 6 | import { isBrowser } from '@penx/constants' 7 | import { dynamicActivate } from './dynamicActivate' 8 | 9 | type Props = { 10 | children: React.ReactNode 11 | locale?: string 12 | } 13 | 14 | export const LocaleProvider = ({ children, locale }: Props) => { 15 | useEffect(() => { 16 | dynamicActivate(locale) 17 | }, []) 18 | return {children} 19 | } 20 | -------------------------------------------------------------------------------- /packages/locales/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dynamicActivate' 2 | export * from './LocaleProvider' 3 | -------------------------------------------------------------------------------- /packages/locales/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "moduleResolution": "bundler", 7 | "declarationMap": false, 8 | "declaration": false, 9 | "strict": true, 10 | "strictNullChecks": true, 11 | "outDir": "dist" 12 | }, 13 | "include": ["."], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/math/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/math", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": { 20 | "@penx/types": "workspace:*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/math/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './math' 2 | export * from './precision' 3 | -------------------------------------------------------------------------------- /packages/math/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/model-type/src/IAsset.ts: -------------------------------------------------------------------------------- 1 | export interface IAsset { 2 | id: string 3 | url: string 4 | filename: string 5 | title: string 6 | description: string 7 | contentType: string 8 | isPublic: boolean 9 | isTrashed: boolean 10 | size: number 11 | userId: string 12 | siteId: string 13 | sharingConfig: any 14 | props: any 15 | createdAt: Date 16 | uploadedAt: Date 17 | updatedAt: Date 18 | assetLabels: any 19 | } 20 | -------------------------------------------------------------------------------- /packages/model-type/src/IChange.ts: -------------------------------------------------------------------------------- 1 | export enum OperationType { 2 | CREATE = 'CREATE', 3 | UPDATE = 'UPDATE', 4 | DELETE = 'DELETE', 5 | } 6 | 7 | export interface IChange { 8 | id: number 9 | operation: OperationType 10 | siteId: string 11 | key: string 12 | data?: any 13 | synced: number // 0 - not synced, 1 - synced 14 | createdAt: Date 15 | } 16 | -------------------------------------------------------------------------------- /packages/model-type/src/IChat.ts: -------------------------------------------------------------------------------- 1 | export interface IChat { 2 | id: string 3 | title: string 4 | userId: string 5 | visibility: 'public' | 'private' 6 | siteId: string 7 | createdAt: Date 8 | } 9 | -------------------------------------------------------------------------------- /packages/model-type/src/IColumn.ts: -------------------------------------------------------------------------------- 1 | import { ColumnType, Option } from '@penx/types' 2 | 3 | export interface IColumn { 4 | id: string 5 | slug: string 6 | name: string 7 | description: string 8 | columnType: ColumnType 9 | config: any 10 | options: Option[] 11 | isPrimary: boolean 12 | createdAt: Date 13 | updatedAt: Date 14 | } 15 | -------------------------------------------------------------------------------- /packages/model-type/src/IDatabase.ts: -------------------------------------------------------------------------------- 1 | export interface IDatabase { 2 | id: string 3 | userId: string 4 | siteId: string 5 | parentId: string 6 | parentType: string 7 | activeViewId: string 8 | viewIds: any[] 9 | name: string 10 | color: string 11 | cover: string 12 | icon: string 13 | trashed: boolean 14 | props: any 15 | createdAt: Date 16 | updatedAt: Date 17 | } 18 | -------------------------------------------------------------------------------- /packages/model-type/src/IDocument.ts: -------------------------------------------------------------------------------- 1 | export interface IDocument { 2 | id: string 3 | title: string 4 | content: string 5 | kind: 'text' | 'code' | 'image' | 'sheet' 6 | userId: string 7 | siteId: string 8 | createdAt: Date 9 | } 10 | -------------------------------------------------------------------------------- /packages/model-type/src/IDomain.ts: -------------------------------------------------------------------------------- 1 | export interface IDomain { 2 | id: string 3 | domain: string 4 | isSubdomain: boolean 5 | subdomainType: any 6 | disabled: boolean 7 | siteId: string 8 | } 9 | -------------------------------------------------------------------------------- /packages/model-type/src/IField.ts: -------------------------------------------------------------------------------- 1 | export interface IField { 2 | id: string 3 | } 4 | -------------------------------------------------------------------------------- /packages/model-type/src/IFile.ts: -------------------------------------------------------------------------------- 1 | export interface IFile { 2 | id: string 3 | 4 | hash: string 5 | 6 | file: File 7 | } 8 | -------------------------------------------------------------------------------- /packages/model-type/src/IMessage.ts: -------------------------------------------------------------------------------- 1 | export interface IMessage { 2 | id: string 3 | chatId: string 4 | role: 'system' | 'user' | 'assistant' | 'data' 5 | parts: any 6 | attachments?: any 7 | siteId: string 8 | createdAt: Date 9 | } 10 | -------------------------------------------------------------------------------- /packages/model-type/src/IRecord.ts: -------------------------------------------------------------------------------- 1 | export interface IRecord { 2 | id: string 3 | } 4 | -------------------------------------------------------------------------------- /packages/model-type/src/ISuggestion.ts: -------------------------------------------------------------------------------- 1 | export interface ISuggestion { 2 | id: string 3 | documentId: string 4 | originalText: string 5 | suggestedText: string 6 | description: string 7 | isResolved: boolean 8 | userId: string 9 | documentCreatedAt: Date 10 | siteId: string 11 | createdAt: Date 12 | } 13 | -------------------------------------------------------------------------------- /packages/model-type/src/IView.ts: -------------------------------------------------------------------------------- 1 | import { Filter, Group, Sort, ViewColumn, ViewType } from '@penx/types' 2 | 3 | export interface IView { 4 | id: string 5 | name: string 6 | description: string 7 | viewType: ViewType 8 | viewColumns: ViewColumn[] 9 | sorts: Sort[] 10 | groups: Group[] 11 | filters: Filter[] 12 | kanbanColumnId: string 13 | kanbanOptionIds: string[] 14 | createdAt: Date 15 | updatedAt: Date 16 | } 17 | -------------------------------------------------------------------------------- /packages/model-type/src/IVoice.ts: -------------------------------------------------------------------------------- 1 | export interface IVoice { 2 | id: string 3 | 4 | hash?: string 5 | 6 | recordDataBase64?: string 7 | 8 | msDuration: number 9 | 10 | mimeType: string 11 | 12 | uri?: string 13 | 14 | uploaded: boolean 15 | } 16 | -------------------------------------------------------------------------------- /packages/model-type/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Automatically generated by barrelsby. 3 | */ 4 | 5 | export * from './IAISetting' 6 | export * from './IAsset' 7 | export * from './ICatalogueNode' 8 | export * from './IDatabase' 9 | export * from './IDomain' 10 | export * from './IField' 11 | export * from './IFile' 12 | export * from './IVoice' 13 | export * from './INode' 14 | export * from './IRecord' 15 | export * from './IView' 16 | export * from './IChat' 17 | export * from './IMessage' 18 | export * from './ISuggestion' 19 | export * from './IDocument' 20 | export * from './IChange' 21 | export * from './IColumn' 22 | export * from './IView' 23 | -------------------------------------------------------------------------------- /packages/model-type/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/novel-editor/src/components/FocusHelper.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { Editor, useCurrentEditor } from '@tiptap/react' 3 | import { appEmitter } from '@penx/emitter' 4 | 5 | export function FocusHelper() { 6 | const { editor } = useCurrentEditor() 7 | useEffect(() => { 8 | const handleFocus = () => { 9 | editor?.chain().focus().run() 10 | } 11 | appEmitter.on('FOCUS_EDITOR', handleFocus) 12 | return () => { 13 | appEmitter.off('FOCUS_EDITOR', handleFocus) 14 | } 15 | }, []) 16 | return null 17 | } 18 | -------------------------------------------------------------------------------- /packages/novel-editor/src/components/ui/icons/crazy-spinner.tsx: -------------------------------------------------------------------------------- 1 | const CrazySpinner = () => { 2 | return ( 3 |
4 |
5 |
6 |
7 |
8 | ); 9 | }; 10 | 11 | export default CrazySpinner; 12 | -------------------------------------------------------------------------------- /packages/novel-editor/src/components/ui/icons/index.tsx: -------------------------------------------------------------------------------- 1 | export { default as FontDefault } from "./font-default"; 2 | export { default as FontSerif } from "./font-serif"; 3 | export { default as FontMono } from "./font-mono"; 4 | -------------------------------------------------------------------------------- /packages/novel-editor/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /packages/novel-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "declaration": false, 6 | "declarationMap": false, 7 | }, 8 | "include": ["src"], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/query-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/query-client", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/query-client/src/index.ts: -------------------------------------------------------------------------------- 1 | import { QueryClient } from '@tanstack/react-query' 2 | 3 | export const queryClient = new QueryClient() 4 | -------------------------------------------------------------------------------- /packages/query-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/services/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Automatically generated by barrelsby. 3 | */ 4 | 5 | export * from './SyncService' 6 | export * from './sync' 7 | export * from './syncPostToHub' 8 | export * from './syncSiteToHub' 9 | export * from './uploadFile' 10 | export * from './uploadthing' 11 | -------------------------------------------------------------------------------- /packages/services/src/sync.ts: -------------------------------------------------------------------------------- 1 | // import { WorkerEvents } from './constants' 2 | 3 | export async function sync(isWorker = false) {} 4 | 5 | async function pushToServer(remoteLastUpdatedAt: number) {} 6 | 7 | async function pullFromServer(localLastUpdatedAt: number, isWorker = false) {} 8 | -------------------------------------------------------------------------------- /packages/services/src/syncPostToHub.ts: -------------------------------------------------------------------------------- 1 | import { NetworkNames } from '@penx/constants' 2 | import { SyncService } from './SyncService' 3 | 4 | export async function syncPostToHub(site: any, creation: any, markdown = '') { 5 | // const token = await api.github.getGitHubToken.query({ 6 | // installationId: site.installationId!, 7 | // }) 8 | // const sync = await SyncService.init(token, site) 9 | // await sync.pushPost(creation, markdown) 10 | } 11 | -------------------------------------------------------------------------------- /packages/services/src/syncSiteToHub.ts: -------------------------------------------------------------------------------- 1 | import { NetworkNames } from '@penx/constants' 2 | import { SyncService } from './SyncService' 3 | 4 | export async function syncSiteToHub(site: any) { 5 | // const token = await getTokenByInstallationId(site.installationId!) 6 | // const sync = await SyncService.init(token, site) 7 | // await sync.pushSite(site) 8 | } 9 | -------------------------------------------------------------------------------- /packages/services/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/session/src/SessionContext.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { createContext, PropsWithChildren, useContext } from 'react' 4 | import { useQuerySession } from './useQuerySession' 5 | 6 | type SessionType = ReturnType 7 | 8 | export const SessionContext = createContext({} as SessionType) 9 | 10 | export const SessionProvider = ({ children }: PropsWithChildren) => { 11 | const sessionRes = useQuerySession() 12 | 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | 20 | export function useSession() { 21 | return useContext(SessionContext) 22 | } 23 | -------------------------------------------------------------------------------- /packages/session/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useQuerySession' 2 | export * from './SessionContext' 3 | -------------------------------------------------------------------------------- /packages/session/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "lib": ["DOM"], 5 | "outDir": "dist" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/store/src/JotaiNexus.ts: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useCallback, useEffect } from 'react' 4 | import { Getter, Setter } from 'jotai' 5 | import { useAtomCallback } from 'jotai/utils' 6 | 7 | export let readAtom!: Getter 8 | export let writeAtom!: Setter 9 | 10 | export const JotaiNexus = () => { 11 | const init = useAtomCallback( 12 | useCallback((get, set) => { 13 | readAtom = get 14 | writeAtom = set 15 | }, []), 16 | ) 17 | 18 | useEffect(() => { 19 | init() 20 | }, [init]) 21 | 22 | return null 23 | } 24 | -------------------------------------------------------------------------------- /packages/store/src/StoreProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { PropsWithChildren, useEffect } from 'react' 4 | import { Provider } from 'jotai' 5 | import { JotaiNexus } from './JotaiNexus' 6 | import { store } from './store' 7 | 8 | export function StoreProvider(props: PropsWithChildren) { 9 | return ( 10 | 11 | 12 | {props.children} 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /packages/store/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './store' 2 | export * from './JotaiNexus' 3 | export * from './StoreProvider' 4 | export * from './stores/AppStore' 5 | export * from './stores/VisitStore' 6 | export * from './stores/SiteStore' 7 | export * from './stores/PanelsStore' 8 | export * from './stores/StructsStore' 9 | export * from './stores/TagsStore' 10 | export * from './stores/CreationTagsStore' 11 | export * from './stores/AreaStore' 12 | export * from './stores/AreasStore' 13 | export * from './stores/CreationsStore' 14 | export * from './stores/JournalsStore' 15 | -------------------------------------------------------------------------------- /packages/store/src/stores/AppStore.ts: -------------------------------------------------------------------------------- 1 | import { atom } from 'jotai' 2 | import { StoreType } from '../store-types' 3 | 4 | export const appLoadingAtom = atom(true) 5 | 6 | export class AppStore { 7 | constructor(private store: StoreType) {} 8 | 9 | get() { 10 | return this.store.get(appLoadingAtom) 11 | } 12 | 13 | getAppLoading() { 14 | return this.store.get(appLoadingAtom) 15 | } 16 | 17 | setAppLoading(loading: boolean) { 18 | return this.store.set(appLoadingAtom, loading) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/store/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/types", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/typescript-config/internal-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | /** Emit types for internal packages to speed up editor performance. */ 6 | "declaration": true, 7 | "jsx": "preserve", 8 | "declarationMap": true, 9 | // "emitDeclarationOnly": true, 10 | "noEmit": false, 11 | "outDir": "${configDir}/dist" 12 | }, 13 | "include": ["${configDir}/src"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/typescript-config", 3 | "private": true, 4 | "version": "0.1.0", 5 | "files": [ 6 | "*.json" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/uikit/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "tailwind.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@penx/uikit/components", 15 | "plate-ui": "@penx/uikit/plate-ui", 16 | "editor": "@penx/uikit/editor", 17 | "utils": "@penx/uikit/lib/utils", 18 | "hooks": "@penx/uikit/hooks", 19 | "lib": "@penx/uikit/lib", 20 | "ui": "@penx/uikit/components" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/uikit/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { plugins: { '@tailwindcss/postcss': {} } }; 2 | -------------------------------------------------------------------------------- /packages/uikit/src/components/Image.tsx: -------------------------------------------------------------------------------- 1 | import NextImage, { ImageProps } from 'next/image' 2 | import { STATIC_URL } from '@penx/constants' 3 | 4 | const basePath = process.env.BASE_PATH 5 | 6 | export const Image = ({ src, ...rest }: ImageProps) => { 7 | if (typeof src === 'string' && src.startsWith(STATIC_URL)) { 8 | return 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /packages/uikit/src/components/icons/loading-dots.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@penx/utils' 2 | 3 | interface LoadingDotsProps { 4 | className?: string 5 | } 6 | 7 | export const LoadingDots = ({ className }: LoadingDotsProps) => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /packages/uikit/src/hooks/use-debounce.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export const useDebounce = (value: T, delay = 500) => { 4 | const [debouncedValue, setDebouncedValue] = React.useState(value) 5 | 6 | React.useEffect(() => { 7 | const handler: NodeJS.Timeout = setTimeout(() => { 8 | setDebouncedValue(value) 9 | }, delay) 10 | 11 | // Cancel the timeout if value changes (also on delay change or unmount) 12 | return () => { 13 | clearTimeout(handler) 14 | } 15 | }, [value, delay]) 16 | 17 | return debouncedValue 18 | } 19 | -------------------------------------------------------------------------------- /packages/uikit/src/hooks/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener('change', onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener('change', onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /packages/uikit/src/hooks/use-mounted.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export function useMounted() { 4 | const [mounted, setMounted] = React.useState(false) 5 | 6 | React.useEffect(() => { 7 | setMounted(true) 8 | }, []) 9 | 10 | return mounted 11 | } 12 | -------------------------------------------------------------------------------- /packages/uikit/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /packages/uikit/src/ui/menu/MenuGroup.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, forwardRef, PropsWithChildren, ReactNode } from 'react' 2 | 3 | export interface MenuGroupProps { 4 | title: ReactNode 5 | } 6 | 7 | export const MenuGroup = forwardRef< 8 | HTMLDivElement, 9 | PropsWithChildren 10 | >(function MenuGroup(props, ref) { 11 | const { title, children, ...rest } = props 12 | return ( 13 |
14 |
15 | {title} 16 |
17 | {children} 18 |
19 | ) 20 | }) 21 | -------------------------------------------------------------------------------- /packages/uikit/src/ui/menu/context.ts: -------------------------------------------------------------------------------- 1 | import { createContext, ReactNode, useContext } from 'react' 2 | 3 | export interface MenuContext { 4 | colorScheme?: any 5 | } 6 | 7 | export const menuContext = createContext({} as MenuContext) 8 | 9 | export const MenuProvider = menuContext.Provider 10 | 11 | export function useMenuContext() { 12 | return useContext(menuContext) 13 | } 14 | -------------------------------------------------------------------------------- /packages/uikit/src/ui/menu/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Menu' 2 | export * from './MenuGroup' 3 | export * from './MenuItem' 4 | -------------------------------------------------------------------------------- /packages/uikit/src/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@penx/utils' 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return ( 5 |
10 | ) 11 | } 12 | 13 | export { Skeleton } 14 | -------------------------------------------------------------------------------- /packages/uikit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "moduleResolution": "bundler", 7 | "declarationMap": false, 8 | "declaration": false, 9 | "outDir": "dist" 10 | }, 11 | "include": ["."], 12 | "exclude": ["node_modules", "dist"] 13 | } 14 | -------------------------------------------------------------------------------- /packages/unique-id/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@penx/unique-id", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "module": "index.ts", 7 | "main": "index.ts", 8 | "types": "./src/index.ts", 9 | "exports": { 10 | ".": "./src/index.ts" 11 | }, 12 | "scripts": { 13 | "lint": "eslint . --max-warnings 0", 14 | "check-types": "tsc --noEmit" 15 | }, 16 | "devDependencies": { 17 | "@penx/typescript-config": "workspace:*" 18 | }, 19 | "dependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /packages/unique-id/src/index.ts: -------------------------------------------------------------------------------- 1 | import { v4 } from 'uuid' 2 | 3 | export function uniqueId() { 4 | return v4() 5 | } 6 | -------------------------------------------------------------------------------- /packages/unique-id/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/utils/src/calculateSHA256FromFile.ts: -------------------------------------------------------------------------------- 1 | export async function calculateSHA256FromFile(file: File): Promise { 2 | const buffer: ArrayBuffer = await file.arrayBuffer() 3 | const hashBuffer: ArrayBuffer = await crypto.subtle.digest('SHA-256', buffer) 4 | const hashArray: Uint8Array = new Uint8Array(hashBuffer) 5 | const hashHex: string = Array.from(hashArray) 6 | .map((byte) => byte.toString(16).padStart(2, '0')) 7 | .join('') 8 | return hashHex 9 | } 10 | -------------------------------------------------------------------------------- /packages/utils/src/editorHelper.ts: -------------------------------------------------------------------------------- 1 | export function docToString(node: any) { 2 | if (!node) return '' 3 | 4 | if (node.type === 'text') { 5 | return node.text || '' 6 | } 7 | 8 | if (node.content && Array.isArray(node.content)) { 9 | return node.content.map(docToString).join('') 10 | } 11 | 12 | return '' 13 | } 14 | 15 | export function stringToDoc(input: string) { 16 | const arr: string[] = input.split('\n') 17 | return { 18 | type: 'doc', 19 | content: arr.map((line) => ({ 20 | type: 'paragraph', 21 | content: [{ type: 'text', text: line }], 22 | })), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/utils/src/generateNonce.ts: -------------------------------------------------------------------------------- 1 | export function generateNonce(length: number = 16): string { 2 | const characters = 3 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 4 | let nonce = '' 5 | for (let i = 0; i < length; i++) { 6 | const randomIndex = Math.floor(Math.random() * characters.length) 7 | nonce += characters[randomIndex] 8 | } 9 | return nonce 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "DOM"], 5 | "outDir": "dist" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/widgets/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { plugins: { '@tailwindcss/postcss': {} } }; 2 | -------------------------------------------------------------------------------- /packages/widgets/src/LoginDialog/useLoginDialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { atom, useAtom } from 'jotai' 4 | 5 | const loginDialogAtom = atom(false) 6 | 7 | export function useLoginDialog() { 8 | const [isOpen, setIsOpen] = useAtom(loginDialogAtom) 9 | return { isOpen, setIsOpen } 10 | } 11 | -------------------------------------------------------------------------------- /packages/widgets/src/Logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | interface Props { 4 | className?: string 5 | } 6 | export function Logo({ className }: Props) { 7 | return ( 8 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /packages/widgets/src/LogoSpinner.tsx: -------------------------------------------------------------------------------- 1 | import { Logo } from './Logo' 2 | 3 | export function LogoSpinner() { 4 | return ( 5 |
6 | {/* */} 7 |
8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /packages/widgets/src/StructName.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | import { Trans } from '@lingui/react/macro' 3 | import { Struct } from '@penx/domain' 4 | 5 | interface Props { 6 | struct: Struct 7 | } 8 | 9 | export function StructName({ struct }: Props) { 10 | let name: ReactNode = struct.name 11 | return name 12 | } 13 | -------------------------------------------------------------------------------- /packages/widgets/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Automatically generated by barrelsby. 3 | */ 4 | 5 | export * from './ConfirmDialog' 6 | export * from './GoogleOauthButton' 7 | export * from './UserAvatar' 8 | export * from './LoginDialog/LoginDialog' 9 | export * from './LoginDialog/LoginDialogContent' 10 | export * from './LoginDialog/LoginForm' 11 | export * from './LoginDialog/RegisterForm' 12 | export * from './LoginDialog/useLoginDialog' 13 | -------------------------------------------------------------------------------- /packages/widgets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/internal-package.json", 3 | "compilerOptions": { 4 | "lib": ["DOM"], 5 | "strict": true, 6 | "strictNullChecks": true 7 | }, 8 | "include": ["."], 9 | "exclude": ["node_modules", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/worker/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './runWorker' 2 | -------------------------------------------------------------------------------- /packages/worker/src/pollingCloudSync.ts: -------------------------------------------------------------------------------- 1 | import { get } from 'idb-keyval' 2 | import { SITE_MODE } from '@penx/constants' 3 | import { sleep } from '@penx/utils' 4 | 5 | export async function pollingCloudSync() { 6 | let pollingInterval = 10 * 1000 7 | 8 | // console.log('=======pollingInterval:', pollingInterval) 9 | 10 | // while (true) { 11 | // } 12 | } 13 | -------------------------------------------------------------------------------- /packages/worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@penx/typescript-config/base.json", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "DOM"], 5 | "outDir": "dist" 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist"] 9 | } 10 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | 5 | catalog: --------------------------------------------------------------------------------