mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-31 21:01:33 +02:00
[web] Create an initial implementation for the CIAM page layout (#29373)
* Add a Storybook Layout page compiling all the "small pages" layouts * Add a CIAM page layout to Storybook and create an initial Layout * Use rem in font mixins * Add a `--ciam-` prefix to the new CSS variables * Fix linting GitOrigin-RevId: 7a89fd1531c87597a918a9170d174cce556d77c4
This commit is contained in:
297
services/web/frontend/stories/page-layouts.stories.tsx
Normal file
297
services/web/frontend/stories/page-layouts.stories.tsx
Normal file
@@ -0,0 +1,297 @@
|
||||
import _ from 'lodash'
|
||||
import { ComponentType } from 'react'
|
||||
import { Navbar } from 'react-bootstrap'
|
||||
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
|
||||
import OLRow from '@/shared/components/ol/ol-row'
|
||||
import OLCol from '@/shared/components/ol/ol-col'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
|
||||
|
||||
const lorem = (n: number) => {
|
||||
const quacks = ['quack', 'quack', 'quack', 'quak']
|
||||
let result = ''
|
||||
if (n >= 1) result += 'Lorem'
|
||||
if (n >= 2) result += ' epsom'
|
||||
for (let i = 2; i < n; i++) {
|
||||
const next =
|
||||
result.at(-1) === '.'
|
||||
? ' ' + _.capitalize(quacks[Math.floor(Math.random() * quacks.length)])
|
||||
: quacks[Math.floor(Math.random() * (quacks.length + 1))]
|
||||
result += next ? ' ' + next : '.'
|
||||
}
|
||||
if (result.at(-1) !== '.') result += '.'
|
||||
return result
|
||||
}
|
||||
|
||||
const Nav = () => <Navbar className="navbar-default navbar-main" />
|
||||
|
||||
export const UnsuportedBrowser = () => (
|
||||
<main className="content content-alt full-height" id="main-content">
|
||||
<div className="container full-height">
|
||||
<div className="error-container full-height">
|
||||
<div className="error-details">
|
||||
<h1 className="error-status">Unsupported Browser</h1>
|
||||
<p className="error-description">{lorem(60)}</p>
|
||||
<hr />
|
||||
<p>{lorem(40)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
|
||||
export const Error400 = () => (
|
||||
<main className="content content-alt full-height" id="main-content">
|
||||
<div className="container full-height">
|
||||
<div className="error-container full-height">
|
||||
<div className="error-details">
|
||||
<p className="error-status">Something went wrong, sorry.</p>
|
||||
<p className="error-description">{lorem(15)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
|
||||
export const Error404 = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content content-alt" id="main-content">
|
||||
<div className="container">
|
||||
<div className="error-container">
|
||||
<div className="error-details">
|
||||
<p className="error-status">Not found</p>
|
||||
<p className="error-description">{lorem(20)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const Closed = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-lg-8 col-lg-offset-2 text-center">
|
||||
<div className="page-header">
|
||||
<h1>Maintenance</h1>
|
||||
</div>
|
||||
<p>{lorem(6)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const PlannedMaintenance = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-lg-8 col-lg-offset-2">
|
||||
<div className="page-header">
|
||||
<h1>Planned Maintenance</h1>
|
||||
</div>
|
||||
<p>{lorem(6)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const PostGateway = () => (
|
||||
<>
|
||||
<div className="content content-alt">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-lg-6 offset-lg-3">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<p className="text-center">
|
||||
Please wait while we process your request.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
export const AccountSuspended = () => (
|
||||
<main className="content content-alt" id="main-content">
|
||||
<div className="container-custom-sm mx-auto">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h3>Your account is suspended</h3>
|
||||
<p>{lorem(6)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
|
||||
export const Restricted = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-8 offset-md-2 text-center">
|
||||
<div className="page-header">
|
||||
<h2>
|
||||
Restricted, sorry you don’t have permission to load this page.
|
||||
</h2>
|
||||
</div>
|
||||
<p>{lorem(23)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const OneTimeLogin = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content content-alt" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-lg-6 offset-lg-3 col-xl-4 offset-xl-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="page-header">
|
||||
<h1>We're back!</h1>
|
||||
</div>
|
||||
<p>Overleaf is now running normally.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const Invite = () => (
|
||||
<main className="content content-alt" id="invite-root">
|
||||
<OLRow className="row row-spaced">
|
||||
<OLCol lg={{ span: 8, offset: 2 }}>
|
||||
<OLPageContentCard>
|
||||
<div className="page-header">
|
||||
<h1 className="text-center">
|
||||
<span className="team-invite-name">
|
||||
max.mustermann@example.com
|
||||
</span>{' '}
|
||||
has invited you to join a group subscription on Overleaf
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-center">{lorem(20)}</p>
|
||||
</OLPageContentCard>
|
||||
</OLCol>
|
||||
</OLRow>
|
||||
</main>
|
||||
)
|
||||
|
||||
export const NotValid = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content content-alt" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2 offset-md-2">
|
||||
<div className="card project-invite-invalid">
|
||||
<div className="card-body">
|
||||
<div className="page-header text-center">
|
||||
<h1>Invite not valid</h1>
|
||||
</div>
|
||||
<div className="row text-center">
|
||||
<div className="col-12 col-md-12">
|
||||
<p>{lorem(20)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const CompleteRegistration = () => (
|
||||
<>
|
||||
<Nav />
|
||||
<main className="content content-alt" id="main-content">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2 offset-md-1 offset-lg-2">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<div className="page-header">
|
||||
<h1 className="text-center">Dropbox Sync</h1>
|
||||
</div>
|
||||
<p>{lorem(20)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
|
||||
export const Ciam = () => (
|
||||
<div className="ciam-layout">
|
||||
<a
|
||||
href="/"
|
||||
aria-label="Overleaf"
|
||||
className="brand"
|
||||
style={{ backgroundImage: `url("${overleafLogo}")` }}
|
||||
/>
|
||||
<div className="ciam-container">
|
||||
<main className="ciam-card" id="main-content">
|
||||
<h1>Create your Overleaf account</h1>
|
||||
<p>{lorem(20)}</p>
|
||||
<hr />
|
||||
<p>{lorem(20)}</p>
|
||||
<OLButton>Button</OLButton>
|
||||
</main>
|
||||
</div>
|
||||
<footer>
|
||||
<a href="https://www.overleaf.com/legal#Privacy">Privacy</a>
|
||||
<a href="https://www.overleaf.com/legal#Terms">Terms</a>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default {
|
||||
title: 'Shared / Layouts',
|
||||
args: {
|
||||
label: 'Option',
|
||||
},
|
||||
|
||||
parameters: {
|
||||
layout: 'fullscreen', // This is crucial for vh/vw layouts
|
||||
},
|
||||
decorators: [
|
||||
(Story: ComponentType) => (
|
||||
<div style={{ height: '100vh', width: '100vw' }}>
|
||||
<style>
|
||||
{`.content {
|
||||
min-height: 100vh;
|
||||
padding-top: 93px;
|
||||
}`}
|
||||
</style>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@import 'account-settings';
|
||||
@import 'ciam';
|
||||
@import 'cms';
|
||||
@import 'content';
|
||||
@import 'project-list';
|
||||
|
||||
68
services/web/frontend/stylesheets/pages/ciam-colors.scss
Normal file
68
services/web/frontend/stylesheets/pages/ciam-colors.scss
Normal file
@@ -0,0 +1,68 @@
|
||||
.ciam-layout {
|
||||
--ciam-color-neutral-50: #fafafa;
|
||||
--ciam-color-neutral-100: #f2f2f2;
|
||||
--ciam-color-neutral-200: #e6e6e6;
|
||||
--ciam-color-neutral-300: #d6d6d6;
|
||||
--ciam-color-neutral-400: #c7c7c7;
|
||||
--ciam-color-neutral-500: #b5b5b5;
|
||||
--ciam-color-neutral-600: #a1a1a1;
|
||||
--ciam-color-neutral-700: #8a8a8a;
|
||||
--ciam-color-neutral-800: #6b6b6b;
|
||||
--ciam-color-neutral-900: #383838;
|
||||
--ciam-color-neutral-950: #262626;
|
||||
--ciam-color-green-50: #f2f8f5;
|
||||
--ciam-color-green-100: #e3f2eb;
|
||||
--ciam-color-green-200: #c0e7d6;
|
||||
--ciam-color-green-300: #8adbb7;
|
||||
--ciam-color-green-400: #38cc89;
|
||||
--ciam-color-green-500: #26b072;
|
||||
--ciam-color-green-600: #158954;
|
||||
--ciam-color-green-700: #19754c;
|
||||
--ciam-color-green-800: #196241;
|
||||
--ciam-color-green-900: #164630;
|
||||
--ciam-color-green-950: #112c20;
|
||||
--ciam-color-yellow-50: #fffaeb;
|
||||
--ciam-color-yellow-100: #fff7db;
|
||||
--ciam-color-yellow-200: #ffeeb8;
|
||||
--ciam-color-yellow-300: #ffe58f;
|
||||
--ciam-color-yellow-400: #ffda61;
|
||||
--ciam-color-yellow-500: #ffcc20;
|
||||
--ciam-color-yellow-600: #f0b800;
|
||||
--ciam-color-yellow-700: #d1a000;
|
||||
--ciam-color-yellow-800: #ad8500;
|
||||
--ciam-color-yellow-900: #806200;
|
||||
--ciam-color-yellow-950: #574200;
|
||||
--ciam-color-red-50: #fff5f7;
|
||||
--ciam-color-red-100: #fee7eb;
|
||||
--ciam-color-red-200: #fdc9d3;
|
||||
--ciam-color-red-300: #fba7b7;
|
||||
--ciam-color-red-400: #f97b92;
|
||||
--ciam-color-red-500: #f51d43;
|
||||
--ciam-color-red-600: #e60a32;
|
||||
--ciam-color-red-700: #c3092b;
|
||||
--ciam-color-red-800: #a10723;
|
||||
--ciam-color-red-900: #75051a;
|
||||
--ciam-color-red-950: #530412;
|
||||
--ciam-color-blue-50: #f7fafd;
|
||||
--ciam-color-blue-100: #ecf2f9;
|
||||
--ciam-color-blue-200: #d4e3f2;
|
||||
--ciam-color-blue-300: #bdd4ea;
|
||||
--ciam-color-blue-400: #a2c3e2;
|
||||
--ciam-color-blue-500: #7facd7;
|
||||
--ciam-color-blue-600: #5893cb;
|
||||
--ciam-color-blue-700: #3470a8;
|
||||
--ciam-color-blue-800: #2b5d8c;
|
||||
--ciam-color-blue-900: #1e4161;
|
||||
--ciam-color-blue-950: #17314a;
|
||||
--ciam-color-teal-50: #f1f8f8;
|
||||
--ciam-color-teal-100: #e3f2f1;
|
||||
--ciam-color-teal-200: #c1e2df;
|
||||
--ciam-color-teal-300: #9ed1cd;
|
||||
--ciam-color-teal-400: #6dbab4;
|
||||
--ciam-color-teal-500: #4a9d96;
|
||||
--ciam-color-teal-600: #438e88;
|
||||
--ciam-color-teal-700: #3b7d77;
|
||||
--ciam-color-teal-800: #2f6460;
|
||||
--ciam-color-teal-900: #244c49;
|
||||
--ciam-color-teal-950: #193432;
|
||||
}
|
||||
107
services/web/frontend/stylesheets/pages/ciam-mixins.scss
Normal file
107
services/web/frontend/stylesheets/pages/ciam-mixins.scss
Normal file
@@ -0,0 +1,107 @@
|
||||
@mixin ciam-body-xs-regular() {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-xs-semibold() {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-sm-regular() {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-sm-semibold() {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-md-regular() {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-md-semibold() {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-lg-regular() {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
@mixin ciam-body-lg-semibold() {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-xs-regular() {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-xs-semibold() {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-sm-regular() {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-sm-semibold() {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-md-regular() {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-md-semibold() {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-lg-regular() {
|
||||
font-size: 2rem;
|
||||
font-weight: 400;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-lg-semibold() {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-xl-regular() {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 400;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
@mixin ciam-heading-xl-semibold() {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
line-height: 3rem;
|
||||
}
|
||||
35
services/web/frontend/stylesheets/pages/ciam-variables.scss
Normal file
35
services/web/frontend/stylesheets/pages/ciam-variables.scss
Normal file
@@ -0,0 +1,35 @@
|
||||
@import 'ciam-mixins';
|
||||
@import 'ciam-colors';
|
||||
|
||||
// TODO: Replace `fuchsia` by the correct colors.
|
||||
|
||||
.ciam-layout {
|
||||
// Spacings
|
||||
--ciam-spacing-200: 8px;
|
||||
--ciam-spacing-250: 10px;
|
||||
--ciam-spacing-350: 12px;
|
||||
--ciam-spacing-400: 16px;
|
||||
--ciam-spacing-600: 24px; // TODO: confirm this variable name (couldn't find in design system)
|
||||
--ciam-spacing-800: 32px; // TODO: confirm this variable name (couldn't find in design system)
|
||||
--ciam-spacing-1300: 52px;
|
||||
|
||||
// Base variables
|
||||
--ciam-color-text-secondary: var(--ciam-color-neutral-800);
|
||||
--ciam-color-text-primary: var(--ciam-color-neutral-900);
|
||||
--ciam-border-radius-200: var(--ciam-spacing-300);
|
||||
--ciam-border-radius-400: var(--ciam-spacing-400);
|
||||
--ciam-font-family-sans: 'Inter', sans-serif;
|
||||
|
||||
// Links
|
||||
// used in services/web/frontend/stylesheets/base/links.scss
|
||||
--link-color: var(--ciam-color-text-secondary);
|
||||
--link-hover-color: fuchsia;
|
||||
|
||||
// TODO: validate that this is correct
|
||||
--link-visited-color: var(--ciam-color-text-secondary);
|
||||
--link-color-dark: fuchsia;
|
||||
--link-hover-color-dark: fuchsia;
|
||||
--link-visited-color-dark: fuchsia;
|
||||
--link-text-decoration: underline;
|
||||
--link-hover-text-decoration: none;
|
||||
}
|
||||
70
services/web/frontend/stylesheets/pages/ciam.scss
Normal file
70
services/web/frontend/stylesheets/pages/ciam.scss
Normal file
@@ -0,0 +1,70 @@
|
||||
@import 'ciam-variables';
|
||||
@import 'ciam-mixins';
|
||||
|
||||
.ciam-layout {
|
||||
padding: var(--ciam-spacing-350);
|
||||
display: flex;
|
||||
min-height: 100%;
|
||||
flex-direction: column;
|
||||
font-family: var(--ciam-font-family-sans), sans-serif;
|
||||
color: var(--ciam-color-text-primary);
|
||||
font-size: var(--ciam-font-size-400);
|
||||
line-height: 1.5;
|
||||
|
||||
@include ciam-body-md-regular;
|
||||
|
||||
.ciam-container {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.brand {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: contain;
|
||||
height: 64px;
|
||||
width: 130px;
|
||||
margin: var(--ciam-spacing-350) auto;
|
||||
display: block;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin: var(--ciam-spacing-350) var(--ciam-spacing-800);
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
@include ciam-heading-sm-semibold;
|
||||
}
|
||||
|
||||
.ciam-card {
|
||||
box-shadow:
|
||||
0 4px 6px -4px rgb(0 0 0 / 10%),
|
||||
0 1px 29px -3px rgb(0 0 0 / 16%);
|
||||
padding: var(--ciam-spacing-800) var(--ciam-spacing-400);
|
||||
border-radius: var(--ciam-border-radius-400);
|
||||
max-width: 460px;
|
||||
margin: var(--ciam-spacing-400) auto;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
padding: var(--ciam-spacing-1300);
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
gap: var(--ciam-spacing-600);
|
||||
text-transform: uppercase;
|
||||
justify-content: center;
|
||||
margin: var(--ciam-spacing-350) auto;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin: var(--ciam-spacing-350) var(--ciam-spacing-800);
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
|
||||
@include ciam-body-sm-regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user