Skip to content

Commit c921972

Browse files
committed
feat(Layout): add basic feature
1 parent 361fe1a commit c921972

File tree

10 files changed

+299
-0
lines changed

10 files changed

+299
-0
lines changed

demo/App.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ import {
102102
DemoGridOrder,
103103
DemoGridResponsive,
104104
} from './grid';
105+
import { DemoLayoutBasic } from './layout';
105106

106107
const Container: FC<PropsWithChildren<{ title: string }>> = ({
107108
title,
@@ -395,6 +396,11 @@ function App() {
395396
<DemoGridResponsive />
396397
</Wrapper>
397398
</Container>
399+
<Container title="Layout">
400+
<Wrapper title="Basic">
401+
<DemoLayoutBasic />
402+
</Wrapper>
403+
</Container>
398404
</div>
399405
);
400406
}

demo/layout/index.tsx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Grid, Layout, RawUITheme, useTheme } from '@/packages';
2+
import { CSSProperties } from 'react';
3+
4+
const headerStyle = (theme: RawUITheme): CSSProperties => ({
5+
display: 'flex',
6+
alignItems: 'center',
7+
justifyContent: 'center',
8+
height: '64px',
9+
color: theme.palette.accents6,
10+
backgroundColor: theme.palette.accents4,
11+
});
12+
13+
const contentStyle = (theme: RawUITheme): CSSProperties => ({
14+
display: 'flex',
15+
alignItems: 'center',
16+
justifyContent: 'center',
17+
minHeight: '120px',
18+
color: theme.palette.accents4,
19+
backgroundColor: theme.palette.accents6,
20+
});
21+
22+
const sidebarStyle = (theme: RawUITheme): CSSProperties => ({
23+
display: 'flex',
24+
alignItems: 'center',
25+
justifyContent: 'center',
26+
width: '25%',
27+
color: theme.palette.accents3,
28+
backgroundColor: theme.palette.accents5,
29+
});
30+
31+
const footerStyle = (theme: RawUITheme): CSSProperties => ({
32+
display: 'flex',
33+
alignItems: 'center',
34+
justifyContent: 'center',
35+
height: '64px',
36+
color: theme.palette.accents6,
37+
backgroundColor: theme.palette.accents4,
38+
});
39+
40+
export function DemoLayoutBasic() {
41+
const theme = useTheme();
42+
43+
return (
44+
<Grid gutter={[16, 16]}>
45+
<Grid.Col span={12}>
46+
<Layout>
47+
<Layout.Header style={headerStyle(theme)}>Header</Layout.Header>
48+
<Layout.Content style={contentStyle(theme)}>Content</Layout.Content>
49+
<Layout.Footer style={footerStyle(theme)}>Footer</Layout.Footer>
50+
</Layout>
51+
</Grid.Col>
52+
<Grid.Col span={12}>
53+
<Layout>
54+
<Layout.Header style={headerStyle(theme)}>Header</Layout.Header>
55+
<Layout>
56+
<Layout.Sidebar style={sidebarStyle(theme)}>Sidebar</Layout.Sidebar>
57+
<Layout.Content style={contentStyle(theme)}>Content</Layout.Content>
58+
</Layout>
59+
<Layout.Footer style={footerStyle(theme)}>Footer</Layout.Footer>
60+
</Layout>
61+
</Grid.Col>
62+
<Grid.Col span={12}>
63+
<Layout>
64+
<Layout.Header style={headerStyle(theme)}>Header</Layout.Header>
65+
<Layout>
66+
<Layout.Content style={contentStyle(theme)}>Content</Layout.Content>
67+
<Layout.Sidebar style={sidebarStyle(theme)}>Sidebar</Layout.Sidebar>
68+
</Layout>
69+
<Layout.Footer style={footerStyle(theme)}>Footer</Layout.Footer>
70+
</Layout>
71+
</Grid.Col>
72+
<Grid.Col span={12}>
73+
<Layout>
74+
<Layout.Sidebar style={sidebarStyle(theme)}>Sidebar</Layout.Sidebar>
75+
<Layout>
76+
<Layout.Header style={headerStyle(theme)}>Header</Layout.Header>
77+
<Layout.Content style={contentStyle(theme)}>Content</Layout.Content>
78+
<Layout.Footer style={footerStyle(theme)}>Footer</Layout.Footer>
79+
</Layout>
80+
</Layout>
81+
</Grid.Col>
82+
</Grid>
83+
);
84+
}

packages/Layout/Content.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { FC, PropsWithChildren } from 'react';
2+
import classNames from 'classnames';
3+
import { ContentProps } from './Layout.types';
4+
5+
const Content: FC<PropsWithChildren<ContentProps>> = ({
6+
className = '',
7+
children,
8+
...restProps
9+
}) => {
10+
const classes = classNames('raw-layout-content', className);
11+
12+
return (
13+
<main className={classes} {...restProps}>
14+
{children}
15+
<style jsx>{`
16+
.raw-layout-content {
17+
flex: auto;
18+
}
19+
`}</style>
20+
</main>
21+
);
22+
};
23+
24+
export default Content;

packages/Layout/Footer.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { FC, PropsWithChildren } from 'react';
2+
import classNames from 'classnames';
3+
import { FooterProps } from './Layout.types';
4+
5+
const Footer: FC<PropsWithChildren<FooterProps>> = ({
6+
className = '',
7+
children,
8+
...restProps
9+
}) => {
10+
const classes = classNames('raw-layout-footer', className);
11+
12+
return (
13+
<footer className={classes} {...restProps}>
14+
{children}
15+
<style jsx>{`
16+
.raw-layout-footer {
17+
flex: 0 0 auto;
18+
}
19+
`}</style>
20+
</footer>
21+
);
22+
};
23+
24+
export default Footer;

packages/Layout/Header.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { FC, PropsWithChildren } from 'react';
2+
import classNames from 'classnames';
3+
import { HeaderProps } from './Layout.types';
4+
5+
const Header: FC<PropsWithChildren<HeaderProps>> = ({
6+
className = '',
7+
children,
8+
...restProps
9+
}) => {
10+
const classes = classNames('raw-layout-header', className);
11+
12+
return (
13+
<header className={classes} {...restProps}>
14+
{children}
15+
<style jsx>{`
16+
.raw-layout-header {
17+
flex: 0 0 auto;
18+
}
19+
`}</style>
20+
</header>
21+
);
22+
};
23+
24+
export default Header;

packages/Layout/Layout.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { FC, PropsWithChildren } from 'react';
2+
import classNames from 'classnames';
3+
import { LayoutProps } from './Layout.types';
4+
import { getValidChildren } from '../utils/common';
5+
import Sidebar from './Sidebar';
6+
7+
const Layout: FC<PropsWithChildren<LayoutProps>> = ({
8+
className = '',
9+
children,
10+
...restProps
11+
}) => {
12+
const hasSidebar = getValidChildren(children).some(
13+
(child) => child.type === Sidebar
14+
);
15+
const classes = classNames(
16+
'raw-layout',
17+
hasSidebar && 'raw-layout-has-sidebar',
18+
className
19+
);
20+
21+
return (
22+
<div className={classes} {...restProps}>
23+
{children}
24+
<style jsx>{`
25+
.raw-layout {
26+
display: flex;
27+
flex: auto;
28+
flex-direction: column;
29+
}
30+
.raw-layout-has-sidebar {
31+
flex-direction: row;
32+
}
33+
`}</style>
34+
</div>
35+
);
36+
};
37+
38+
export default Layout;

packages/Layout/Layout.types.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { HTMLAttributes } from 'react';
2+
3+
interface BaseLayoutProps {
4+
className?: string;
5+
}
6+
7+
interface BaseHeaderProps {
8+
className?: string;
9+
}
10+
11+
interface BaseContentProps {
12+
className?: string;
13+
}
14+
15+
interface BaseFooterProps {
16+
className?: string;
17+
}
18+
19+
interface BaseSidebarProps {
20+
className?: string;
21+
}
22+
23+
type NativeLayoutProps = Omit<
24+
HTMLAttributes<HTMLDivElement>,
25+
keyof BaseLayoutProps
26+
>;
27+
28+
type NativeHeaderProps = Omit<
29+
HTMLAttributes<HTMLElement>,
30+
keyof BaseHeaderProps
31+
>;
32+
33+
type NativeContentProps = Omit<
34+
HTMLAttributes<HTMLElement>,
35+
keyof BaseContentProps
36+
>;
37+
38+
type NativeFooterProps = Omit<
39+
HTMLAttributes<HTMLElement>,
40+
keyof BaseFooterProps
41+
>;
42+
43+
type NativeSidebarProps = Omit<
44+
HTMLAttributes<HTMLElement>,
45+
keyof BaseSidebarProps
46+
>;
47+
48+
export type LayoutProps = BaseLayoutProps & NativeLayoutProps;
49+
export type HeaderProps = BaseHeaderProps & NativeHeaderProps;
50+
export type ContentProps = BaseContentProps & NativeContentProps;
51+
export type FooterProps = BaseFooterProps & NativeFooterProps;
52+
export type SidebarProps = BaseSidebarProps & NativeSidebarProps;

packages/Layout/Sidebar.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { FC, PropsWithChildren } from 'react';
2+
import classNames from 'classnames';
3+
import { SidebarProps } from './Layout.types';
4+
5+
const Sidebar: FC<PropsWithChildren<SidebarProps>> = ({
6+
className = '',
7+
children,
8+
...restProps
9+
}) => {
10+
const classes = classNames('raw-layout-sidebar', className);
11+
12+
return (
13+
<aside className={classes} {...restProps}>
14+
{children}
15+
<style jsx>{`
16+
.raw-layout-sidebar {
17+
position: relative;
18+
transition: all 0.2s;
19+
}
20+
`}</style>
21+
</aside>
22+
);
23+
};
24+
25+
export default Sidebar;

packages/Layout/index.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Layout from './Layout';
2+
import Header from './Header';
3+
import Content from './Content';
4+
import Sidebar from './Sidebar';
5+
import Footer from './Footer';
6+
7+
export type LayoutComponentType = typeof Layout & {
8+
Header: typeof Header;
9+
Content: typeof Content;
10+
Sidebar: typeof Sidebar;
11+
Footer: typeof Footer;
12+
};
13+
14+
(Layout as LayoutComponentType).Header = Header;
15+
(Layout as LayoutComponentType).Content = Content;
16+
(Layout as LayoutComponentType).Sidebar = Sidebar;
17+
(Layout as LayoutComponentType).Footer = Footer;
18+
19+
export default Layout as LayoutComponentType;

packages/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ export * from './Tabs/Tabs.types';
4848

4949
export { default as Grid } from './Grid';
5050
export * from './Grid/Grid.types';
51+
52+
export { default as Layout } from './Layout';
53+
export * from './Layout/Layout.types';

0 commit comments

Comments
 (0)