├── public ├── favicon.ico ├── images │ ├── sponsors │ │ ├── dewaweb.png │ │ ├── cloudkilat.png │ │ ├── cloudflare.svg │ │ └── bunny.net.svg │ └── branding │ │ ├── statically-mark.jpg │ │ ├── statically-mark.png │ │ ├── statically-logo-dark.png │ │ ├── statically-mark-lg.jpg │ │ ├── statically-mark-lg.png │ │ ├── statically-logo-light.png │ │ ├── statically-mark-bg-white-lg.png │ │ ├── statically-mark.svg │ │ ├── statically-mark-bg-white-lg.svg │ │ ├── statically-logo-dark.svg │ │ └── statically-logo-light.svg └── _headers ├── app ├── not-found.ts ├── layout.tsx └── globals.css ├── wrangler.jsonc ├── postcss.config.mjs ├── lib └── utils.ts ├── components ├── ui │ ├── aspect-ratio.tsx │ ├── skeleton.tsx │ ├── spinner.tsx │ ├── use-mobile.tsx │ ├── sonner.tsx │ ├── label.tsx │ ├── separator.tsx │ ├── textarea.tsx │ ├── progress.tsx │ ├── toaster.tsx │ ├── collapsible.tsx │ ├── kbd.tsx │ ├── input.tsx │ ├── switch.tsx │ ├── avatar.tsx │ ├── checkbox.tsx │ ├── radio-group.tsx │ ├── hover-card.tsx │ ├── toggle.tsx │ ├── badge.tsx │ ├── popover.tsx │ ├── scroll-area.tsx │ ├── alert.tsx │ ├── tooltip.tsx │ ├── toggle-group.tsx │ ├── tabs.tsx │ ├── slider.tsx │ ├── resizable.tsx │ ├── accordion.tsx │ ├── button.tsx │ ├── card.tsx │ ├── button-group.tsx │ ├── input-otp.tsx │ ├── breadcrumb.tsx │ ├── empty.tsx │ ├── table.tsx │ ├── pagination.tsx │ ├── form.tsx │ ├── alert-dialog.tsx │ ├── dialog.tsx │ ├── sheet.tsx │ ├── drawer.tsx │ ├── use-toast.ts │ ├── toast.tsx │ ├── item.tsx │ ├── command.tsx │ ├── input-group.tsx │ ├── carousel.tsx │ ├── select.tsx │ ├── field.tsx │ ├── navigation-menu.tsx │ ├── calendar.tsx │ └── context-menu.tsx ├── theme-provider.tsx └── url-converter.tsx ├── .gitignore ├── components.json ├── hooks ├── use-mobile.ts └── use-toast.ts ├── next.config.mjs ├── .github └── workflows │ └── stale.yml ├── tsconfig.json ├── README.md ├── package.json └── styles └── globals.css /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/images/sponsors/dewaweb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/sponsors/dewaweb.png -------------------------------------------------------------------------------- /public/images/sponsors/cloudkilat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/sponsors/cloudkilat.png -------------------------------------------------------------------------------- /app/not-found.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default function NotFound() { 4 | redirect("/"); 5 | } 6 | -------------------------------------------------------------------------------- /public/images/branding/statically-mark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-mark.jpg -------------------------------------------------------------------------------- /public/images/branding/statically-mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-mark.png -------------------------------------------------------------------------------- /public/images/branding/statically-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-logo-dark.png -------------------------------------------------------------------------------- /public/images/branding/statically-mark-lg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-mark-lg.jpg -------------------------------------------------------------------------------- /public/images/branding/statically-mark-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-mark-lg.png -------------------------------------------------------------------------------- /public/images/branding/statically-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-logo-light.png -------------------------------------------------------------------------------- /public/_headers: -------------------------------------------------------------------------------- 1 | /images/* 2 | Cache-Control: public, max-age=31536000, immutable 3 | 4 | /favicon.ico 5 | Cache-Control: public, max-age=31536000, immutable -------------------------------------------------------------------------------- /public/images/branding/statically-mark-bg-white-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticallyio/statically/HEAD/public/images/branding/statically-mark-bg-white-lg.png -------------------------------------------------------------------------------- /wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/wrangler/config-schema.json", 3 | "compatibility_date": "2025-11-17", 4 | "compatibility_flags": ["nodejs_compat"] 5 | } 6 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | '@tailwindcss/postcss': {}, 5 | }, 6 | } 7 | 8 | export default config 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio' 4 | 5 | function AspectRatio({ 6 | ...props 7 | }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | export { AspectRatio } 12 | -------------------------------------------------------------------------------- /components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return ( 5 |
10 | ) 11 | } 12 | 13 | export { Skeleton } 14 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { 5 | ThemeProvider as NextThemesProvider, 6 | type ThemeProviderProps, 7 | } from 'next-themes' 8 | 9 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 10 | return {children} 11 | } 12 | -------------------------------------------------------------------------------- /components/ui/spinner.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2Icon } from 'lucide-react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | function Spinner({ className, ...props }: React.ComponentProps<'svg'>) { 6 | return ( 7 | 13 | ) 14 | } 15 | 16 | export { Spinner } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # next.js 7 | /.next/ 8 | /out/ 9 | 10 | # production 11 | /build 12 | 13 | # debug 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | .pnpm-debug.log* 18 | 19 | # env files 20 | .env* 21 | 22 | # vercel 23 | .vercel 24 | 25 | # typescript 26 | *.tsbuildinfo 27 | next-env.d.ts -------------------------------------------------------------------------------- /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": "app/globals.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 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /components/ui/use-mobile.tsx: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useTheme } from 'next-themes' 4 | import { Toaster as Sonner, ToasterProps } from 'sonner' 5 | 6 | const Toaster = ({ ...props }: ToasterProps) => { 7 | const { theme = 'system' } = useTheme() 8 | 9 | return ( 10 | 22 | ) 23 | } 24 | 25 | export { Toaster } 26 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import * as LabelPrimitive from '@radix-ui/react-label' 5 | 6 | import { cn } from '@/lib/utils' 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ) 22 | } 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | typescript: { 4 | ignoreBuildErrors: true, 5 | }, 6 | images: { 7 | unoptimized: true, 8 | }, 9 | devIndicators: false, 10 | async headers() { 11 | return [ 12 | { 13 | source: "/images/:path*", 14 | headers: [ 15 | { 16 | key: "Cache-Control", 17 | value: "public, max-age=31536000, immutable", 18 | }, 19 | ], 20 | }, 21 | { 22 | source: "/favicon.ico", 23 | headers: [ 24 | { 25 | key: "Cache-Control", 26 | value: "public, max-age=31536000, immutable", 27 | }, 28 | ], 29 | }, 30 | ]; 31 | }, 32 | }; 33 | 34 | export default nextConfig; 35 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v10 14 | with: 15 | days-before-issue-stale: 30 16 | days-before-issue-close: 14 17 | stale-issue-label: "stale" 18 | stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." 19 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." 20 | days-before-pr-stale: -1 21 | days-before-pr-close: -1 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import * as SeparatorPrimitive from '@radix-ui/react-separator' 5 | 6 | import { cn } from '@/lib/utils' 7 | 8 | function Separator({ 9 | className, 10 | orientation = 'horizontal', 11 | decorative = true, 12 | ...props 13 | }: React.ComponentProps) { 14 | return ( 15 | 25 | ) 26 | } 27 | 28 | export { Separator } 29 | -------------------------------------------------------------------------------- /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 |