mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-14 05:04:02 +02:00
Add teams banner
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
@@ -1,4 +1,5 @@
|
|||||||
import { CheckIcon } from '../ReactIcons/CheckIcon';
|
import { CheckIcon } from '../ReactIcons/CheckIcon';
|
||||||
|
import { TeamAnnouncement } from '../TeamAnnouncement';
|
||||||
|
|
||||||
type EmptyProgressProps = {
|
type EmptyProgressProps = {
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -12,12 +13,18 @@ export function EmptyProgress(props: EmptyProgressProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex min-h-full flex-col items-start sm:items-center justify-center py-6">
|
<div className="relative flex min-h-full flex-col items-start justify-center py-6 sm:items-center">
|
||||||
<h2 className={'mb-1 flex items-center text-lg sm:text-2xl text-gray-200'}>
|
<h2
|
||||||
<CheckIcon additionalClasses='mr-2 top-[0.5px] w-[16px] h-[16px] sm:w-[20px] sm:h-[20px]' />
|
className={'mb-1.5 flex items-center text-lg text-gray-200 sm:text-2xl'}
|
||||||
Start learning ..
|
>
|
||||||
|
<CheckIcon additionalClasses="mr-2 top-[0.5px] w-[16px] h-[16px] sm:w-[20px] sm:h-[20px]" />
|
||||||
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
<p className={'text-gray-400 text-sm sm:text-base'}>{message}</p>
|
<p className={'text-sm text-gray-400 sm:text-base'}>{message}</p>
|
||||||
|
|
||||||
|
<p className="mt-5">
|
||||||
|
<TeamAnnouncement />
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -119,7 +119,10 @@ export function FavoriteRoadmaps() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex min-h-[192px] bg-gradient-to-b transition-opacity duration-500 sm:min-h-[280px] opacity-${containerOpacity} ${
|
className={`transition-opacity duration-500 opacity-${containerOpacity}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`flex min-h-[192px] bg-gradient-to-b sm:min-h-[280px] ${
|
||||||
hasProgress && `border-t border-t-[#1e293c]`
|
hasProgress && `border-t border-t-[#1e293c]`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -127,7 +130,6 @@ export function FavoriteRoadmaps() {
|
|||||||
{!isLoading && progress?.length == 0 && <EmptyProgress />}
|
{!isLoading && progress?.length == 0 && <EmptyProgress />}
|
||||||
{hasProgress && (
|
{hasProgress && (
|
||||||
<HeroRoadmaps
|
<HeroRoadmaps
|
||||||
showCustomRoadmaps={true}
|
|
||||||
customRoadmaps={customRoadmaps}
|
customRoadmaps={customRoadmaps}
|
||||||
progress={defaultRoadmaps}
|
progress={defaultRoadmaps}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
@@ -135,5 +137,6 @@ export function FavoriteRoadmaps() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import { MapIcon } from 'lucide-react';
|
|||||||
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
|
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
|
||||||
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { TeamAnnouncement } from '../TeamAnnouncement';
|
||||||
|
|
||||||
type ProgressRoadmapProps = {
|
type ProgressRoadmapProps = {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -87,6 +88,9 @@ export function HeroRoadmaps(props: ProgressListProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative pb-12 pt-4 sm:pt-7">
|
<div className="relative pb-12 pt-4 sm:pt-7">
|
||||||
|
<p className="mb-7 text-sm mt-2">
|
||||||
|
<TeamAnnouncement />
|
||||||
|
</p>
|
||||||
{isCreatingRoadmap && (
|
{isCreatingRoadmap && (
|
||||||
<CreateRoadmapModal onClose={() => setIsCreatingRoadmap(false)} />
|
<CreateRoadmapModal onClose={() => setIsCreatingRoadmap(false)} />
|
||||||
)}
|
)}
|
||||||
|
@@ -1,23 +1,17 @@
|
|||||||
---
|
---
|
||||||
import { FavoriteRoadmaps } from './FavoriteRoadmaps';
|
import { FavoriteRoadmaps } from './FavoriteRoadmaps';
|
||||||
|
import {TeamAnnouncement} from "../TeamAnnouncement";
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class='min-h-auto relative min-h-[192px] border-b border-b-[#1e293c] sm:min-h-[281px]'
|
class='min-h-auto relative min-h-[192px] border-b border-b-[#1e293c] sm:min-h-[281px] transition-all'
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class='container px-5 py-6 pb-14 text-left transition-opacity duration-300 sm:px-0 sm:py-20 sm:text-center'
|
class='container px-5 py-6 pb-14 text-left transition-opacity duration-300 sm:px-0 sm:py-20 sm:text-center'
|
||||||
id='hero-text'
|
id='hero-text'
|
||||||
>
|
>
|
||||||
<p class='-mt-4 sm:-mt-10 mb-4 text-gray-300'>
|
<p class='-mt-4 sm:-mt-10 mb-7'>
|
||||||
<a href='/teams' class="hover:text-white">
|
<TeamAnnouncement />
|
||||||
<span
|
|
||||||
class='mr-1 rounded-sm border-black bg-white px-1 py-0.5 text-center text-xs font-semibold uppercase text-black group-hover:bg-white'
|
|
||||||
>New</span
|
|
||||||
>
|
|
||||||
<span class="hidden sm:inline ml-1">Announcing roadmaps for teams.</span>
|
|
||||||
<span class="inline-block sm:hidden ml-1">Roadmaps for teams.</span>
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1
|
<h1
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
import Icon from '../AstroIcon.astro';
|
import Icon from '../AstroIcon.astro';
|
||||||
import { AccountDropdown } from './AccountDropdown';
|
import { AccountDropdown } from './AccountDropdown';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
||||||
<nav class='container flex items-center justify-between'>
|
<nav class='container flex items-center justify-between'>
|
||||||
<a
|
<a
|
||||||
|
16
src/components/TeamAnnouncement.tsx
Normal file
16
src/components/TeamAnnouncement.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
type TeamAnnouncementProps = {};
|
||||||
|
|
||||||
|
export function TeamAnnouncement(props: TeamAnnouncementProps) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
className="rounded-md border border-dashed border-purple-700 px-3 py-1.5 text-purple-400 transition-colors hover:border-gray-700 hover:text-white"
|
||||||
|
href="/teams"
|
||||||
|
>
|
||||||
|
<span className="relative -top-[0.5px] mr-1 text-xs font-semibold uppercase text-white">
|
||||||
|
New
|
||||||
|
</span>{' '}
|
||||||
|
<span className={'hidden sm:inline'}>Announcing roadmaps for teams. <span className='font-semibold'>Learn more!</span></span>
|
||||||
|
<span className={'inline sm:hidden'}>Announcing roadmaps for teams!</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cn } from '../../lib/classname.ts';
|
import { cn } from '../../lib/classname.ts';
|
||||||
import { isLoggedIn } from '../../lib/jwt.ts';
|
import { isLoggedIn } from '../../lib/jwt.ts';
|
||||||
|
import { fireTeamCreationClick } from './TeamHeroBanner.tsx';
|
||||||
|
|
||||||
const demoItems = [
|
const demoItems = [
|
||||||
{
|
{
|
||||||
@@ -56,7 +57,11 @@ export function TeamDemo() {
|
|||||||
const [hasViewed, setHasViewed] = useState<number[]>([0]);
|
const [hasViewed, setHasViewed] = useState<number[]>([0]);
|
||||||
const [activeItem, setActiveItem] = useState(demoItems[0]);
|
const [activeItem, setActiveItem] = useState(demoItems[0]);
|
||||||
|
|
||||||
const isAuthenticated = isLoggedIn();
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsAuthenticated(isLoggedIn());
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="hidden border-t py-12 sm:block">
|
<div className="hidden border-t py-12 sm:block">
|
||||||
@@ -122,6 +127,7 @@ export function TeamDemo() {
|
|||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
fireTeamCreationClick();
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,6 +144,7 @@ export function TeamDemo() {
|
|||||||
or
|
or
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
fireTeamCreationClick();
|
||||||
localStorage.setItem('authRedirect', '/team/new');
|
localStorage.setItem('authRedirect', '/team/new');
|
||||||
}}
|
}}
|
||||||
href="/login"
|
href="/login"
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { CheckCircle, CheckCircle2, CheckIcon } from 'lucide-react';
|
import { CheckCircle, CheckCircle2, CheckIcon } from 'lucide-react';
|
||||||
import { isLoggedIn } from '../../lib/jwt.ts';
|
import { isLoggedIn } from '../../lib/jwt.ts';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
const featureList = [
|
const featureList = [
|
||||||
'Create custom roadmaps for your team',
|
'Create custom roadmaps for your team',
|
||||||
@@ -8,8 +9,21 @@ const featureList = [
|
|||||||
"Get insights on your team's skills and growth",
|
"Get insights on your team's skills and growth",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export function fireTeamCreationClick() {
|
||||||
|
window.fireEvent({
|
||||||
|
category: 'FeatureClick',
|
||||||
|
action: `Pages / Teams`,
|
||||||
|
label: 'Create your Team',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function TeamHeroBanner() {
|
export function TeamHeroBanner() {
|
||||||
const isAuthenticated = isLoggedIn();
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsAuthenticated(isLoggedIn());
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white py-8 lg:py-12">
|
<div className="bg-white py-8 lg:py-12">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
@@ -34,11 +48,7 @@ export function TeamHeroBanner() {
|
|||||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isAuthenticated) {
|
fireTeamCreationClick();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem('authRedirect', '/team/new');
|
|
||||||
}}
|
}}
|
||||||
href={isAuthenticated ? '/team/new' : '/signup'}
|
href={isAuthenticated ? '/team/new' : '/signup'}
|
||||||
className="flex w-full items-center justify-center rounded-lg border border-transparent bg-purple-600 px-5 py-2 text-sm font-medium text-white hover:bg-blue-700 sm:w-auto sm:text-base"
|
className="flex w-full items-center justify-center rounded-lg border border-transparent bg-purple-600 px-5 py-2 text-sm font-medium text-white hover:bg-blue-700 sm:w-auto sm:text-base"
|
||||||
@@ -52,6 +62,7 @@ export function TeamHeroBanner() {
|
|||||||
<a
|
<a
|
||||||
href="/login"
|
href="/login"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
fireTeamCreationClick();
|
||||||
localStorage.setItem('authRedirect', '/team/new');
|
localStorage.setItem('authRedirect', '/team/new');
|
||||||
}}
|
}}
|
||||||
className="text-purple-600 underline hover:text-purple-700"
|
className="text-purple-600 underline hover:text-purple-700"
|
||||||
@@ -62,6 +73,7 @@ export function TeamHeroBanner() {
|
|||||||
<a
|
<a
|
||||||
href="/login"
|
href="/login"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
fireTeamCreationClick();
|
||||||
localStorage.setItem('authRedirect', '/team/new');
|
localStorage.setItem('authRedirect', '/team/new');
|
||||||
}}
|
}}
|
||||||
className="flex w-full items-center justify-center rounded-lg border border-purple-600 px-5 py-2 text-base text-sm font-medium text-purple-600 hover:bg-blue-700 sm:hidden sm:text-base"
|
className="flex w-full items-center justify-center rounded-lg border border-purple-600 px-5 py-2 text-base text-sm font-medium text-purple-600 hover:bg-blue-700 sm:hidden sm:text-base"
|
||||||
|
@@ -2,12 +2,18 @@ import { Check, CheckCircle, Copy, Sparkles } from 'lucide-react';
|
|||||||
import { useCopyText } from '../../hooks/use-copy-text.ts';
|
import { useCopyText } from '../../hooks/use-copy-text.ts';
|
||||||
import { cn } from '../../lib/classname.ts';
|
import { cn } from '../../lib/classname.ts';
|
||||||
import { isLoggedIn } from '../../lib/jwt.ts';
|
import { isLoggedIn } from '../../lib/jwt.ts';
|
||||||
|
import { fireTeamCreationClick } from './TeamHeroBanner.tsx';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export function TeamPricing() {
|
export function TeamPricing() {
|
||||||
const { isCopied, copyText } = useCopyText();
|
const { isCopied, copyText } = useCopyText();
|
||||||
const teamEmail = 'teams@roadmap.sh';
|
const teamEmail = 'teams@roadmap.sh';
|
||||||
|
|
||||||
const isAuthenticated = isLoggedIn();
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsAuthenticated(isLoggedIn());
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-t py-4 sm:py-8 md:py-12">
|
<div className="border-t py-4 sm:py-8 md:py-12">
|
||||||
@@ -32,6 +38,7 @@ export function TeamPricing() {
|
|||||||
|
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
fireTeamCreationClick();
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user