Files
wehub-resource-sync d718c5a372
CI / compile_and_lint (push) Failing after 0s
CI / docker_build (linux/amd64, -linux-amd64-duckdb, duckdb) (push) Failing after 0s
CI / docker_build (linux/arm64, -linux-arm64, minimal) (push) Failing after 2s
CI / docker_build (linux/arm64, -linux-arm64-duckdb, duckdb) (push) Failing after 1s
CI / docker_build (linux/amd64, minimal) (push) Failing after 1s
CI / test (, sqlite, sqlite::memory:) (push) Has been skipped
CI / test (mssql, mssql, mssql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (mysql, mysql, mysql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (oracle, oracle, Driver=Oracle 21 ODBC driver;Dbq=//127.0.0.1:1521/FREEPDB1;Uid=root;Pwd=Password123!) (push) Has been skipped
CI / test (postgres, odbc, Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!, true) (push) Has been skipped
CI / test (postgres, postgres, postgres://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / playwright (push) Has been skipped
CI / docker_build (linux/arm/v7, -linux-arm-v7, minimal) (push) Failing after 0s
CI / hurl_examples (push) Failing after 8s
deploy website / deploy_official_site (push) Failing after 1s
CI / hurl (${{ matrix.example }}) (push) Has been skipped
CI / docker_push (duckdb) (push) Has been cancelled
CI / docker_push (minimal) (push) Has been cancelled
CI / windows_test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:57 +08:00

1517 lines
48 KiB
Handlebars
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>SQLPage - SQL websites</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:title" content="SQLPage: SQL websites" />
<meta name="description"
content="Build interactive websites and apps with only SQL queries. SQLPage is an open-source tool to generate nice user interfaces on top of traditional databases. Maps, charts, tables, forms, and dashboards - without traditional web programming." />
<meta property="og:description" content="Build interactive websites with only SQL queries." />
<meta property="og:image" content="/sqlpage_social_preview.webp" />
<meta name="twitter:image" content="/sqlpage_social_preview.webp" />
<meta name="generator" content="SQLPage" />
<style>
/* ROOT VARIABLES
===============
Color system based on SQLPage visual identity.
BRAND COLORS (from visual-identity.sql):
- Primary Cyan: #37E5EF - bright accent, use sparingly
- Teal: #2A9FAF - secondary accent
- Dark Navy: #0a0f1a - primary background
DESIGN PRINCIPLE:
Bright cyan is an ACCENT color for small elements (buttons, borders, hovers).
Gradients and large areas use darker, desaturated tones for readability.
*/
:root {
/* === BRAND COLORS === */
--brand-cyan: #37E5EF;
--brand-teal: #2A9FAF;
--brand-navy: #0a0f1a;
/* === BACKGROUNDS ===
Dark navy family - slight teal undertone for cohesion */
--bg-primary: #0a0f1a;
--bg-secondary: #0c1520;
--bg-tertiary: #101c28;
--bg-elevated: #142430;
/* === TEXT === */
--text-primary: #f0f4f7;
--text-secondary: #8a9baa;
--text-muted: rgba(255, 255, 255, 0.6);
/* === ACCENT COLORS ===
For buttons, links, highlights - the bright brand colors */
--accent-primary: var(--brand-cyan);
--accent-secondary: var(--brand-teal);
/* === GRADIENT COLORS ===
Darker, desaturated versions for large area gradients.
These blend smoothly without harsh contrast. */
--gradient-dark: #0d1a24;
--gradient-mid: #153040;
--gradient-light: #1a4055;
/* === GLOW COLORS ===
Semi-transparent brand colors for subtle atmospheric effects */
--glow-cyan: rgba(55, 229, 239, 0.15);
--glow-teal: rgba(42, 159, 175, 0.12);
--glow-subtle: rgba(55, 229, 239, 0.06);
/* === OVERLAYS === */
--overlay-light: rgba(255, 255, 255, 0.03);
--overlay-lighter: rgba(255, 255, 255, 0.05);
--overlay-lightest: rgba(255, 255, 255, 0.12);
/* === BORDERS === */
--border-subtle: rgba(55, 229, 239, 0.08);
--border-light: rgba(55, 229, 239, 0.15);
--border-medium: rgba(55, 229, 239, 0.25);
/* === GRADIENTS ===
Primary: for buttons and interactive elements
Atmospheric: for background decoration */
--gradient-primary: linear-gradient(135deg,
var(--brand-teal) 0%,
var(--brand-cyan) 100%);
--gradient-atmospheric: linear-gradient(135deg,
var(--gradient-dark) 0%,
var(--gradient-mid) 100%);
/* === SHADOWS === */
--shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.2);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.25);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.3);
--shadow-glow: 0 0 20px var(--glow-cyan);
/* === SPACING === */
--container-padding: 40px;
--container-width: 1000px;
--gap-sm: 20px;
--gap-md: 40px;
--gap-lg: 60px;
/* === TRANSITIONS === */
--transition-fast: 0.3s ease;
--transition-medium: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
--transition-slow: 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Firefox scrollbar styles */
* {
scrollbar-width: thin;
scrollbar-color: var(--border-medium) var(--bg-primary);
}
/* RESET */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
font-family: sans-serif;
display: block;
background-color: var(--bg-primary);
color: var(--text-primary);
background-image:
radial-gradient(ellipse 80% 60% at 100% 0%,
var(--glow-cyan) 0%,
transparent 70%),
radial-gradient(ellipse 70% 50% at 0% 100%,
var(--glow-teal) 0%,
transparent 70%),
linear-gradient(160deg,
var(--bg-primary) 0%,
var(--bg-secondary) 100%);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
overflow-x: hidden;
scroll-behavior: smooth;
}
.container:first-of-type {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
/* CONTAINER */
.container {
text-align: left;
max-width: var(--container-width);
width: 90%;
margin: 0 auto;
padding: var(--container-padding);
display: flex;
align-items: center;
gap: var(--gap-lg);
}
/* LOGO WRAPPER */
.logo {
width: 300px;
height: 300px;
flex-shrink: 0;
animation: floatWaves 6s ease-in-out infinite;
margin-bottom: .5rem;
}
@keyframes floatWaves {
0%,
100% {
transform: rotate(-15deg) translateY(0px) scale(1);
}
50% {
transform: rotate(-15deg) translateY(-10px) scale(1.01);
}
}
/* TEXT WRAPPER */
.text-content {
display: flex;
flex-direction: column;
gap: var(--gap-sm);
animation: fadeIn 1s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* LOGO WRAPPER - ENHANCED STYLING */
.logo {
display: inline-block;
width: 220px;
height: 220px;
transform: rotate(-15deg);
position: relative;
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow:
inset 0 0 20px rgba(0, 0, 0, 0.7),
0 5px 15px rgba(0, 0, 0, 0.6);
border-radius: 12px;
overflow: hidden;
background: linear-gradient(135deg, var(--glow-teal), var(--glow-subtle));
margin-right: 30px;
animation: floatWaves 6s ease-in-out infinite;
}
.logo:hover {
transform: rotate(-5deg) scale(1.08) translateY(-5px);
box-shadow:
inset 0 0 25px rgba(0, 0, 0, 0.8),
0 12px 30px rgba(0, 0, 0, 0.4),
0 4px 8px rgba(0, 0, 0, 0.3);
animation: buzz 0.6s;
}
@keyframes buzz {
0%,
100% {
transform: rotate(-5deg) scale(1.08) translateY(-5px);
}
20% {
transform: rotate(-3deg) scale(1.08) translateY(-5px);
}
40% {
transform: rotate(-7deg) scale(1.08) translateY(-5px);
}
60% {
transform: rotate(-3deg) scale(1.08) translateY(-5px);
}
80% {
transform: rotate(-7deg) scale(1.08) translateY(-5px);
}
}
.logo svg {
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.logo:hover svg {
transform: scale(0.95) translateY(2px);
}
/* TITLE & TAGLINE - ENHANCED */
h1 {
font-size: 4rem;
margin-bottom: 15px;
font-weight: 800;
letter-spacing: -1px;
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transform: scale(1) translateX(0) translateY(0) translateZ(0);
}
h1:hover {
color: white;
background: none;
transform: scale(1.02) translateX(8px) translateY(-8px) translateZ(2px);
}
h1 span:first-child {
margin-right: 0;
transition: margin-right 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
h1:hover span:first-child {
margin-right: 0.5em;
}
h1 .words {
position: relative;
}
h1 .words span {
position: absolute;
left: 0;
opacity: 0;
}
h1 .words span:first-child {
opacity: 1;
position: relative;
transform: translateX(0);
}
h1:hover .words span {
text-shadow: 0 0 3px rgba(255, 255, 255, 0.5);
/* Total animation time: 8 words × 2s per word = 16s total cycle */
animation: rotateWords 16s ease-in-out infinite;
}
/* Delays: each word starts at 2s intervals
2s × (n-1) -1s where n is the word position */
h1:hover .words span:nth-child(1) {
animation-delay: -1s;
}
h1:hover .words span:nth-child(2) {
animation-delay: 1s;
}
h1:hover .words span:nth-child(3) {
animation-delay: 3s;
}
h1:hover .words span:nth-child(4) {
animation-delay: 5s;
}
h1:hover .words span:nth-child(5) {
animation-delay: 7s;
}
h1:hover .words span:nth-child(6) {
animation-delay: 9s;
}
h1:hover .words span:nth-child(7) {
animation-delay: 11s;
}
h1:hover .words span:nth-child(8) {
animation-delay: 13s;
}
/** Each word needs to appear for 2s, then disappear for the rest of the animation.
2s / 16s = 12.5% of the animation time.
**/
@keyframes rotateWords {
0% {
opacity: 0;
}
3%,
9.5% {
opacity: 1;
}
12%,
100% {
opacity: 0;
}
}
@keyframes shimmer {
0% {
background-position: 400% 0;
}
100% {
background-position: -400% 0;
}
}
p {
font-size: 2rem;
color: var(--text-secondary);
line-height: 1.4;
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
/* RESPONSIVE ADJUSTMENTS */
@media (max-width: 900px) {
:root {
--container-padding: 30px;
--gap-lg: 40px;
}
.container {
gap: var(--gap-lg);
padding: var(--container-padding);
}
.logo {
width: 250px;
height: 250px;
}
h1 {
font-size: 3.5rem;
}
p {
font-size: 1.8rem;
}
}
@media (max-width: 768px) {
:root {
--container-padding: 20px;
--gap-lg: 30px;
}
.container {
flex-direction: column;
text-align: center;
gap: var(--gap-lg);
}
.text-content {
align-items: center;
}
.logo {
width: 200px;
height: 200px;
margin-right: 0;
}
h1 {
font-size: 3rem;
}
p {
font-size: 1.6rem;
}
}
@media (max-width: 480px) {
.container {
padding: var(--container-padding);
gap: var(--gap-lg);
}
.logo {
width: 150px;
height: 150px;
}
h1 {
font-size: 2.5rem;
}
p {
font-size: 1.4rem;
}
}
/* MENU STYLES */
.menu {
position: fixed;
top: 2rem;
right: 2rem;
display: flex;
gap: 0.5rem;
z-index: 1000;
background: rgba(10, 15, 26, 0.85);
backdrop-filter: blur(12px);
padding: 0.6rem 1rem;
border-radius: 8px;
border: 1px solid var(--border-subtle);
}
.menu a {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.85rem;
padding: 0.4rem 0.8rem;
border-radius: 6px;
position: relative;
transition: all 0.2s ease;
}
.menu a:hover {
color: var(--text-primary);
background: var(--overlay-lighter);
text-decoration: none;
}
@media (max-width: 768px) {
.menu {
top: 1rem;
right: 1rem;
gap: 0.25rem;
padding: 0.4rem 0.6rem;
}
.menu a {
font-size: 0.8rem;
padding: 0.3rem 0.5rem;
}
}
/* CTA BUTTON - Minimal, transparent base */
.cta-button {
display: inline-block;
text-align: center;
padding: .8rem 2rem;
min-width: 200px;
max-width: 300px;
font-size: 1.2rem;
font-weight: 600;
background: transparent;
color: var(--text-primary);
text-decoration: none !important;
border-radius: 8px;
transition: all var(--transition-fast);
border: 1px solid var(--border-medium);
cursor: pointer;
margin-top: 1.5rem;
}
.cta-button:hover {
color: var(--brand-cyan);
border-color: var(--brand-cyan);
background: rgba(55, 229, 239, 0.05);
text-decoration: none !important;
}
.cta-button:active {
background: rgba(55, 229, 239, 0.1);
transition-duration: 0.1s;
}
.cta-button:focus {
outline: none;
border-color: var(--brand-cyan);
}
@media (max-width: 768px) {
.cta-button {
font-size: 1.1rem;
padding: 0.7rem 1.8rem;
min-width: 180px;
}
}
.scroll-link {
position: fixed;
bottom: 1.5rem;
left: 50%;
transform: translateX(-50%);
color: var(--text-secondary);
opacity: 0.5;
transition: all 0.3s ease;
animation: bounce 3s infinite;
cursor: pointer;
}
.scroll-link svg {
width: 32px;
height: 32px;
}
.scroll-link:hover {
color: var(--text-primary);
opacity: 0.8;
transform: translateX(-50%) scale(1.05);
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateX(-50%) translateY(0);
}
40% {
transform: translateX(-50%) translateY(-6px);
}
60% {
transform: translateX(-50%) translateY(-3px);
}
}
#features {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg,
var(--bg-secondary) 0%,
var(--bg-tertiary) 100%);
}
#features .container {
flex-direction: column;
gap: 3rem;
}
#features h2 {
font-size: 3.5rem;
margin-bottom: 1rem;
color: var(--text-primary);
}
.features-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2.5rem;
perspective: 1000px;
}
.feature-card {
background: var(--overlay-light);
border: 1px solid var(--border-subtle);
border-radius: 16px;
padding: 2.5rem;
transform-style: preserve-3d;
transform: perspective(1000px) rotateX(10deg);
transition: all var(--transition-slow);
backdrop-filter: blur(10px);
box-shadow: var(--shadow-lg);
}
.feature-card:hover {
transform: perspective(1000px) rotateX(0deg) translateY(-10px);
background: var(--overlay-lighter);
border-color: var(--border-light);
}
.feature-card h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: var(--text-primary);
position: relative;
}
.feature-card h3::before {
content: '';
position: absolute;
width: 30px;
height: 2px;
background: var(--gradient-primary);
bottom: -8px;
left: 0;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.feature-card:hover h3::before {
transform: scaleX(1);
}
.feature-card p {
font-size: 1rem;
line-height: 1.6;
color: var(--text-secondary);
margin-top: 1rem;
}
.feature-icon {
font-size: 2rem;
margin-bottom: 1.5rem;
opacity: 0.8;
transition: all 0.3s ease;
}
.feature-card:hover .feature-icon {
opacity: 1;
transform: translateY(-5px);
}
@media (max-width: 968px) {
.features-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.features-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
#features .container {
gap: 3rem;
}
.feature-card {
padding: 2rem;
}
}
.feature-section {
min-height: 100vh;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
}
.feature-section:nth-child(odd) {
background: linear-gradient(135deg,
var(--bg-secondary) 0%,
var(--bg-tertiary) 100%);
}
.feature-section .container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: center;
}
.feature-section:nth-child(even) .container {
direction: rtl;
}
.feature-section:nth-child(even) .feature-content {
direction: ltr;
}
.feature-content {
max-width: 500px;
}
.feature-content .gradient-title {
font-size: 2.5rem;
margin-bottom: 1.5rem;
background: var(--gradient-primary);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.feature-content p {
font-size: 1.2rem;
margin-bottom: 2rem;
}
.feature-image {
position: relative;
border-radius: 12px;
overflow: hidden;
box-shadow: var(--shadow-lg);
transition: transform var(--transition-medium);
}
.feature-image:hover {
transform: translateY(-10px);
}
.feature-image img,
.feature-image video {
width: 100%;
object-fit: cover;
object-position: left;
display: block;
}
@media (max-width: 968px) {
.feature-section .container {
grid-template-columns: 1fr;
text-align: center;
}
.feature-content {
max-width: 100%;
}
}
.compat-section {
position: relative;
background:
radial-gradient(ellipse 60% 50% at 20% 20%, var(--glow-teal), transparent 60%),
radial-gradient(ellipse 50% 40% at 80% 10%, var(--glow-subtle), transparent 60%),
linear-gradient(160deg, var(--bg-secondary), var(--bg-primary));
overflow: hidden;
isolation: isolate;
}
.compat-section::before,
.compat-section::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
}
.compat-section::before {
background-image: radial-gradient(2px 2px at 25px 35px, rgba(255, 255, 255, 0.6), transparent), radial-gradient(1px 1px at 120px 80px, rgba(255, 255, 255, 0.4), transparent), radial-gradient(1.5px 1.5px at 220px 140px, rgba(255, 255, 255, 0.55), transparent), radial-gradient(2px 2px at 320px 60px, rgba(255, 255, 255, 0.5), transparent), radial-gradient(1px 1px at 420px 180px, rgba(255, 255, 255, 0.4), transparent), radial-gradient(1.5px 1.5px at 520px 90px, rgba(255, 255, 255, 0.5), transparent);
background-size: 240px 220px;
opacity: 0.45;
animation: twinkle 14s linear infinite;
}
.compat-section::after {
background: radial-gradient(450px 450px at 80% 110%, var(--glow-teal), transparent 70%);
}
.compat-layout {
display: grid;
grid-template-columns: minmax(400px, 1fr) minmax(450px, 1.2fr);
gap: var(--gap-lg);
padding-top: calc(var(--container-padding) * 1.5);
padding-bottom: calc(var(--container-padding) * 1.5);
position: relative;
z-index: 1;
}
.compat-intro {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.compat-eyebrow {
font-size: 0.85rem;
letter-spacing: 0.3em;
text-transform: uppercase;
color: var(--brand-cyan);
opacity: 0.7;
}
.compat-intro h2 {
font-size: 3.2rem;
line-height: 1.1;
color: var(--text-primary);
}
.compat-intro p {
font-size: 1.15rem;
color: var(--text-secondary);
max-width: 90%;
}
.compat-highlights {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.compat-pill {
padding: 0.45rem 0.9rem;
border-radius: 999px;
background: var(--overlay-lighter);
border: 1px solid var(--border-light);
color: var(--text-primary);
font-size: 0.85rem;
backdrop-filter: blur(6px);
}
.compat-showcase {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;
width: 100%;
min-width: 0;
}
.compat-orbit {
position: relative;
width: 320px;
height: 320px;
margin: 0 auto;
border-radius: 50%;
background: radial-gradient(circle, var(--gradient-mid), var(--bg-tertiary));
box-shadow: inset 0 0 40px var(--glow-subtle), 0 20px 60px rgba(0, 0, 0, 0.5);
}
.compat-orbit::before {
content: "";
position: absolute;
inset: 14px;
border-radius: 50%;
border: 1px dashed var(--border-medium);
animation: orbitSpin 26s linear infinite;
}
.compat-orbit::after {
content: "";
position: absolute;
inset: 44px;
border-radius: 50%;
border: 1px solid var(--border-subtle);
filter: blur(0.3px);
}
.compat-core {
position: absolute;
width: 160px;
height: 160px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, var(--bg-elevated), var(--bg-tertiary));
box-shadow: var(--shadow-glow);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 1rem;
color: var(--text-primary);
font-size: 0.9rem;
line-height: 1.3;
backdrop-filter: blur(6px);
margin: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.compat-node {
position: absolute;
width: 84px;
height: 84px;
border-radius: 18px;
background: var(--bg-secondary);
box-shadow: var(--shadow-lg), inset 0 0 24px var(--glow-subtle);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
border: 1px solid var(--border-light);
outline: 1px solid rgba(0, 0, 0, 0.3);
outline-offset: -4px;
}
.compat-node img {
width: 54px;
height: 54px;
}
.compat-node:nth-child(2) {
top: 6%;
left: 50%;
transform: translate(-50%, -50%);
animation: floatNode 7s ease-in-out infinite;
}
.compat-node:nth-child(3) {
top: 50%;
right: 2%;
transform: translate(50%, -50%);
animation: floatNode 9s ease-in-out infinite;
}
.compat-node:nth-child(4) {
bottom: 4%;
left: 50%;
transform: translate(-50%, 50%);
animation: floatNode 8s ease-in-out infinite;
}
.compat-node:nth-child(5) {
top: 50%;
left: 2%;
transform: translate(-50%, -50%);
animation: floatNode 10s ease-in-out infinite;
}
.compat-card {
background: rgba(10, 15, 26, 0.8);
border-radius: 18px;
padding: 1.8rem;
border: 1px solid var(--border-subtle);
box-shadow: var(--shadow-lg);
backdrop-filter: blur(12px);
display: grid;
gap: 1.2rem;
width: 100%;
max-width: 500px;
min-width: 380px;
}
.compat-card h3 {
font-size: 1.35rem;
color: var(--text-primary);
}
.compat-card p {
font-size: 0.98rem;
color: var(--text-secondary);
line-height: 1.6;
}
.compat-logos {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.75rem;
}
.compat-logos .db-logo {
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
padding: 0.7rem;
background: var(--bg-tertiary);
border: 1px solid var(--border-subtle);
position: relative;
overflow: hidden;
}
.compat-logos img {
width: 44px;
height: 44px;
}
.compat-badges {
display: flex;
flex-wrap: wrap;
gap: 0.6rem 0.75rem;
}
.compat-badge {
padding: 0.35rem 0.75rem;
border-radius: 999px;
background: var(--glow-teal);
color: var(--text-primary);
font-size: 0.82rem;
}
@keyframes twinkle {
0% {
opacity: 0.4;
transform: scale(1) translate3d(0, 0, 0);
}
50% {
opacity: 0.75;
transform: scale(1.05) translate3d(-2%, -3%, 0);
}
100% {
opacity: 0.4;
transform: scale(1) translate3d(0, 0, 0);
}
}
@keyframes orbitSpin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes floatNode {
0% {
transform: translate3d(0, 0, 0);
}
50% {
transform: translate3d(0, -10px, 0);
}
100% {
transform: translate3d(0, 0, 0);
}
}
@media (max-width: 968px) {
.compat-layout {
grid-template-columns: 1fr;
text-align: center;
}
.compat-intro p {
max-width: 100%;
}
.compat-highlights {
justify-content: center;
}
.compat-orbit {
width: 260px;
height: 260px;
}
.compat-node {
width: 74px;
height: 74px;
}
.compat-node img {
width: 46px;
height: 46px;
}
.compat-logos {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 640px) {
.compat-intro h2 {
font-size: 2.6rem;
}
.compat-logos {
grid-template-columns: repeat(2, 1fr);
}
.compat-card {
padding: 1.4rem;
}
}
/* FOOTER STYLES */
footer {
background:
radial-gradient(ellipse 60% 40% at 0% 100%, var(--glow-subtle), transparent 70%),
radial-gradient(ellipse 50% 30% at 100% 0%, var(--glow-subtle), transparent 70%),
linear-gradient(180deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%);
padding: 5rem 0 1rem 0;
border-top: 1px solid var(--border-subtle);
}
footer .container {
padding: 0;
min-height: auto !important;
}
.footer-content {
display: flex;
flex-direction: column;
gap: 5rem;
}
.footer-links {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 5rem;
}
.link-category {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
.link-category h4 {
color: var(--text-primary);
font-size: 1.1rem;
margin-bottom: 0.5rem;
}
.link-category a {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.9rem;
transition: color var(--transition-fast);
}
.link-category a:hover {
color: var(--brand-cyan);
}
.social-links {
display: flex;
gap: 1rem;
justify-content: center;
}
.social-links a {
color: var(--text-secondary);
transition: all var(--transition-fast);
}
.social-links a:hover {
color: var(--brand-cyan);
transform: translateY(-2px);
}
@media (max-width: 768px) {
.footer-links {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.footer-links {
grid-template-columns: 1fr;
}
}
/* SWORD METAL EFFECT */
.sword {
color: transparent;
background:
linear-gradient(180deg,
rgba(255, 255, 255, .8) 0%,
rgba(172, 179, 211, 0.9) 100%),
linear-gradient(135deg,
#ccc 0%,
#ccc 45%,
#fff 50%,
#ccc 55%,
#ccc 100%);
background-blend-mode: multiply;
background-size: 100% 100%, 400% 100%;
background-clip: text;
-webkit-background-clip: text;
animation: shimmer 25s linear infinite;
}
@keyframes shimmer {
0% {
background-position: 400% 0;
}
100% {
background-position: -400% 0;
}
}
.dynamic-title {
font-size: 2.5rem;
background: var(--gradient-primary);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow:
0 1px 1px rgba(0, 0, 0, 0.2),
0 -1px 1px rgba(255, 255, 255, 0.1);
position: relative;
margin-bottom: 1rem;
}
.footer-attribution {
text-align: center;
padding: 2rem 0 1rem 0;
font-size: 0.7rem;
opacity: 0.8;
transition: .2s;
}
.footer-attribution:hover {
opacity: 1;
}
.footer-attribution a {
color: inherit;
text-decoration: none;
border-bottom: 1px dotted currentColor;
}
a {
color: var(--text-primary);
text-decoration: none;
font-weight: 500;
transition: color var(--transition-fast), text-decoration var(--transition-fast);
}
a:hover {
color: var(--brand-cyan);
text-decoration: underline;
text-underline-offset: 2px;
text-decoration-thickness: 1.5px;
}
</style>
</head>
<body>
<nav class="menu">
<a href="/your-first-sql-website/">Download</a>
<a href="/documentation.sql">Documentation</a>
<a href="/examples/tabs">Examples</a>
<a href="https://github.com/sqlpage/SQLPage">Github</a>
<a href="https://datapage.app">Hosting</a>
</nav>
<div class="container">
<div class="logo">
<img src="/assets/icon.webp" alt="SQLPage Logo" width="220" height="248"
style="position: relative; bottom: 13%; object-fit: contain; width: 100%; height: 100%;">
</div>
<div class="text-content">
<h1 class="sword"><span>SQL</span><span class="words"><span class="sword">Page</span><span>
Website</span><span>
App</span><span>
Tools</span><span>
Forms</span><span>
Maps</span><span>
Plots</span><span>
APIs</span></span>
</h1>
<p>Instant web interfaces for your database. Free and open-source.</p>
<a href="/your-first-sql-website/" class="cta-button">Get Started</a>
</div>
</div>
<a href="#features" class="scroll-link">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none">
<path d="M7 13l5 5 5-5M7 6l5 5 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
<section id="features">
<div class="container">
<div class="text-content">
<h2>Build sophisticated tools, easily</h2>
<p>Turn simple SQL queries into beautiful, dynamic web applications.</p>
</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">📈</div>
<h3>Complete</h3>
<p>Create navigatable interfaces with
<a href="/component.sql?component=map">maps</a>,
<a href="/component.sql?component=chart">charts</a>,
<a href="/component.sql?component=table">tables</a>,
<a href="/component.sql?component=form">forms</a>,
<a href="/component.sql?component=card">grids</a>,
<a href="/component.sql?component=big_number">dashboards</a>, and more.
Batteries included.
</p>
</div>
<div class="feature-card">
<div class="feature-icon">⚡</div>
<h3>Fast</h3>
<p>Build fast applications, quickly. You spend one afternoon building your first app. Then it
<a href="/performance">loads instantly</a> for everyone forever.
</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎯</div>
<h3>Easy</h3>
<p>You can teach yourself enough <i>SQL</i> to query and edit a database through SQLPage in a
weekend. Focus on your data, we'll handle <a href="/performance">optimizations</a> and <a
href="/safety">security</a>.</p>
</div>
</div>
</div>
</section>
<section class="feature-section" id="scalable">
<div class="container">
<div class="feature-content">
<h2 class="dynamic-title">More scalable than a spreadsheet</h2>
<p>SQL queries sort, filter, and aggregate millions of rows in milliseconds. No more slow spreadsheet
formulas or memory limitations. Your app remains <a href="/performance">smooth and responsive</a>
even
as your data grows.</p>
</div>
<div class="feature-image">
<video src="/assets/screenshots/big_tables.webm" alt="SQLPage displaying large tables" width="600"
height="400" autoplay loop muted playsinline></video>
</div>
</div>
</section>
<section class="feature-section" id="dynamic">
<div class="container">
<div class="feature-content">
<h2 class="dynamic-title">More dynamic than a dashboard</h2>
<p>Create multi-page interactive websites with drill-down capabilities. Navigate from summaries to
detailed records.
<p>
You should be able to comment, edit, and dive into your data instead of just looking at aggregated
statistics.
<p>
Build apps, not dashboards.
</div>
<div class="feature-image">
<img src="/assets/screenshots/user-creation-form.png"
alt="User creation form, illustrating the ability to create, edit, and delete individual data points, to go beyond simple static dashboards."
width="600" height="400">
</div>
</div>
</section>
<section class="compat-section" id="compatibility">
<div class="container compat-layout">
<div class="compat-intro">
<div class="compat-eyebrow">Database Compatibility</div>
<h2>Works with <em>your</em> database</h2>
<p>SQLPage connects to the database engine you already rely on today.
Keep your data in place and surface it through a
friendly interface that stays in sync.
If you don't have a DB yet, SQLPage comes with a built-in query engine.
</p>
<div class="compat-highlights">
<div class="compat-pill">SQLite built-in</div>
<div class="compat-pill">MySQL &amp; MariaDB</div>
<div class="compat-pill">PostgreSQL family</div>
<div class="compat-pill">Microsoft SQL Server</div>
<div class="compat-pill">ODBC bridge</div>
</div>
</div>
<div class="compat-showcase">
<div class="compat-orbit">
<div class="compat-core" title="Native connectors for SQLite, MySQL, PostgreSQL, and SQL Server">
Native connectors
</div>
<div class="compat-node" title="SQLite"><img src="/assets/db-sqlite.svg" alt="SQLite"></div>
<div class="compat-node" title="MySQL"><img src="/assets/db-mysql.svg" alt="MySQL"></div>
<div class="compat-node" title="PostgreSQL"><img src="/assets/db-postgres.svg" alt="PostgreSQL"></div>
<div class="compat-node" title="Microsoft SQL Server"><img src="/assets/db-sqlserver.svg" alt="Microsoft SQL Server"></div>
</div>
<div class="compat-card">
<h3>Wherever your data lives</h3>
<p>Through ODBC you can plug SQLPage into any warehouses and enterprise engines.</p>
<div class="compat-logos">
<div class="db-logo" title="Open Database Connectivity"><img src="/assets/db-odbc.svg" alt="ODBC"></div>
<div class="db-logo" title="DuckDB: fast portable in-process analytical SQL database"><img src="/assets/db-duckdb.svg" alt="DuckDB"></div>
<div class="db-logo" title="ClickHouse: fast columnar database for OLAP"><img src="/assets/db-clickhouse.svg" alt="ClickHouse"></div>
<div class="db-logo" title="Databricks: cloud-native data warehouse"><img src="/assets/db-databricks.svg" alt="Databricks"></div>
<div class="db-logo" title="Snowflake: cloud-native data warehouse"><img src="/assets/db-snowflake.svg" alt="Snowflake"></div>
<div class="db-logo" title="BigQuery: cloud-native data warehouse"><img src="/assets/db-bigquery.svg" alt="BigQuery"></div>
<div class="db-logo" title="Oracle: enterprise database"><img src="/assets/db-oracle.svg" alt="Oracle"></div>
<div class="db-logo" title="IBM Db2: enterprise database"><img src="/assets/db-db2.svg" alt="Db2"></div>
</div>
<div class="compat-badges">
<span class="compat-badge">No data copy</span>
<span class="compat-badge">Streams query results</span>
</div>
</div>
</div>
</div>
</section>
<section class="feature-section">
<div class="container">
<div class="feature-content">
<h2 class="gradient-title">The power of the web, without the complexity</h2>
<p>Do not code, <i>query</i>. Write SQL, get a web app.
<p>Traditional web programming languages are powerful, but complex.
Using smart opinionated defaults, SQLPage requires 10x less code.
<p>
For advanced customization, you can still optionally use HTML/CSS/JS, and
integrate with external programs and APIs.</p>
</div>
<img src="/assets/screenshots/plot.svg" alt="Simple Web Development. Just SQL" width="380"
style="width: 100%;">
</div>
</section>
<footer>
<div class="container footer-content">
<div class="footer-links">
<div class="link-category">
<h4>Product</h4>
<a href="/your-first-sql-website/">Get Started</a>
<a href="/documentation.sql">Documentation</a>
<a href="/examples/tabs">Examples</a>
<a href="/safety.sql">Security</a>
<a href="/performance.sql">Performance</a>
</div>
<div class="link-category">
<h4>Hosting</h4>
<a href="https://editor.datapage.app">Online Editor</a>
<a href="https://datapage.app">SFTP + Postgres</a>
<a href="https://editor.datapage.app/privacy">Privacy Policy</a>
<a href="https://editor.datapage.app/terms">Terms of Service</a>
<a href="/your-first-sql-website/nginx.sql">Self Hosting</a>
</div>
<div class="link-category">
<h4>Community</h4>
<a href="https://github.com/sqlpage/sqlpage">GitHub</a>
<a href="https://github.com/sqlpage/sqlpage/discussions">Discussions</a>
<a href="https://github.com/sqlpage/sqlpage/issues">Report a Bug</a>
<a href="/blog.sql">Blog</a>
</div>
<div class="link-category">
<h4>Components</h4>
<a href="/component.sql?component=form">SQL Forms</a>
<a href="/component.sql?component=chart">SQL Plots</a>
<a href="/component.sql?component=map">SQL Maps</a>
<a href="/component.sql?component=authentication">Authentication</a>
<a href="/component.sql?component=json">JSON APIs</a>
<a href="/documentation.sql">More...</a>
</div>
</div>
<div class="social-links">
<a href="https://x.com/sqlpage" aria-label="Twitter">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
</a>
<a href="https://github.com/sqlpage/sqlpage" aria-label="GitHub">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.604-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
</svg>
</a>
<a href="https://youtube.com/@sqlpage" aria-label="YouTube">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z" />
</svg>
</a>
</div>
</div>
<div class="footer-attribution">
Built <a href="https://github.com/sqlpage/SQLPage/tree/main/examples/official-site">with SQLPage</a>
</div>
</footer>
</body>
</html>