-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PAYG] [dashboard] Onboarding: Product Educational content in `/ work…
…spaces` view (#20021) * intial commit * Documentation links * Update YouTube Videos * cleanup + performant YT method * Static section of `Personalised for you` 😜 * Add blog banners * Minor fixes * Educational content should only be in Gitpod PAYG & minor fixes * nit fix * nti fix * reorder docs link * nit fix * final nit fix :) * fix the label issue, video bug, line break in banner * use `flex-1` * bring back old description copy for header * improve spacing * Optimize VideoCarousel rendering and key usage - Render only the current video to improve performance - Remove redundant key prop from lite-youtube component - Ensure unique keys for list items in VideoCarousel * Enhance VideoCarousel button accessibility - Add focus rings to video selection buttons - Improve keyboard navigation with visible focus indicators
- Loading branch information
1 parent
1f5bc61
commit ccca3a6
Showing
10 changed files
with
351 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/** | ||
* Copyright (c) 2024 Gitpod GmbH. All rights reserved. | ||
* Licensed under the GNU Affero General Public License (AGPL). | ||
* See License.AGPL.txt in the project root for license information. | ||
*/ | ||
|
||
import React, { useEffect, useState } from "react"; | ||
import blogBannerBg from "../images/blog-banner-bg.png"; | ||
|
||
const banners = [ | ||
{ | ||
type: "Blog Post", | ||
title: "Gitpod Enterprise:<br/> Self-hosted, not self-managed", | ||
link: "https://www.gitpod.io/blog/self-hosted-not-self-managed", | ||
}, | ||
{ | ||
type: "Customer Story", | ||
title: "Thousands of hours spent on VM-based development environments reduced to zero using Gitpod", | ||
link: "https://www.gitpod.io/customers/kingland", | ||
}, | ||
{ | ||
type: "Gartner Report", | ||
title: `"By 2026, 60% of cloud workloads will be built and deployed using CDE's"`, | ||
link: "https://www.gitpod.io/blog/gartner-2023-cde-hypecycle", | ||
}, | ||
{ | ||
type: "Webinar Series", | ||
title: "The Platform Engineering maturity model", | ||
link: "https://www.gitpod.io/events#platform-maturity-model-series", | ||
}, | ||
]; | ||
|
||
const initialBannerIndex = 0; // Index for "Self-hosted, not self-managed" | ||
|
||
export const BlogBanners: React.FC = () => { | ||
const [currentBannerIndex, setCurrentBannerIndex] = useState(initialBannerIndex); | ||
|
||
useEffect(() => { | ||
const storedBannerData = localStorage.getItem("blog-banner-data"); | ||
const currentTime = new Date().getTime(); | ||
|
||
if (storedBannerData) { | ||
const { lastIndex, lastTime } = JSON.parse(storedBannerData); | ||
|
||
if (currentTime - lastTime >= 2 * 24 * 60 * 60 * 1000) { | ||
// 2 days in milliseconds | ||
const nextIndex = getRandomBannerIndex(lastIndex); | ||
setCurrentBannerIndex(nextIndex); | ||
localStorage.setItem( | ||
"blog-banner-data", | ||
JSON.stringify({ lastIndex: nextIndex, lastTime: currentTime }), | ||
); | ||
} else { | ||
setCurrentBannerIndex(lastIndex); | ||
} | ||
} else { | ||
setCurrentBannerIndex(initialBannerIndex); | ||
localStorage.setItem( | ||
"blog-banner-data", | ||
JSON.stringify({ lastIndex: initialBannerIndex, lastTime: currentTime }), | ||
); | ||
} | ||
}, []); | ||
|
||
const getRandomBannerIndex = (excludeIndex: number) => { | ||
let nextIndex; | ||
do { | ||
nextIndex = Math.floor(Math.random() * banners.length); | ||
} while (nextIndex === excludeIndex || nextIndex === initialBannerIndex); | ||
return nextIndex; | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col"> | ||
<a | ||
href={banners[currentBannerIndex].link} | ||
target="_blank" | ||
rel="noopener noreferrer" | ||
className="bg-pk-surface rounded-lg overflow-hidden flex flex-col gap-2 text-decoration-none text-inherit max-w-[320px] border border-gray-200 dark:border-gray-800 hover:shadow" | ||
aria-label={banners[currentBannerIndex].type + " - " + banners[currentBannerIndex].title} | ||
style={{ | ||
backgroundPosition: "top left", | ||
backgroundRepeat: "no-repeat", | ||
backgroundImage: `url(${blogBannerBg})`, | ||
backgroundSize: "contain", | ||
}} | ||
> | ||
<div className="flex flex-col gap-8 mt-6 ml-4 max-w-[320px] overflow-wrap min-h-fit pb-4"> | ||
<div className="bg-pk-surface-invert w-fit text-pk-content-invert-primary text-sm leading-[18px] font-bold rounded-2xl py-1 px-4"> | ||
{banners[currentBannerIndex].type} | ||
</div> | ||
<div | ||
className="text-base font-semibold text-pk-content-primary max-w-[285px]" | ||
dangerouslySetInnerHTML={{ __html: banners[currentBannerIndex].title }} | ||
/> | ||
</div> | ||
</a> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/** | ||
* Copyright (c) 2024 Gitpod GmbH. All rights reserved. | ||
* Licensed under the GNU Affero General Public License (AGPL). | ||
* See License.AGPL.txt in the project root for license information. | ||
*/ | ||
|
||
import React, { useState } from "react"; | ||
import { trackVideoClick } from "../Analytics"; | ||
|
||
import "lite-youtube-embed/src/lite-yt-embed.css"; | ||
import "lite-youtube-embed/src/lite-yt-embed"; | ||
|
||
interface Video { | ||
id: string; | ||
title: string; | ||
analyticsLabel: string; | ||
} | ||
|
||
const videos: Video[] = [ | ||
{ id: "1ZBN-b2cIB8", title: "Gitpod in 120 seconds", analyticsLabel: "gitpod-demo" }, | ||
{ id: "zhZNnzFlZnY", title: "Getting started with Gitpod", analyticsLabel: "getting-started-with-gitpod" }, | ||
{ id: "kuoHM2bpBqY", title: "Fully automate your dev setup", analyticsLabel: "automate-gitpod-setup" }, | ||
{ id: "_CwFzCbAsoU", title: "Personalise your workspace", analyticsLabel: "personalise-gitpod-workspace" }, | ||
]; | ||
|
||
declare global { | ||
namespace JSX { | ||
interface IntrinsicElements { | ||
"lite-youtube": any; | ||
} | ||
} | ||
} | ||
|
||
export const VideoCarousel: React.FC = () => { | ||
const [currentVideo, setCurrentVideo] = useState(0); | ||
|
||
const handleDotClick = (index: number) => { | ||
setCurrentVideo(index); | ||
}; | ||
|
||
const onPlayerStateChange = (index: number) => { | ||
trackVideoClick(videos[index].analyticsLabel); | ||
}; | ||
|
||
return ( | ||
<div className="video-carousel"> | ||
<div className="video-container"> | ||
{videos.map((video, index) => ( | ||
<div key={video.id} style={{ display: index === currentVideo ? "block" : "none" }}> | ||
{index === currentVideo && ( | ||
<lite-youtube | ||
videoid={video.id} | ||
style={{ | ||
width: "320px", | ||
height: "180px", | ||
}} | ||
class="rounded-lg" | ||
playlabel={video.title} | ||
onClick={() => onPlayerStateChange(index)} | ||
></lite-youtube> | ||
)} | ||
</div> | ||
))} | ||
</div> | ||
<div className="flex justify-center space-x-2 mt-2"> | ||
{videos.map((_, index) => ( | ||
<button | ||
key={index} | ||
className={`w-3 h-3 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-kumquat-dark transition-colors duration-200 ease-in-out ${ | ||
index === currentVideo | ||
? "bg-kumquat-dark" | ||
: "bg-gray-300 dark:bg-gray-600 hover:bg-kumquat-light dark:hover:bg-kumquat-light" | ||
}`} | ||
onClick={() => handleDotClick(index)} | ||
aria-label={`Go to video ${index + 1}`} | ||
></button> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.