From a825258d10774d141e5991e04a65ce7904705d00 Mon Sep 17 00:00:00 2001 From: Wojtek Majewski Date: Tue, 18 Nov 2025 11:08:37 +0100 Subject: [PATCH] style: update component layout, add quote styling, and improve responsiveness - Adjusted padding and grid layout in HeroWithSlot component for better spacing - Added a styled quote block with hover effects and responsive typography - Enhanced quote container margins and max-width for clarity and mobile support - Included styling for quote link hover states and attribution text - Minor layout tweaks to improve visual separation and consistency across components --- pkgs/website/astro.config.mjs | 24 +- pkgs/website/src/assets/quote-left.svg | 5 + pkgs/website/src/assets/quote-right.svg | 5 + pkgs/website/src/components/CodeOverlay.astro | 32 ++- .../website/src/components/HeroWithSlot.astro | 5 +- pkgs/website/src/components/PageFrame.astro | 259 ++++++++++++++++++ pkgs/website/src/components/Quote.astro | 229 ++++++++++++++++ .../src/components/SVGDAGAnimation.astro | 4 +- .../src/components/TestimonialCarousel.astro | 234 ---------------- .../src/components/TestimonialGrid.astro | 110 ++++++++ pkgs/website/src/content/docs/index.mdx | 39 ++- pkgs/website/src/styles/global.css | 25 +- 12 files changed, 691 insertions(+), 280 deletions(-) create mode 100644 pkgs/website/src/assets/quote-left.svg create mode 100644 pkgs/website/src/assets/quote-right.svg create mode 100644 pkgs/website/src/components/PageFrame.astro create mode 100644 pkgs/website/src/components/Quote.astro delete mode 100644 pkgs/website/src/components/TestimonialCarousel.astro create mode 100644 pkgs/website/src/components/TestimonialGrid.astro diff --git a/pkgs/website/astro.config.mjs b/pkgs/website/astro.config.mjs index 1d0e284bd..3564aad56 100644 --- a/pkgs/website/astro.config.mjs +++ b/pkgs/website/astro.config.mjs @@ -121,29 +121,6 @@ export default defineConfig({ content: 'website', }, }, - { - tag: 'script', - content: ` - document.addEventListener('DOMContentLoaded', function() { - if (!window.location.pathname.startsWith('/author')) { - const sticker = document.createElement('a'); - sticker.href = '/author/'; - sticker.className = 'hire-sticker'; - sticker.textContent = 'Chat with Author'; - document.body.appendChild(sticker); - - // Trigger one-time attention nudge after 5 seconds - setTimeout(function() { - sticker.classList.add('nudge'); - // Remove the class after animation completes - setTimeout(function() { - sticker.classList.remove('nudge'); - }, 800); - }, 5000); - } - }); - `, - }, ], plugins: [ starlightBlog({ @@ -468,6 +445,7 @@ export default defineConfig({ ], components: { Hero: './src/components/ConditionalHero.astro', + PageFrame: './src/components/PageFrame.astro', }, }), robotsTxt({ diff --git a/pkgs/website/src/assets/quote-left.svg b/pkgs/website/src/assets/quote-left.svg new file mode 100644 index 000000000..24c772853 --- /dev/null +++ b/pkgs/website/src/assets/quote-left.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/pkgs/website/src/assets/quote-right.svg b/pkgs/website/src/assets/quote-right.svg new file mode 100644 index 000000000..55dc3572e --- /dev/null +++ b/pkgs/website/src/assets/quote-right.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/pkgs/website/src/components/CodeOverlay.astro b/pkgs/website/src/components/CodeOverlay.astro index 31cf11138..e931cf924 100644 --- a/pkgs/website/src/components/CodeOverlay.astro +++ b/pkgs/website/src/components/CodeOverlay.astro @@ -408,7 +408,7 @@ setTimeout(() => { const resetButton = document.querySelector('.reset-overlay-button') as HTMLElement; if (resetButton) resetButton.style.display = 'block'; - }, 2000); + }, 1700); }); }; @@ -439,8 +439,25 @@ scrollableInner.addEventListener('scroll', updateButtonVisibility, { passive: true }); button.addEventListener('click', () => { + // Cancel any ongoing scroll animation + if (isAnimating) { + isAnimating = false; + if (scrollAnimationFrame) { + cancelAnimationFrame(scrollAnimationFrame); + scrollAnimationFrame = null; + } + } + + // Show the reset overlay button immediately + const resetButton = document.querySelector('.reset-overlay-button') as HTMLElement; + if (resetButton) { + resetButton.style.display = 'block'; + } + // Mark as programmatic scroll to avoid tracking isProgrammaticScroll = true; + + // Scroll to top smoothly scrollableInner.scrollTo({ top: 0, behavior: 'smooth' }); // Reset flag after scroll completes @@ -463,22 +480,31 @@ // Cancel any ongoing animation isAnimating = false; - isProgrammaticScroll = false; // Reset programmatic flag if (scrollAnimationFrame) { cancelAnimationFrame(scrollAnimationFrame); scrollAnimationFrame = null; } + // Mark as programmatic scroll to avoid tracking + isProgrammaticScroll = true; + + // Scroll to top smoothly + scrollableInner.scrollTo({ top: 0, behavior: 'smooth' }); + // Reset to initial state overlay.classList.remove('hidden'); overlay.style.opacity = '1'; scrollableContainer.classList.remove('scrollable-enabled'); - scrollableInner.scrollTop = 0; button.style.display = 'none'; if (scrollTopButton) { scrollTopButton.style.display = 'none'; } + // Reset flag after scroll completes + setTimeout(() => { + isProgrammaticScroll = false; + }, 1000); + // Note: hasTrackedManualScroll is NOT reset here // This means we track manual scroll only once per page session, // even if user reveals, resets, and reveals again diff --git a/pkgs/website/src/components/HeroWithSlot.astro b/pkgs/website/src/components/HeroWithSlot.astro index fb3607a0e..0a14c9b16 100644 --- a/pkgs/website/src/components/HeroWithSlot.astro +++ b/pkgs/website/src/components/HeroWithSlot.astro @@ -52,7 +52,7 @@ const { title = data.title, tagline, actions = [] } = data.hero || {}; order: 2; justify-content: center; } - + .stack { order: 1; flex-direction: column; @@ -93,7 +93,8 @@ const { title = data.title, tagline, actions = [] } = data.hero || {}; .hero { grid-template-columns: 4fr 5fr; gap: 3%; - padding-block: clamp(1.5rem, calc(0.5rem + 8vmin), 8rem); + padding-top: clamp(1.5rem, calc(0.5rem + 8vmin), 8rem); + padding-bottom: 0; } .hero > .hero-html { diff --git a/pkgs/website/src/components/PageFrame.astro b/pkgs/website/src/components/PageFrame.astro new file mode 100644 index 000000000..dd6db2e48 --- /dev/null +++ b/pkgs/website/src/components/PageFrame.astro @@ -0,0 +1,259 @@ +--- +import type { Props } from '@astrojs/starlight/props'; +import Default from '@astrojs/starlight/components/PageFrame.astro'; +import { LinkButton } from '@astrojs/starlight/components'; + +const isAuthorPage = Astro.url.pathname.startsWith('/author'); +const isLandingPage = Astro.url.pathname === '/'; +const showFooter = isLandingPage || isAuthorPage; +--- + + + + + + + +{!isAuthorPage && ( + + Chat with Author + +)} + +{showFooter && ( + +)} + + diff --git a/pkgs/website/src/components/Quote.astro b/pkgs/website/src/components/Quote.astro new file mode 100644 index 000000000..0b6e93dec --- /dev/null +++ b/pkgs/website/src/components/Quote.astro @@ -0,0 +1,229 @@ +--- +interface Props { + text: string; + attribution: string; + source?: string; + href?: string; + class?: string; + size?: 'large' | 'medium' | 'small'; +} + +const { text, attribution, source, href, class: className, size = 'large' } = Astro.props; +--- + +
+ {href ? ( + +
+ +
+

"{text}"

+

+ — {attribution} + {source && ({source})} +

+
+
+
+ ) : ( +
+ +
+

"{text}"

+

+ — {attribution} + {source && ({source})} +

+
+
+ )} +
+ + diff --git a/pkgs/website/src/components/SVGDAGAnimation.astro b/pkgs/website/src/components/SVGDAGAnimation.astro index ea2fc6ce8..c5a685b34 100644 --- a/pkgs/website/src/components/SVGDAGAnimation.astro +++ b/pkgs/website/src/components/SVGDAGAnimation.astro @@ -16,7 +16,7 @@ const { showCaption = true, large = false } = Astro.props; aria-controls="flowDemoSvg" aria-pressed="true" title="Pause animation" - class="anim-ctrl">Pause + class="anim-ctrl plausible-event-name=home:animation-pause">Pause
@@ -24,7 +24,7 @@ const { showCaption = true, large = false } = Astro.props; {showCaption && (

Parallel execution with automatic retry. - How it works? + How it works?

)} diff --git a/pkgs/website/src/components/TestimonialCarousel.astro b/pkgs/website/src/components/TestimonialCarousel.astro deleted file mode 100644 index b1761b2e1..000000000 --- a/pkgs/website/src/components/TestimonialCarousel.astro +++ /dev/null @@ -1,234 +0,0 @@ ---- -const heroTestimonial = { - author: 'cpursley', - source: 'Discord', - message: - 'Got a flow up and running, this is bad ass. I love that everything just goes into Postgres.', -}; - -const testimonials = [ - { - author: 'nel', - source: 'Discord', - message: - 'EdgeWorker is clearly a building block missing from supabase. I toyed with it locally for several days and it worked great.', - }, - { - author: 'Alipio Pereira', - source: 'Discord', - message: - "I'm really enjoying PQFlow — this is incredibly powerful! I'm implementing it in a flow with RAG.", - }, - { - author: 'Jie', - source: 'Discord', - message: - "I've been through hell and back with Airflow, Windmill, Inngest, etc and to be honest i haven't find anything I really love yet.", - }, - { - author: '_perhaps', - source: 'Discord', - message: - 'I was for a while now feeling like there had to be a better way of handling workflows on a supabase project without needing to add something like inngest or n8n to my tech stack. It clicked really hard when I found out about your project', - }, - { - author: 'TapTap2121', - source: 'Reddit', - message: - "I was searching through the docs for something like this and I'm quite surprised it's not part of Supabase already. A queue feels kinda useless with serverless runners if I need to trigger them manually", - }, - { - author: 'Revolutionary-Fact28', - source: 'Reddit', - message: - 'I built a system to this on edge functions but it was very complicated and took so much time this will be amazing! I will be probably switch to this.', - }, - { - author: 'CjHuber', - source: 'Hacker News', - message: - 'Exactly what I was looking for without even knowing it :) well I knew I need smt like this, but I thought I\'d had to build a very rudimentary version myself. Thank you for saving me tons of time', - }, - { - author: 'enciso', - source: 'Discord', - message: - 'I was trying to build my own after having a couple of pgmq queues... you found a problem and you are giving a very good solution', - }, -]; ---- - -
- -
-
- {heroTestimonial.message} -
-
-
@{heroTestimonial.author}
-
{heroTestimonial.source}
-
-
- - -
- {testimonials.map((testimonial) => ( -
-
- {testimonial.message} -
-
-
@{testimonial.author}
-
{testimonial.source}
-
-
- ))} -
-
- - diff --git a/pkgs/website/src/components/TestimonialGrid.astro b/pkgs/website/src/components/TestimonialGrid.astro new file mode 100644 index 000000000..d7a027192 --- /dev/null +++ b/pkgs/website/src/components/TestimonialGrid.astro @@ -0,0 +1,110 @@ +--- +import Quote from './Quote.astro'; + +const heroTestimonial = { + author: 'cpursley', + source: 'Discord', + message: + 'Got a flow up and running, this is bad ass. I love that everything just goes into Postgres.', +}; + +const testimonials = [ + { + author: 'nel', + source: 'Discord', + message: + 'EdgeWorker is clearly a building block missing from supabase. I toyed with it locally for several days and it worked great.', + }, + { + author: 'Alipio Pereira', + source: 'Discord', + message: + "I'm really enjoying PQFlow — this is incredibly powerful! I'm implementing it in a flow with RAG.", + }, + { + author: '_perhaps', + source: 'Discord', + message: + 'I was for a while now feeling like there had to be a better way of handling workflows on a supabase project without needing to add something like inngest or n8n to my tech stack. It clicked really hard when I found out about your project', + }, + { + author: 'TapTap2121', + source: 'Reddit', + message: + "I was searching through the docs for something like this and I'm quite surprised it's not part of Supabase already. A queue feels kinda useless with serverless runners if I need to trigger them manually", + }, + { + author: 'CjHuber', + source: 'Hacker News', + message: + 'Exactly what I was looking for without even knowing it :) well I knew I need smt like this, but I thought I\'d had to build a very rudimentary version myself. Thank you for saving me tons of time', + }, + { + author: 'enciso', + source: 'Discord', + message: + 'I was trying to build my own after having a couple of pgmq queues... you found a problem and you are giving a very good solution', + }, +]; +--- + +
+ +
+ +
+ + +
+ {testimonials.map((testimonial) => ( + + ))} +
+
+ + diff --git a/pkgs/website/src/content/docs/index.mdx b/pkgs/website/src/content/docs/index.mdx index 465cb9186..61ed34974 100644 --- a/pkgs/website/src/content/docs/index.mdx +++ b/pkgs/website/src/content/docs/index.mdx @@ -11,10 +11,14 @@ hero: icon: right-arrow variant: primary attrs: - class: plausible-event-name=home:cta-get-started - - text: How It Works + class: call-to-action plausible-event-name=home:cta-get-started + - text: Try Demo + link: https://demo.pgflow.dev/ + variant: secondary + attrs: + class: plausible-event-name=home:cta-try-demo + - text: How It Works? link: /concepts/how-pgflow-works/ - icon: information variant: minimal attrs: class: plausible-event-name=home:cta-how-it-works @@ -22,8 +26,17 @@ editUrl: false --- import { Card, CardGrid, LinkCard, Aside, Tabs, TabItem } from '@astrojs/starlight/components'; -import TestimonialCarousel from '../../components/TestimonialCarousel.astro'; +import TestimonialGrid from '../../components/TestimonialGrid.astro'; import CodeOverlay from '../../components/CodeOverlay.astro'; +import Quote from '../../components/Quote.astro'; + +
@@ -350,13 +363,13 @@ new Flow<{ url: string }>({ slug: 'analyzeArticle' })
-
+
```bash npx pgflow@latest install ``` -
Sets up pgflow in your Supabase project. View full setup guide →
+
Sets up pgflow in your Supabase project. View full setup guide →
@@ -364,33 +377,33 @@ npx pgflow@latest install - Skip the tedious pg_cron → pgmq → Edge Function setup. No manual queue wiring, no archive code, no state table management. pgflow handles all the plumbing - you just define your workflow. [Learn more →](/get-started/installation/) + Skip the tedious pg_cron → pgmq → Edge Function setup. No manual queue wiring, no archive code, no state table management. pgflow handles all the plumbing - you just define your workflow. Learn more → - Everything in your existing Supabase project. No Bull, no Redis, no Temporal, no Railway. No external services, no vendor dashboards, no additional infrastructure to manage. [Learn more →](/concepts/how-pgflow-works/) + Everything in your existing Supabase project. No Bull, no Redis, no Temporal, no Railway. No external services, no vendor dashboards, no additional infrastructure to manage. Learn more → - All workflow state lives in Postgres tables. Query execution history, inspect step outputs, and debug failures with standard SQL. No hidden state, no external dashboards. [Learn more →](/deploy/monitor-execution/) + All workflow state lives in Postgres tables. Query execution history, inspect step outputs, and debug failures with standard SQL. No hidden state, no external dashboards. Learn more → - Built-in retry logic with exponential backoff for flaky AI APIs. When OpenAI times out or rate-limits, only that step retries - your workflow continues. Configure max attempts and delays per step, no retry code needed. [Learn more →](/build/retrying-steps/) + Built-in retry logic with exponential backoff for flaky AI APIs. When OpenAI times out or rate-limits, only that step retries - your workflow continues. Configure max attempts and delays per step, no retry code needed. Learn more → - Process arrays in parallel with independent retries per item. Batch 100 embeddings - if 3 fail, only those 3 retry while others continue. Perfect for AI workloads with unreliable APIs. [Learn more →](/build/process-arrays-in-parallel/) + Process arrays in parallel with independent retries per item. Batch 100 embeddings - if 3 fail, only those 3 retry while others continue. Perfect for AI workloads with unreliable APIs. Learn more → - Start workflows from database triggers, scheduled pg_cron jobs, browser clients, or RPC calls. Ultimate flexibility in how you start your workflows. [Learn more →](/build/starting-flows/) + Start workflows from database triggers, scheduled pg_cron jobs, browser clients, or RPC calls. Ultimate flexibility in how you start your workflows. Learn more → ## What Developers Say - +
diff --git a/pkgs/website/src/styles/global.css b/pkgs/website/src/styles/global.css index a327ee4cf..02bc02ece 100644 --- a/pkgs/website/src/styles/global.css +++ b/pkgs/website/src/styles/global.css @@ -70,6 +70,7 @@ svg .secondary { } @keyframes breathing-glow { + 0%, 100% { filter: drop-shadow(0 0 0 transparent); @@ -84,7 +85,7 @@ svg .secondary { .call-to-action { font-weight: bold; box-shadow: 0 0 10px var(--logo-glow-color), 0 0 15px var(--logo-glow-color); - filter: brightness(1.15); + filter: brightness(1.05); transition: all 0.3s ease; &:hover { @@ -93,6 +94,11 @@ svg .secondary { } } +/* Bold hero primary CTA */ +.hero .actions .sl-link-button.primary { + font-weight: bold; +} + /* HERO QUICKSTART */ .hero-quickstart { text-align: center; @@ -329,10 +335,23 @@ svg .secondary { } } -/* Hide on small screens */ +/* Mobile: Convert to fixed footer bar */ @media (max-width: 768px) { .hire-sticker { - display: none; + bottom: 0; + right: 0; + left: 0; + width: 100%; + border-radius: 0; + padding: 10px 20px; + text-align: center; + justify-content: center; + box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15); + font-size: 0.9rem; + } + + .hire-sticker:hover { + transform: none; } }