feat: add Features component and update Community section layout

This commit is contained in:
mr. M 2025-03-08 16:41:56 +01:00
parent 5dc5df961a
commit 5bbf42140c
No known key found for this signature in database
GPG key ID: CBD57A2AEDBDA1FB
8 changed files with 206 additions and 16 deletions

BIN
src/assets/ComImage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

BIN
src/assets/CompactMode.mp4 Normal file

Binary file not shown.

BIN
src/assets/Glance.mp4 Normal file

Binary file not shown.

BIN
src/assets/SplitViews.mp4 Normal file

Binary file not shown.

View file

@ -4,18 +4,18 @@ import Button from '../components/Button.astro'
import { motion } from 'motion/react'
import { Github, Check } from 'lucide-astro'
import { getTitleAnimation } from '../animations'
import Video from './Video.astro'
import WorkspacesVideo from '../assets/Workspaces.mp4'
import ComImage from '../assets/ComImage.png'
import Image from 'astro/components/Image.astro'
---
<section
id="Community"
class="relative flex w-full flex-col items-center px-4 text-start md:px-0 md:text-center lg:py-36"
class="relative flex w-full flex-col items-center px-4 text-start md:px-0 md:text-center lg:pt-36"
>
<Description class="mb-2 px-4 text-6xl font-bold">
<motion.span client:load {...getTitleAnimation(0.2)}> What </motion.span>
<motion.span client:load {...getTitleAnimation(0.4)}> Defines </motion.span>
<motion.span client:load {...getTitleAnimation(0.6)}> Zen? </motion.span>
<motion.span client:load {...getTitleAnimation(0.2)}> Our </motion.span>
<motion.span client:load {...getTitleAnimation(0.4)}> Core </motion.span>
<motion.span client:load {...getTitleAnimation(0.6)}> Values </motion.span>
</Description>
<motion.p
client:load
@ -57,14 +57,10 @@ import WorkspacesVideo from '../assets/Workspaces.mp4'
client:load
{...getTitleAnimation(1.4)}
>
<Video
src={WorkspacesVideo}
autoplay
loop
muted
playsinline
preload="none"
class="mb-24 mt-12 rounded-3xl shadow-md lg:mx-auto lg:w-3/4 dark:opacity-80"
<Image
src={ComImage}
alt="Community"
class="my-24 rounded-3xl shadow-md lg:mx-auto lg:w-4/5 dark:opacity-80"
/>
</motion.span>
</section>

View file

@ -0,0 +1,192 @@
---
import Description from '../components/Description.astro'
import { motion } from 'motion/react'
import { getTitleAnimation } from '../animations'
import WorkspacesVideo from '../assets/Workspaces.mp4'
import GlanceVideo from '../assets/Glance.mp4'
import CompactModeVideo from '../assets/CompactMode.mp4'
import SplitViewsVideo from '../assets/SplitViews.mp4'
import Video from './Video.astro'
---
<section
id="Community"
class="relative flex w-full flex-col px-4 text-start md:px-24 lg:mx-auto lg:w-3/4 lg:px-0 lg:py-36"
>
<Description class="mb-2 text-6xl font-bold">
<motion.span client:load {...getTitleAnimation(0.2)}>
Productivity
</motion.span>
<motion.span client:load {...getTitleAnimation(0.4)}> at </motion.span>
<motion.span client:load {...getTitleAnimation(0.6)}>
its best
</motion.span>
</Description>
<motion.p client:load {...getTitleAnimation(0.6)} className="lg:w-1/2">
Zen is packed with features that help you stay productive and focused.
Browsers should be tools that help you get things done, not distractions
that keep you from your work.
</motion.p>
<div class="mt-6 flex flex-col justify-between gap-2 lg:flex-row">
<div
id="features-list"
class="relative flex w-full flex-col gap-3 md:flex-row lg:w-1/3 lg:flex-col"
>
<motion.div
client:load
{...getTitleAnimation(0.8)}
className="feature"
data-video={WorkspacesVideo}
>
<Description class="text-2xl font-bold">Workspaces</Description>
<Description>
Organize your tabs into workspaces to keep your projects separate and
organized, and switch between them with ease.
</Description>
</motion.div>
<motion.div
client:load
{...getTitleAnimation(1)}
className="feature"
data-video={CompactModeVideo}
>
<Description class="text-2xl font-bold">Compact Mode</Description>
<Description>
Zen's compact mode gives you more screen real estate by hiding the tab
bar when you don't need it, and showing it when you do.
</Description>
</motion.div>
<motion.div
client:load
{...getTitleAnimation(1.2)}
className="feature"
data-video={GlanceVideo}
>
<Description class="text-2xl font-bold">Glance</Description>
<Description>
Zen's glance feature lets you preview tabs without switching to them,
so you can quickly find the tab you're looking for.
</Description>
</motion.div>
<motion.div
client:load
{...getTitleAnimation(1.4)}
className="feature"
data-video={SplitViewsVideo}
>
<Description class="text-2xl font-bold">Split View</Description>
<Description>
Zen's split view feature lets you view two tabs side by side, so you
can compare information or work on two things at once.
</Description>
</motion.div>
</div>
<div class="relative w-1/2">
<Video
autoplay
loop
src=""
muted
playsinline
preload="none"
class="mb-24 hidden rounded-3xl shadow-md lg:absolute lg:mx-auto lg:block lg:w-full dark:opacity-80"
id="feature-video"
/>
</div>
</div>
</section>
<script>
import { animate } from 'motion/react'
const features = document.querySelectorAll('.feature')
const videos = Array.from(features).map(
(f) => f.getAttribute('data-video') as string,
)
var currentFeature = -1
function changeToFeature({
target,
}: {
target: HTMLElement | undefined | null
}) {
target = target?.closest('.feature')
if (!target) return
const index = Array.from(features).indexOf(target)
if (index === -1) return
const videoSrc = videos[index]
const video = document.getElementById('feature-video')
if (!video) return
if (currentFeature === index) return
currentFeature = index
animate(video, {
opacity: 0,
})
video.setAttribute('src', videoSrc)
for (const feature of features) {
feature.removeAttribute('active')
}
target.setAttribute('active', '')
const rect = target.getBoundingClientRect()
video.addEventListener(
'loadeddata',
() => {
const videoParentRect = video.parentElement?.getBoundingClientRect()
const videoRect = video.getBoundingClientRect()
// Always make the video fit the parent
let y =
rect.top -
videoParentRect!.top +
rect.height / 2 -
videoRect.height / 2
if (y < 0) {
if (index === 0) {
y = 0
} else {
y = 20
}
} else if (y + videoRect.height > videoParentRect!.height) {
if (index === features.length - 1) {
y = videoParentRect!.height - videoRect.height
} else {
y = rect.height * index - videoRect.height / 2 + 25
}
}
animate(
video,
{
opacity: 1,
y: y,
},
{},
)
},
{ once: true },
)
}
for (const feature of features) {
feature.addEventListener('click', changeToFeature as any)
}
changeToFeature({ target: features[0] as any })
</script>
<style>
.feature {
@apply w-full cursor-pointer select-none rounded-lg p-4 hover:bg-[rgba(0,0,0,.03)];
transition: background-color 0.2s;
&[active] {
@apply md:bg-[rgba(0,0,0,.05)];
}
}
/* Dont animate translation on small screens */
@media (max-width: 1024px) {
#feature-video {
transform: none !important;
}
}
</style>

View file

@ -2,11 +2,13 @@
import Layout from '../layouts/Layout.astro'
import Hero from '../components/Hero.astro'
import Community from '../components/Community.astro'
import Features from '../components/Features.astro'
---
<Layout title="Zen Browser" isHome>
<main>
<Hero />
<Features />
<Community />
</main>
</Layout>

View file

@ -2147,7 +2147,7 @@
"If the newtab button is at the top, new tabs will be inserted at the top as well"
],
"breakingChanges": [
"The default newtab possition is now at the top (can be disabled in the settings under Look & Feel)",
"The default newtab position is now at the top (can be disabled in the settings under Look & Feel)",
"Changed default pinned behaviour where it always opens a new tab if only pinned tabs exist"
],
"workflowId": 13053102880,
@ -2336,7 +2336,7 @@
"Fixed bookmark items not opening",
"Fixed not hiding empty tab from add-ons, crashing the browser on some cases",
"Fixed compact mode sidebar animating on an empty state and not animating properly when having the URL bar floating",
"Fixed expanding glance not opening in the correct possition when having container specific essentials",
"Fixed expanding glance not opening in the correct position when having container specific essentials",
"Fixed external links not opening in the correct workspace container",
"Fixed appimage not being able to set itself as default web browser",
"Fixed closing the browser in an empty state opening about:blank on startup",