├── public ├── robots.txt ├── logo.webp ├── preview.png ├── icons │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── icon512_rounded.png │ ├── apple-touch-icon.png │ ├── icon512_maskable.png │ ├── android-chrome-192x192.png │ └── android-chrome-512x512.png ├── wasm │ └── sql-wasm.wasm └── site.webmanifest ├── src ├── vite-env.d.ts ├── lib │ ├── utils.ts │ ├── queryCache.ts │ └── secureStorage.ts ├── types │ └── window.d.ts ├── components │ ├── ui │ │ ├── badge.tsx │ │ ├── span.tsx │ │ ├── label.tsx │ │ ├── button.tsx │ │ ├── textarea.tsx │ │ ├── input.tsx │ │ ├── buttonVariants.ts │ │ ├── tabs.tsx │ │ ├── resizable.tsx │ │ ├── table.tsx │ │ ├── dialog.tsx │ │ ├── select.tsx │ │ └── dropdown-menu.tsx │ ├── structureTab │ │ ├── StructureTab.tsx │ │ ├── common │ │ │ ├── ToggleChevron.tsx │ │ │ └── SectionHeader.tsx │ │ ├── SchemaSearch.tsx │ │ ├── IndexItem.tsx │ │ ├── TableColumn.tsx │ │ ├── IndexesSection.tsx │ │ ├── TableItem.tsx │ │ ├── SchemaTree.tsx │ │ └── TablesSection.tsx │ ├── common │ │ ├── Toaster │ │ │ ├── Toaster.tsx │ │ │ └── Toast.tsx │ │ └── ErrorBoundary.tsx │ ├── theme │ │ └── ModeToggle.tsx │ ├── browseTab │ │ ├── TableSelector.tsx │ │ ├── ActionButtons.tsx │ │ ├── BrowseTab.tsx │ │ ├── ActionsDropdown.tsx │ │ ├── PaginationControls.tsx │ │ ├── EditSection.tsx │ │ └── DataTable.tsx │ ├── accessibility │ │ ├── SkipLinks.tsx │ │ ├── HighContrastToggle.tsx │ │ └── LiveRegion.tsx │ ├── FileDropHandler.tsx │ ├── table │ │ ├── ColumnIcon.tsx │ │ ├── SorterButton.tsx │ │ └── FilterInput.tsx │ ├── executeTab │ │ ├── ApiKeyModal.tsx │ │ ├── CustomSQLTextarea.tsx │ │ └── ExecuteTab.tsx │ ├── TopBar.tsx │ └── DatabaseURLLoader.tsx ├── hooks │ ├── useTheme.ts │ ├── usePanel.ts │ ├── useWorker.ts │ ├── useKeyPress.ts │ ├── useFileDrop.ts │ └── useGeminiAI.ts ├── providers │ ├── theme │ │ ├── ThemeContext.tsx │ │ └── ThemeProvider.tsx │ ├── panel │ │ ├── PanelContext.tsx │ │ └── PanelProvider.tsx │ └── worker │ │ └── WorkerContext.tsx ├── sqlite │ ├── sqlite-type-check.ts │ └── demo-db.ts ├── store │ ├── usePanelStore.ts │ ├── useSchemaStore.ts │ └── useDatabaseStore.ts ├── main.tsx ├── types.ts ├── App.tsx └── index.css ├── tsconfig.json ├── prettier.config.js ├── .gitignore ├── components.json ├── .github ├── dependabot.yml └── workflows │ ├── lint.yml │ ├── format.yml │ └── codeql.yml ├── tsconfig.node.json ├── tsconfig.app.json ├── eslint.config.js ├── LICENSE ├── vite.config.ts ├── package.json ├── README.md └── index.html /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/logo.webp -------------------------------------------------------------------------------- /public/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/preview.png -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/favicon.ico -------------------------------------------------------------------------------- /public/wasm/sql-wasm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/wasm/sql-wasm.wasm -------------------------------------------------------------------------------- /public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/icons/icon512_rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/icon512_rounded.png -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/icons/icon512_maskable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/icon512_maskable.png -------------------------------------------------------------------------------- /public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vwh/sqlite-online/HEAD/public/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/types/window.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Window interface extensions for global functions 3 | */ 4 | 5 | declare global { 6 | interface Window { 7 | loadDatabaseBuffer?: (buffer: ArrayBuffer) => Promise; 8 | } 9 | } 10 | 11 | export {}; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | function Badge({ children }: Readonly<{ children: React.ReactNode }>) { 2 | return ( 3 | 4 | {children} 5 | 6 | ); 7 | } 8 | 9 | export default Badge; 10 | -------------------------------------------------------------------------------- /src/components/structureTab/StructureTab.tsx: -------------------------------------------------------------------------------- 1 | import SchemaTree from "./SchemaTree"; 2 | 3 | const DatabaseStructureTab = () => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default DatabaseStructureTab; 12 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */ 2 | const config = { 3 | plugins: ["prettier-plugin-tailwindcss"], 4 | arrowParens: "always", 5 | printWidth: 80, 6 | singleQuote: false, 7 | jsxSingleQuote: false, 8 | semi: true, 9 | trailingComma: "none", 10 | tabWidth: 2, 11 | }; 12 | 13 | export default config; 14 | -------------------------------------------------------------------------------- /src/hooks/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | 3 | import ThemeProviderContext from "@/providers/theme/ThemeContext"; 4 | 5 | const useTheme = () => { 6 | const context = useContext(ThemeProviderContext); 7 | 8 | if (context === undefined) 9 | throw new Error("useTheme must be used within a ThemeProvider"); 10 | 11 | return context; 12 | }; 13 | 14 | export default useTheme; 15 | -------------------------------------------------------------------------------- /.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 | dev-dist 14 | *.local 15 | stats.html 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 | .million 28 | -------------------------------------------------------------------------------- /src/hooks/usePanel.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | 3 | import PanelContext from "@/providers/panel/PanelContext"; 4 | 5 | const usePanelManager = () => { 6 | const context = useContext(PanelContext); 7 | 8 | if (context === undefined) { 9 | throw new Error("usePanelManager must be used within a PanelProvider"); 10 | } 11 | 12 | return context; 13 | }; 14 | 15 | export default usePanelManager; 16 | -------------------------------------------------------------------------------- /src/components/ui/span.tsx: -------------------------------------------------------------------------------- 1 | import { memo, type ReactNode } from "react"; 2 | 3 | export const Span = memo(function Span({ 4 | children, 5 | className 6 | }: { 7 | children: ReactNode; 8 | className?: string; 9 | }) { 10 | return ( 11 | 16 | {children} 17 | 18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /src/hooks/useWorker.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | 3 | import DatabaseWorkerContext from "@/providers/worker/WorkerContext"; 4 | 5 | const useDatabaseWorker = () => { 6 | const context = useContext(DatabaseWorkerContext); 7 | 8 | if (context === undefined) 9 | throw new Error( 10 | "useDatabaseWorker must be used within a DatabaseWorkerProvider" 11 | ); 12 | 13 | return context; 14 | }; 15 | 16 | export default useDatabaseWorker; 17 | -------------------------------------------------------------------------------- /src/providers/theme/ThemeContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | import type { Theme } from "./ThemeProvider"; 4 | 5 | type ThemeProviderState = { 6 | theme: Theme; 7 | setTheme: (theme: Theme) => void; 8 | }; 9 | 10 | const initialState: ThemeProviderState = { 11 | theme: "system", 12 | setTheme: () => null 13 | }; 14 | 15 | const ThemeProviderContext = createContext(initialState); 16 | 17 | export default ThemeProviderContext; 18 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/index.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: "20" 23 | cache: 'npm' 24 | 25 | - name: Install dependencies 26 | run: npm install 27 | 28 | - name: Run ESLint 29 | run: npm run lint 30 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Check Format 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | format: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: "20" 23 | cache: 'npm' 24 | 25 | - name: Install dependencies 26 | run: npm install 27 | 28 | - name: Run Prettier check 29 | run: npm run format:check 30 | -------------------------------------------------------------------------------- /src/components/common/Toaster/Toaster.tsx: -------------------------------------------------------------------------------- 1 | import { Toaster } from "sonner"; 2 | 3 | function AppToaster() { 4 | return ( 5 | 21 | ); 22 | } 23 | 24 | export default AppToaster; 25 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as LabelPrimitive from "@radix-ui/react-label"; 3 | 4 | import { cn } from "@/lib/utils"; 5 | 6 | function Label({ 7 | className, 8 | ...props 9 | }: React.ComponentProps) { 10 | return ( 11 | 19 | ); 20 | } 21 | 22 | export { Label }; 23 | -------------------------------------------------------------------------------- /src/components/structureTab/common/ToggleChevron.tsx: -------------------------------------------------------------------------------- 1 | import { memo } from "react"; 2 | import { ChevronDownIcon, ChevronRightIcon } from "lucide-react"; 3 | 4 | const MemoizedChevronDownIcon = memo(ChevronDownIcon); 5 | const MemoizedChevronRightIcon = memo(ChevronRightIcon); 6 | 7 | interface ToggleChevronProps { 8 | expanded: boolean; 9 | size?: number; 10 | } 11 | 12 | const ToggleChevron = memo(({ expanded, size = 4 }: ToggleChevronProps) => { 13 | const className = `h-${size} w-${size}`; 14 | 15 | if (expanded) { 16 | return ; 17 | } 18 | 19 | return ; 20 | }); 21 | 22 | export default ToggleChevron; 23 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import type * as React from "react"; 2 | import { Slot } from "@radix-ui/react-slot"; 3 | import type { VariantProps } from "class-variance-authority"; 4 | import { cn } from "@/lib/utils"; 5 | import buttonVariants from "./buttonVariants"; 6 | 7 | type ButtonProps = React.ComponentProps<"button"> & 8 | VariantProps & { 9 | asChild?: boolean; 10 | }; 11 | 12 | const ButtonComponent = ({ 13 | className, 14 | variant, 15 | size, 16 | asChild = false, 17 | ...props 18 | }: ButtonProps) => { 19 | const Comp = asChild ? Slot : "button"; 20 | 21 | return ( 22 | 27 | ); 28 | }; 29 | 30 | export const Button = ButtonComponent; 31 | -------------------------------------------------------------------------------- /src/providers/panel/PanelContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | import type { SqlValue } from "sql.js"; 4 | 5 | interface PanelContextProps { 6 | handleRowClick: ( 7 | row: SqlValue[], 8 | index: number, 9 | primaryValue: SqlValue 10 | ) => void; 11 | handleInsert: () => void; 12 | isEditing: boolean; 13 | selectedRowObject: { 14 | data: SqlValue[]; 15 | index: number; 16 | primaryValue: SqlValue; 17 | } | null; 18 | isInserting: boolean; 19 | setIsInserting: (value: boolean) => void; 20 | setSelectedRowObject: ( 21 | value: { data: SqlValue[]; index: number; primaryValue: SqlValue } | null 22 | ) => void; 23 | handleCloseEdit: () => void; 24 | } 25 | 26 | const PanelContext = createContext(undefined); 27 | 28 | export default PanelContext; 29 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 6 | return ( 7 |