-
Notifications
You must be signed in to change notification settings - Fork 4.3k
KTL-3868: Move KMP landing page - hero block #5193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: ktl-3875-kmp-landing-page
Are you sure you want to change the base?
Changes from all commits
9029ece
bb8c82d
323cffd
71ee4dc
57986c2
409576c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| @import "@jetbrains/kotlin-web-site-ui/out/components/breakpoints-v2/media.pcss"; | ||
|
|
||
| .wrapper { | ||
| position: relative; | ||
| z-index: 0; | ||
| overflow: hidden; | ||
| } | ||
|
|
||
| .wrapper::before { | ||
| content: ''; | ||
| display: block; | ||
|
|
||
| background: radial-gradient(238.09% 60.02% at 49.98% 105.17%, rgba(177, 38, 235, 0.00) 0%, #260053 100%) center no-repeat; | ||
| filter: blur(200px); | ||
|
|
||
| height: 696px; | ||
| width: 826px; | ||
|
|
||
| position: absolute; | ||
| top: 36px; | ||
| left: 50%; | ||
| transform: translate(-50%, -50%); | ||
| z-index: -1; | ||
| } | ||
|
|
||
| .hero { | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
|
|
||
| padding-block: 72px 96px; | ||
|
|
||
| --hero-logo-image: ''; | ||
| } | ||
|
|
||
| .hero::before { | ||
| display: block; | ||
| content: ''; | ||
| background: var(--hero-logo-image) no-repeat center; | ||
|
|
||
| height: 72px; | ||
| width: 72px; | ||
|
|
||
| @media (--ktl-ts-more) { | ||
| height: 96px; | ||
| width: 96px; | ||
| } | ||
| } | ||
|
|
||
| .title, .subtitle { | ||
| margin: 0; | ||
| padding: 0; | ||
| text-align: center; | ||
| } | ||
|
|
||
| .title { | ||
| padding-block: 24px; | ||
|
|
||
| @media (--ktl-ts-in) { | ||
| /* @mixin rs-hero-sm-*; */ | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to add
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to get font-size and line height, right? |
||
| font-size: 42px; | ||
| line-height: 50px; | ||
| } | ||
| } | ||
|
|
||
| .subtitle { | ||
| @media (--ktl-ts-in) { | ||
| /* @mixin rs-subtitle-1-sm-* */ | ||
| font-size: 23px; | ||
| line-height: 30px; | ||
| } | ||
| } | ||
|
|
||
| .platforms { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
| justify-content: center; | ||
|
|
||
| box-sizing: border-box; | ||
| gap: 18px 40px; | ||
| width: 100%; | ||
|
|
||
| margin: 0; | ||
| padding: 48px 0; | ||
| list-style: none; | ||
|
|
||
| --hero-item-src: ''; | ||
| } | ||
|
|
||
| .platform { | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| justify-content: center; | ||
| gap: 8px; | ||
|
|
||
| line-height: 1.5; | ||
|
|
||
| @media (--ktl-ts-more) { | ||
| flex-basis: 80px; | ||
| } | ||
|
|
||
| @media (--ktl-ms-in) { | ||
| padding-inline: 14px; | ||
| } | ||
| } | ||
|
|
||
| .platform::before { | ||
| display: block; | ||
| content: ''; | ||
|
|
||
| background: var(--hero-item-src) no-repeat center; | ||
| background-size: 32px; | ||
| height: 32px; | ||
| width: 32px; | ||
|
|
||
| @media (--ktl-ts-more) { | ||
| background-size: 48px; | ||
| height: 48px; | ||
| width: 48px; | ||
| } | ||
| } | ||
|
|
||
| .button { | ||
| @media (--ktl-ms-in) { | ||
| width: 100%; | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import cn from 'classnames'; | ||
|
|
||
| import { useTextStyles } from '@rescui/typography'; | ||
| import { Button } from '@rescui/button'; | ||
|
|
||
| import { useML } from '@jetbrains/kotlin-web-site-ui/out/components/breakpoints-v2'; | ||
|
|
||
| import android from './icons/android.svg'; | ||
| import ios from './icons/ios.svg'; | ||
| import web from './icons/web.svg'; | ||
| import desktop from './icons/desktop.svg'; | ||
| import server from './icons/server.svg'; | ||
|
|
||
| import logo from './logo.svg'; | ||
|
|
||
| import styles from './hero.module.css'; | ||
|
|
||
| const platforms = [ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JIC: We have some platform types declared in the case studies module here. Probably it's worth extracting it to some common place (or maybe not) Anyway, there is a difference in names for platforms on different pages (frontend + backend on case studies, web + server on this kmp landing) and there is still a discussion what options are better. |
||
| { title: 'Android', icon: android }, | ||
| { title: 'iOS', icon: ios }, | ||
| { title: 'Web', icon: web }, | ||
| { title: 'Desktop', icon: desktop }, | ||
| { title: 'Server', icon: server } | ||
| ] as const; | ||
|
|
||
| export function HeroBanner({ url }: { url: string }) { | ||
| const isML = useML(); | ||
| const textCn = useTextStyles(); | ||
|
|
||
| return ( | ||
| <div className={styles.wrapper}> | ||
| <div className={cn(styles.hero, 'ktl-layout', 'ktl-layout--center')} | ||
| style={{ '--hero-logo-image': `url(${logo.src})` }}> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't get why you prefer using a background image instead of the img tag. Not a major thing at all, just seems more complicated then a image tag.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is a ts error also, something like could fix it declare module 'react' {
interface CSSProperties {
[key: `--${string}`]: string | number;
}
}
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If your question is about the custom property - it's simply a technique to keep images colocated with the component. If this is a broader question about images in HTML vs CSS, here's my reasoning: Content vs Decorative graphics
This practice stems from accessibility techniques. The core idea is distinguishing between two types of images: content images and decorative graphics.
My own baseline rule: if an image must remain accessible without CSS - use the |
||
| <h1 className={cn(styles.title, textCn('rs-hero'))}>Kotlin Multiplatform</h1> | ||
| <p className={cn(styles.subtitle, textCn('rs-subtitle-1'))}> | ||
| Go cross‑platform without compromising performance, UX, or code quality | ||
| </p> | ||
| <ul className={styles.platforms}> | ||
| {platforms.map(({ title, icon }) => ( | ||
| <li | ||
| key={title.toLowerCase()} | ||
| className={cn(styles.platform, textCn(isML ? 'rs-h5' : 'rs-h4'))} | ||
| style={{ '--hero-item-src': `url(${icon.src})` }} | ||
| > | ||
| {title} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| <Button className={cn(styles.button)} mode={'rock'} href={url} size={isML ? 'm' : 'l'}>Get | ||
| Started</Button> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,26 @@ | ||
| import { Button } from '@rescui/button'; | ||
| import { LandingLayout, LandingLayoutProps } from '../../components/landing-layout/landing-layout'; | ||
| import { ThemeProvider } from '@rescui/ui-contexts'; | ||
|
|
||
| import { | ||
| MULTIPLATFORM_MOBILE_TITLE, | ||
| MULTIPLATFORM_MOBILE_URL | ||
| } from '@jetbrains/kotlin-web-site-ui/out/components/header'; | ||
| import { LandingLayout, LandingLayoutProps } from '../../components/landing-layout/landing-layout'; | ||
|
|
||
| import styles from './multiplatform.module.css'; | ||
| import { FaqBlock } from '../../blocks/multiplatform/faq-block/faq-block'; | ||
| import { HeroBanner } from '../../blocks/multiplatform/hero'; | ||
|
|
||
| const MULTIPLATFORM_MOBILE_TITLE = 'Kotlin Multiplatform' as const; | ||
| const MULTIPLATFORM_MOBILE_URL = '/multiplatform/' as const; | ||
|
|
||
| const TOP_MENU_ITEMS: LandingLayoutProps['topMenuItems'] = [ | ||
| { | ||
| title: 'Compose Multiplatform', | ||
| url: 'https://www.jetbrains.com/compose-multiplatform/' | ||
| }, | ||
| { | ||
| title: 'Docs', | ||
| url: 'https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html' | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :) |
||
| } | ||
| ]; | ||
|
|
||
| const TOP_MENU_ITEMS: LandingLayoutProps['topMenuItems'] = []; | ||
| const GET_STARTED_URL = '/docs/multiplatform/get-started.html' as const; | ||
|
|
||
| export default function MultiplatformLanding() { | ||
| return ( | ||
|
|
@@ -23,11 +34,14 @@ export default function MultiplatformLanding() { | |
| topMenuTitle={MULTIPLATFORM_MOBILE_TITLE} | ||
| topMenuHomeUrl={MULTIPLATFORM_MOBILE_URL} | ||
| topMenuItems={TOP_MENU_ITEMS} | ||
| topMenuButton={<Button href={'#get-started'}>Get started</Button>} | ||
| topMenuButton={<Button href={GET_STARTED_URL}>Get started</Button>} | ||
| canonical={'https://kotlinlang.org/multiplatform/'} | ||
| > | ||
| <div className={styles.page}> | ||
| <FaqBlock /> | ||
| <div className="ktl-layout-to-2"> | ||
| <ThemeProvider theme={'dark'}> | ||
| <HeroBanner url={GET_STARTED_URL} /> | ||
| <FaqBlock /> | ||
| </ThemeProvider> | ||
| </div> | ||
| </LandingLayout> | ||
| ); | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better when icons and other resources in the same folder with component, but i can't find a normal way for nextjs. Ask for help
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the images should be in public directory, this seems to be a kind of contract in Next.JS: https://nextjs.org/docs/app/api-reference/file-conventions/public-folder.
Regarding the inlining of the SVGs, I'd prefer to see them as paths to files instead of base64 (to reduce size of the page via caching). As I see, it's something related to webpack configuration: maybe it's downside of the optimizedImages task, maybe we just need to configure "asset/resource" configuration for SVG files. Not sure we can fix it right away, without breaking all SVG imports.
@krutilov, ,maybe you know what we can do?