Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@
]
},
"scripts": {
"pre-autoload-dump": [
"pre-autoload-dump": [
"Google\\Task\\Composer::cleanup"
],
"post-install-cmd": [
Expand Down
3 changes: 0 additions & 3 deletions web/landing/.env
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,3 @@ TURNSTILE_SITE_KEY=0x4AAAAAACAjJaWImyaJwWCy
TURNSTILE_APPEARANCE=interaction-only
PLAYGROUND_API_URL=http://localhost:8787/api/playground/snippets
PLAYGROUND_SNIPPETS_URL=http://localhost:8787
DATADOG_APPLICATION_ID=4a297124-5ea7-4fc5-b75a-6fb71e699f54
DATADOG_CLIENT_TOKEN=pubf4d7626f7fd335a27355e01cd877c277
DATADOG_SITE=datadoghq.eu
3 changes: 0 additions & 3 deletions web/landing/.env.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
POSTHOG_KEY=
POSTHOG_API_HOST=
POSTHOG_UI_HOST=
DATADOG_APPLICATION_ID=
DATADOG_CLIENT_TOKEN=
DATADOG_SITE=
3 changes: 0 additions & 3 deletions web/landing/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ DOMAIN='flow-php.wip'
POSTHOG_KEY=
POSTHOG_API_HOST=
POSTHOG_UI_HOST=
DATADOG_APPLICATION_ID=
DATADOG_CLIENT_TOKEN=
DATADOG_SITE=
FLOW_VERSION=1.x-dev
TURNSTILE_SITE_KEY=0x4AAAAAACAjJaWImyaJwWCy
TURNSTILE_APPEARANCE=interaction-only
Expand Down
77 changes: 76 additions & 1 deletion web/landing/assets/codemirror/completions/dsl.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* CodeMirror Completer for Flow PHP DSL Functions
*
* Total functions: 821
* Total functions: 826
*
* This completer provides autocompletion for all Flow PHP DSL functions:
* - Extractors (flow-extractors)
Expand Down Expand Up @@ -2963,6 +2963,21 @@ const dslFunctions = [
},
apply: snippet("\\Flow\\PostgreSql\\DSL\\current_date()"),
boost: 10
}, {
label: "current_row",
type: "function",
detail: "flow\u002Ddsl\u002Ddata\u002Dframe",
info: () => {
const div = document.createElement("div")
div.innerHTML = `
<div style="font-family: 'Fira Code', 'JetBrains Mono', monospace; margin-bottom: 8px;">
<span class=\"fn-name\">current_row</span><span class=\"fn-operator\">(</span><span class=\"fn-operator\">)</span> <span class=\"fn-operator\">:</span> <span class=\"fn-return\">FrameBound</span>
</div>
`
return div
},
apply: snippet("\\Flow\\ETL\\DSL\\current_row()"),
boost: 10
}, {
label: "current_time",
type: "function",
Expand Down Expand Up @@ -4205,6 +4220,21 @@ const dslFunctions = [
},
apply: snippet("\\Flow\\ETL\\DSL\\flow_context(" + "$" + "{" + "1:config" + "}" + ")"),
boost: 10
}, {
label: "following",
type: "function",
detail: "flow\u002Ddsl\u002Ddata\u002Dframe",
info: () => {
const div = document.createElement("div")
div.innerHTML = `
<div style="font-family: 'Fira Code', 'JetBrains Mono', monospace; margin-bottom: 8px;">
<span class=\"fn-name\">following</span><span class=\"fn-operator\">(</span><span class=\"fn-type\">int</span> <span class=\"fn-param\">$offset</span><span class=\"fn-operator\">)</span> <span class=\"fn-operator\">:</span> <span class=\"fn-return\">FrameBound</span>
</div>
`
return div
},
apply: snippet("\\Flow\\ETL\\DSL\\following(" + "$" + "{" + "1:offset" + "}" + ")"),
boost: 10
}, {
label: "foreign_key",
type: "function",
Expand Down Expand Up @@ -7913,6 +7943,21 @@ const dslFunctions = [
},
apply: snippet("\\Flow\\ETL\\Adapter\\Doctrine\\postgresql_update_options(" + "$" + "{" + "1:primary_key_columns" + "}" + ", " + "$" + "{" + "2:update_columns" + "}" + ")"),
boost: 10
}, {
label: "preceding",
type: "function",
detail: "flow\u002Ddsl\u002Ddata\u002Dframe",
info: () => {
const div = document.createElement("div")
div.innerHTML = `
<div style="font-family: 'Fira Code', 'JetBrains Mono', monospace; margin-bottom: 8px;">
<span class=\"fn-name\">preceding</span><span class=\"fn-operator\">(</span><span class=\"fn-type\">int</span> <span class=\"fn-param\">$offset</span><span class=\"fn-operator\">)</span> <span class=\"fn-operator\">:</span> <span class=\"fn-return\">FrameBound</span>
</div>
`
return div
},
apply: snippet("\\Flow\\ETL\\DSL\\preceding(" + "$" + "{" + "1:offset" + "}" + ")"),
boost: 10
}, {
label: "prepare_transaction",
type: "function",
Expand Down Expand Up @@ -12626,6 +12671,36 @@ const dslFunctions = [
},
apply: snippet("\\Flow\\ETL\\DSL\\ulid(" + "$" + "{" + "1:value" + "}" + ")"),
boost: 10
}, {
label: "unbounded_following",
type: "function",
detail: "flow\u002Ddsl\u002Ddata\u002Dframe",
info: () => {
const div = document.createElement("div")
div.innerHTML = `
<div style="font-family: 'Fira Code', 'JetBrains Mono', monospace; margin-bottom: 8px;">
<span class=\"fn-name\">unbounded_following</span><span class=\"fn-operator\">(</span><span class=\"fn-operator\">)</span> <span class=\"fn-operator\">:</span> <span class=\"fn-return\">FrameBound</span>
</div>
`
return div
},
apply: snippet("\\Flow\\ETL\\DSL\\unbounded_following()"),
boost: 10
}, {
label: "unbounded_preceding",
type: "function",
detail: "flow\u002Ddsl\u002Ddata\u002Dframe",
info: () => {
const div = document.createElement("div")
div.innerHTML = `
<div style="font-family: 'Fira Code', 'JetBrains Mono', monospace; margin-bottom: 8px;">
<span class=\"fn-name\">unbounded_preceding</span><span class=\"fn-operator\">(</span><span class=\"fn-operator\">)</span> <span class=\"fn-operator\">:</span> <span class=\"fn-return\">FrameBound</span>
</div>
`
return div
},
apply: snippet("\\Flow\\ETL\\DSL\\unbounded_preceding()"),
boost: 10
}, {
label: "union_schema",
type: "function",
Expand Down
59 changes: 59 additions & 0 deletions web/landing/assets/controllers/shop_carousel_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["track", "slide", "dot"]
static values = { index: { type: Number, default: 0 } }

indexValueChanged() {
const count = this.slideTargets.length

if (count === 0) {
return
}

if (this.indexValue < 0) {
this.indexValue = count - 1
return
}

if (this.indexValue > count - 1) {
this.indexValue = 0
return
}

this.trackTarget.style.transform = `translateX(-${this.indexValue * 100}%)`

this.slideTargets.forEach((slide, i) => {
slide.setAttribute('aria-hidden', i === this.indexValue ? 'false' : 'true')
})

this.dotTargets.forEach((dot, i) => {
const active = i === this.indexValue
dot.classList.toggle('bg-white', active)
dot.classList.toggle('bg-white/40', !active)
dot.setAttribute('aria-current', active ? 'true' : 'false')
})
}

next() {
this.indexValue++
}

prev() {
this.indexValue--
}

goTo(event) {
this.indexValue = Number(event.params.index)
}

keydown(event) {
if (event.key === "ArrowLeft") {
event.preventDefault()
this.prev()
} else if (event.key === "ArrowRight") {
event.preventDefault()
this.next()
}
}
}
14 changes: 14 additions & 0 deletions web/landing/assets/controllers/shop_checkout_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Controller } from "@hotwired/stimulus"
import { PolarEmbedCheckout } from "@polar-sh/checkout/embed"

export default class extends Controller {
static values = { url: String }

open(event) {
event.preventDefault()

const theme = document.documentElement.classList.contains("dark") ? "dark" : "light"

PolarEmbedCheckout.create(this.urlValue, { theme })
}
}
153 changes: 153 additions & 0 deletions web/landing/assets/controllers/shop_confetti_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { Controller } from "@hotwired/stimulus"

// Brand palette from tailwind.config.js, plus white so the fall reads on the dark theme.
const COLORS = ["#ff5547", "#806dfe", "#e1761a", "#5945d8", "#ffffff"]
const PIECES = 150
const GRAVITY = 0.04
const MAX_FALL = 3.5
// Pieces start staggered above the fold so they keep arriving instead of landing all at once.
const STAGGER = 1.1
const FADE_FROM = 0.82

export default class extends Controller {
connect() {
this.motion = window.matchMedia("(prefers-reduced-motion: reduce)")
this.pieces = []
this.frame = null
this.onResize = () => this.#resize()

this.burst()
}

disconnect() {
this.#stop()
this.#unmount()
}

burst() {
if (this.motion.matches) {
return
}

this.#mount()

const width = window.innerWidth
const height = window.innerHeight

for (let i = 0; i < PIECES; i++) {
this.pieces.push({
x: Math.random() * width,
y: -20 - Math.random() * height * STAGGER,
vx: (Math.random() - 0.5) * 0.7,
vy: 1 + Math.random() * 1.5,
sway: 0.4 + Math.random() * 1.1,
swaySpeed: 0.01 + Math.random() * 0.03,
phase: Math.random() * Math.PI * 2,
width: 5 + Math.random() * 5,
height: 9 + Math.random() * 6,
rotation: Math.random() * Math.PI * 2,
spin: (Math.random() - 0.5) * 0.12,
flip: Math.random() * Math.PI * 2,
flipSpeed: 0.05 + Math.random() * 0.09,
color: COLORS[Math.floor(Math.random() * COLORS.length)],
})
}

this.#start()
}

#tick() {
const context = this.context
const height = window.innerHeight

context.clearRect(0, 0, window.innerWidth, height)

this.pieces = this.pieces.filter((piece) => {
piece.vy = Math.min(piece.vy + GRAVITY, MAX_FALL)
piece.phase += piece.swaySpeed
piece.y += piece.vy
piece.x += piece.vx + Math.sin(piece.phase) * piece.sway
piece.rotation += piece.spin
piece.flip += piece.flipSpeed

if (piece.y > height + 40) {
return false
}

const travelled = piece.y / height

context.save()
context.translate(piece.x, piece.y)
context.rotate(piece.rotation)
// Squashing the height as it tumbles fakes a flat piece turning over.
context.scale(1, Math.abs(Math.cos(piece.flip)))
context.globalAlpha = travelled > FADE_FROM ? Math.max(0, 1 - (travelled - FADE_FROM) / (1 - FADE_FROM)) : 1
context.fillStyle = piece.color
context.fillRect(-piece.width / 2, -piece.height / 2, piece.width, piece.height)
context.restore()

return true
})

if (this.pieces.length === 0) {
this.#stop()
this.#unmount()

return
}

this.frame = window.requestAnimationFrame(() => this.#tick())
}

#mount() {
if (this.canvas) {
return
}

this.canvas = document.createElement("canvas")
this.canvas.setAttribute("aria-hidden", "true")
this.canvas.style.cssText = "position:fixed;inset:0;pointer-events:none;z-index:60"
document.body.appendChild(this.canvas)
this.context = this.canvas.getContext("2d")

this.#resize()
window.addEventListener("resize", this.onResize)
}

#resize() {
if (!this.canvas) {
return
}

const ratio = window.devicePixelRatio || 1

this.canvas.width = window.innerWidth * ratio
this.canvas.height = window.innerHeight * ratio
this.canvas.style.width = `${window.innerWidth}px`
this.canvas.style.height = `${window.innerHeight}px`
this.context.setTransform(ratio, 0, 0, ratio, 0, 0)
}

#unmount() {
window.removeEventListener("resize", this.onResize)

if (this.canvas) {
this.canvas.remove()
this.canvas = null
this.context = null
}
}

#start() {
if (this.frame === null) {
this.frame = window.requestAnimationFrame(() => this.#tick())
}
}

#stop() {
if (this.frame !== null) {
window.cancelAnimationFrame(this.frame)
this.frame = null
}
}
}
Loading
Loading