Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<img width="3315" height="951" alt="safe" src="https://github.com/user-attachments/assets/24613a26-95da-4777-870e-f5c53c82da2a" />
<img width="100%" alt="Simplifying layout management with React — maintained by App&Flow" src="./docs/static/img/github-banner.png" />

### About
App & Flow is a Montreal-based React Native engineering and consulting studio. We partner with the world’s top companies and are recommended by [Expo](https://expo.dev/consultants). Need a hand? Let’s build together. team@appandflow.com
Expand Down
Binary file added docs/static/img/github-banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
build/
.docusaurus/
.cache/
21 changes: 21 additions & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default {
title: 'React Native Safe Area Context',
tagline: 'Simplifying layout management with React Native Safe Area Context',
url: 'https://rrsac.appandflow.com',
baseUrl: '/',
onBrokenLinks: 'throw',
presets: [
['classic', {
docs: false,
blog: false,
theme: { customCss: './src/css/custom.css' },
}],
],
themeConfig: {
colorMode: {
defaultMode: 'light',
disableSwitch: true,
respectPrefersColorScheme: false,
},
},
};
13 changes: 13 additions & 0 deletions website/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "safe-area-context-website",
"private": true,
"scripts": { "start": "docusaurus start", "build": "docusaurus build", "serve": "docusaurus serve" },
"dependencies": {
"@docusaurus/core": "3.7.0",
"@docusaurus/preset-classic": "3.7.0",
"@mdx-js/react": "^3.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"engines": { "node": ">=18" }
}
17 changes: 17 additions & 0 deletions website/src/component/FeatureCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import styles from '../css/landing.module.css';
import Illustration from './Illustration';

export default function FeatureCard({ feature }) {
return (
<div className={styles.feature}>
<h2 className={styles.featureHeading}>
<a className={styles.featureLink} href={feature.href}>
<Illustration file={feature.icon} alt="" width={24} height={24} />
<span className={styles.linkLabel}>{feature.title}</span>
</a>
</h2>
<p className={styles.featureDescription}>{feature.description}</p>
</div>
);
}
20 changes: 20 additions & 0 deletions website/src/component/Footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import styles from '../css/landing.module.css';
import { github } from '../landing/content';

export default function Footer() {
return (
<footer className={styles.footer}>
<span>
Made by{' '}
<a className={styles.attributionLink} href="https://appandflow.com">
<span className={styles.linkLabel}>App&Flow</span>
</a>
</span>
<span aria-hidden="true">·</span>
<a className={styles.link} href={`${github}/blob/main/LICENSE`}>
<span className={styles.linkLabel}>licensed under the MIT License</span>
</a>
</footer>
);
}
14 changes: 14 additions & 0 deletions website/src/component/Hero.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import styles from '../css/landing.module.css';
import InstallCommand from './InstallCommand';

export default function Hero() {
return (
<header className={styles.hero}>
<h1 className={styles.title}>
Simplifying Layout Management with React Native Safe Area Context
</h1>
<InstallCommand />
</header>
);
}
15 changes: 15 additions & 0 deletions website/src/component/Illustration.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';

export default function Illustration({ file, mobileFile, ...imageProps }) {
const assets = useBaseUrl('/img/');
const image = <img {...imageProps} src={`${assets}${file}`} />;
return mobileFile ? (
<picture>
<source media="(max-width: 760px)" srcSet={`${assets}${mobileFile}`} />
{image}
</picture>
) : (
image
);
}
76 changes: 76 additions & 0 deletions website/src/component/InstallCommand.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useEffect, useRef, useState } from 'react';
import styles from '../css/landing.module.css';
import Illustration from './Illustration';
import { command, docs } from '../landing/content';

export default function InstallCommand() {
const [copyStatus, setCopyStatus] = useState('');
const copied = copyStatus === 'Copied!';
const resetTimer = useRef(null);
useEffect(() => () => clearTimeout(resetTimer.current), []);
async function copyCommand() {
clearTimeout(resetTimer.current);
try {
await navigator.clipboard.writeText(command);
setCopyStatus('Copied!');
resetTimer.current = setTimeout(() => setCopyStatus(''), 2000);
} catch {
setCopyStatus('Select the command to copy it manually.');
}
}
return (
<>
<div className={styles.actions}>
<a className={styles.getStarted} href={docs}>
<span>Get started</span>
</a>
<div className={styles.install}>
<code className={styles.command}>{command}</code>
<button
className={styles.copyButton}
type="button"
onClick={copyCommand}
aria-label={copied ? 'Copied' : 'Copy install command'}
title={copied ? 'Copied' : 'Copy'}
>
<span className={styles.copyIcons} aria-hidden="true">
<Illustration
className={styles.copyIcon}
file="copy.svg"
alt=""
width={12}
height={12}
style={{
opacity: copied ? 0 : 1,
transform: copied ? 'scale(0.33)' : 'scale(1)',
}}
/>
<svg
className={styles.copySuccess}
viewBox="0 0 24 24"
width={12}
height={12}
style={{
opacity: copied ? 1 : 0,
transform: copied ? 'scale(1)' : 'scale(0.33)',
transitionDelay: copied ? '75ms' : '0ms',
}}
>
<path
fill="currentColor"
d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"
/>
</svg>
</span>
</button>
</div>
</div>
<output className={styles.copyStatus} aria-live="polite">
{copied ? '' : copyStatus}
</output>
<output className={styles.screenReaderOnly} aria-live="polite">
{copied ? copyStatus : ''}
</output>
</>
);
}
46 changes: 46 additions & 0 deletions website/src/component/LandingLayout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import LayoutProvider from '@theme/Layout/Provider';
import SkipToContent from '@theme/SkipToContent';
import {
PageMetadata,
SkipToContentFallbackId,
} from '@docusaurus/theme-common';
import styles from '../css/landing.module.css';
import Navigation from './Navigation';
import Footer from './Footer';
import Illustration from './Illustration';

export default function LandingLayout({ children }) {
return (
<LayoutProvider>
<PageMetadata
title="React Native Safe Area Context"
description="Simplify safe area layouts on iOS, Android, and web."
/>
<SkipToContent />
<div className={styles.page}>
<a
className={styles.brandLink}
href="https://appandflow.com"
aria-label="App&Flow"
>
<Illustration
className={styles.brandImage}
file="brand.svg"
mobileFile="brand-mobile.svg"
alt=""
width={24}
height={24}
/>
</a>
<div className={styles.rail}>
<Navigation />
<main className={styles.main} id={SkipToContentFallbackId}>
{children}
</main>
<Footer />
</div>
</div>
</LayoutProvider>
);
}
30 changes: 30 additions & 0 deletions website/src/component/Navigation.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import styles from '../css/landing.module.css';
import Illustration from './Illustration';
import { docs, github } from '../landing/content';
import packageJson from '../../../package.json';

export default function Navigation() {
return (
<nav className={styles.navigation} aria-label="Main navigation">
<a className={[styles.packageName, styles.link].join(' ')} href={github}>
<span className={styles.linkLabel}>react-native-safe-area-context</span>
</a>
<a
className={styles.githubLink}
href={github}
aria-label={`GitHub repository, version ${packageJson.version}`}
>
<Illustration file="github.svg" alt="" width={16} height={16} />
<span>·</span>
<span className={styles.linkLabel}>v{packageJson.version}</span>
</a>
<a className={styles.link} href={docs}>
<span className={styles.linkLabel}>Documentation</span>
</a>
<a className={styles.link} href={`${docs}api/safe-area-provider`}>
<span className={styles.linkLabel}>API</span>
</a>
</nav>
);
}
115 changes: 115 additions & 0 deletions website/src/css/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
@font-face {
font-family: 'GT Maru';
src: url('../font/GT-Maru-Bold.ttf') format('truetype');
font-style: normal;
font-weight: 700;
font-display: swap;
}

@font-face {
font-family: 'Inter';
src: url('../font/InterVariable.woff2') format('woff2');
font-style: normal;
font-weight: 100 900;
font-display: swap;
}

@font-face {
font-family: 'JetBrains Mono';
src: url('../font/JetBrainsMono-Regular.woff2') format('woff2');
font-style: normal;
font-weight: 400;
font-display: swap;
}

:root {
--ifm-color-primary: #008cff;
--ifm-color-primary-dark: #007ee6;
--ifm-color-primary-darker: #0077d9;
--ifm-color-primary-darkest: #0062b3;
--ifm-color-primary-light: #1a98ff;
--ifm-color-primary-lighter: #26a0ff;
--ifm-color-primary-lightest: #4dafff;
--ifm-font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--ifm-heading-font-weight: 650;
--ifm-font-size-base: 16px;
--ifm-line-height-base: 1.7;
--ifm-code-font-size: 90%;
--ifm-background-color: #fff;
--ifm-font-color-base: #1c2942;
--ifm-heading-color: #12213b;
--ifm-navbar-shadow: none;
--ifm-global-radius: 8px;
--ifm-footer-background-color: #f6f8fc;
--rr-border: #e1e6ef;
--rr-muted: #59677f;
--rr-panel: #f6f8fc;
--rr-subtle: #edf1f8;
}

[data-theme='dark'] {
--ifm-color-primary: #008cff;
--ifm-color-primary-dark: #007ee6;
--ifm-color-primary-darker: #0077d9;
--ifm-color-primary-darkest: #0062b3;
--ifm-color-primary-light: #1a98ff;
--ifm-color-primary-lighter: #26a0ff;
--ifm-color-primary-lightest: #4dafff;
--ifm-background-color: #101725;
--ifm-background-surface-color: #161f30;
--ifm-navbar-background-color: #101725;
--ifm-font-color-base: #d8e1f2;
--ifm-heading-color: #f0f4fc;
--ifm-footer-background-color: #141d2d;
--rr-border: #2b3850;
--rr-muted: #aab8d0;
--rr-panel: #161f30;
--rr-subtle: #243149;
}

.navbar {
border-bottom: 1px solid var(--rr-border);
}
.navbar__title {
font-size: 1rem;
letter-spacing: -0.03em;
}
.navbar__logo {
height: 30px;
}
.footer {
border-top: 1px solid var(--rr-border);
}
.footer__copyright {
font-size: 0.85rem;
color: var(--rr-muted);
}
.markdown h1 {
letter-spacing: -0.045em;
}
.markdown h2 {
letter-spacing: -0.025em;
}
.markdown table {
font-size: 0.94rem;
}
.theme-doc-sidebar-item-link {
font-size: 0.92rem;
}
.button {
font-weight: 600;
}
.button--primary:not(.button--outline) {
color: #fff;
background: var(--ifm-color-primary);
border-color: var(--ifm-color-primary);
}
.button--primary:not(.button--outline):hover {
background: var(--ifm-color-primary-dark);
border-color: var(--ifm-color-primary-dark);
}
a:focus-visible,
button:focus-visible {
outline: 3px solid var(--ifm-color-primary);
outline-offset: 4px;
}
Loading
Loading