Skip to content

Commit b511f0f

Browse files
committed
[add] Jumbotron Example page
[refactor] GitHub Repository data API
1 parent b4fb552 commit b511f0f

File tree

9 files changed

+166
-54
lines changed

9 files changed

+166
-54
lines changed

document/source/components/FormField.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,12 +722,10 @@ While these feedback styles cannot be styled with CSS, you can still customize t
722722
<ToggleField className="mb-3" type="checkbox" required>
723723
Agree to terms and conditions
724724
</ToggleField>
725-
726725
<Button type="submit" color="primary">
727726
Submit form
728727
</Button>
729728
</form>
730-
731729
</Example>
732730

733731
```TSX

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@types/classnames": "^2.2.11",
2626
"@types/lodash.groupby": "^4.6.6",
2727
"autoprefixer": "^9.8.6",
28-
"husky": "^4.3.5",
28+
"husky": "^4.3.6",
2929
"less": "^3.13.0",
3030
"lint-staged": "^10.5.3",
3131
"mark-cell": "^0.4.5",

source/component/DocumentBox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class DocumentBox extends mixin<DocumentBoxProps>() {
7171
<main className="col-12 col-sm-9 col-md-10 p-4 border-left">
7272
<h1 className="d-flex justify-content-between align-items-center">
7373
{header}
74-
<Button size="sm" href={API}>
74+
<Button color="primary" size="sm" href={API}>
7575
API
7676
</Button>
7777
</h1>

source/model/Repository.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { observable } from 'mobx';
2+
import { components } from '@octokit/openapi-types';
3+
4+
import { github } from './service';
5+
6+
export type Repository = components['schemas']['minimal-repository'];
7+
8+
export class RepositoryModel {
9+
@observable
10+
loading = false;
11+
12+
@observable
13+
list: Repository[] = [];
14+
15+
async getList() {
16+
this.loading = true;
17+
18+
const { body } = await github.get<Repository[]>(
19+
'orgs/EasyWebApp/repos'
20+
);
21+
this.list = body.sort(({ updated_at: A }, { updated_at: B }) =>
22+
B.localeCompare(A)
23+
);
24+
this.loading = false;
25+
26+
return this.list;
27+
}
28+
}
29+
30+
export default new RepositoryModel();

source/model/index.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
import { History } from 'cell-router/source';
2-
import { HTTPClient } from 'koajax';
3-
import { components } from '@octokit/openapi-types';
42

53
import { MetaModel } from './Meta';
64

75
export const history = new History();
8-
96
export const meta = new MetaModel();
10-
11-
export const github = new HTTPClient({
12-
baseURI: 'https://api.github.com/',
13-
responseType: 'json'
14-
});
15-
16-
export type Repository = components['schemas']['minimal-repository'];

source/model/service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { HTTPClient } from 'koajax';
2+
3+
export const github = new HTTPClient({
4+
baseURI: 'https://api.github.com/',
5+
responseType: 'json'
6+
});

source/page/Example/Carousel/index.tsx

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,52 @@
11
import { component, mixin, createCell, Fragment } from 'web-cell';
2+
import { observer } from 'mobx-web-cell';
23
import classNames from 'classnames';
34

45
import { NavBar } from 'boot-cell/source/Navigator/NavBar';
56
import { Form } from 'boot-cell/source/Form/Form';
67
import { Field } from 'boot-cell/source/Form/Field';
78
import { Button } from 'boot-cell/source/Form/Button';
89
import { CarouselView, CarouselItem } from 'boot-cell/source/Media/Carousel';
10+
import { SpinnerBox } from 'boot-cell/source/Prompt/Spinner';
911

1012
import { Feature } from './Feature';
1113
import style from './index.less';
1214

13-
import { Repository, github } from '../../../model';
1415
import { headers, banners, features } from './data';
16+
import repository, { Repository } from '../../../model/Repository';
1517

16-
interface CarouselPageState {
17-
projects: Repository[];
18-
}
19-
18+
@observer
2019
@component({
2120
tagName: 'carousel-page',
2221
renderTarget: 'children'
2322
})
24-
export class CarouselPage extends mixin<{}, CarouselPageState>() {
25-
state = {
26-
projects: [] as Repository[]
27-
};
23+
export class CarouselPage extends mixin() {
24+
connectedCallback() {
25+
repository.getList();
2826

29-
async connectedCallback() {
3027
super.connectedCallback();
28+
}
3129

32-
const { body } = await github.get<Repository[]>(
33-
'orgs/EasyWebApp/repos'
34-
);
30+
renderItem = ({ name, description, html_url }: Repository) => (
31+
<div className="col-lg-4 mb-4">
32+
<img
33+
className="rounded-circle"
34+
style={{ width: '8.75rem' }}
35+
src="https://web-cell.dev/WebCell-0.f1ffd28b.png"
36+
/>
37+
<h2 style={{ fontWeight: '400' }}>{name}</h2>
38+
<p>{description}</p>
39+
<p>
40+
<Button color="secondary" href={html_url}>
41+
View details »
42+
</Button>
43+
</p>
44+
</div>
45+
);
3546

36-
await this.setState({
37-
projects: body
38-
.sort(({ updated_at: A }, { updated_at: B }) =>
39-
B.localeCompare(A)
40-
)
41-
.slice(0, 3)
42-
});
43-
}
47+
render() {
48+
const { loading, list } = repository;
4449

45-
render(_, { projects }: CarouselPageState) {
4650
return (
4751
<>
4852
<NavBar brand="Carousel" menu={headers}>
@@ -71,24 +75,9 @@ export class CarouselPage extends mixin<{}, CarouselPageState>() {
7175
</CarouselView>
7276

7377
<div className={classNames('container', style.marketing)}>
74-
<div className="row text-center">
75-
{projects.map(({ name, description, html_url }) => (
76-
<div className="col-lg-4 mb-4">
77-
<img
78-
className="rounded-circle"
79-
style={{ width: '8.75rem' }}
80-
src="https://web-cell.dev/WebCell-0.f1ffd28b.png"
81-
/>
82-
<h2 style={{ fontWeight: '400' }}>{name}</h2>
83-
<p>{description}</p>
84-
<p>
85-
<Button color="secondary" href={html_url}>
86-
View details »
87-
</Button>
88-
</p>
89-
</div>
90-
))}
91-
</div>
78+
<SpinnerBox className="row text-center" cover={loading}>
79+
{list.slice(0, 3).map(this.renderItem)}
80+
</SpinnerBox>
9281
<hr className={style['featurette-divider']} />
9382

9483
{features.map((item, index) => (

source/page/Example/Jumbotron.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { component, mixin, createCell, Fragment } from 'web-cell';
2+
import { observer } from 'mobx-web-cell';
3+
import { NavBar } from 'boot-cell/source/Navigator/NavBar';
4+
import { NavLink } from 'boot-cell/source/Navigator/Nav';
5+
import { DropMenuItem } from 'boot-cell/source/Navigator/DropMenu';
6+
import { Form } from 'boot-cell/source/Form/Form';
7+
import { Field } from 'boot-cell/source/Form/Field';
8+
import { Button } from 'boot-cell/source/Form/Button';
9+
import { Jumbotron } from 'boot-cell/source/Content/Jumbotron';
10+
import { SpinnerBox } from 'boot-cell/source/Prompt/Spinner';
11+
12+
import repository, { Repository } from '../../model/Repository';
13+
14+
@observer
15+
@component({
16+
tagName: 'jumbotron-page',
17+
renderTarget: 'children'
18+
})
19+
export class JumbotronPage extends mixin() {
20+
connectedCallback() {
21+
repository.getList();
22+
23+
super.connectedCallback();
24+
}
25+
26+
renderItem = ({ name, description, html_url }: Repository) => (
27+
<div className="col-md-4">
28+
<h2>{name}</h2>
29+
<p>{description}</p>
30+
<p>
31+
<Button color="secondary" href={html_url}>
32+
View details »
33+
</Button>
34+
</p>
35+
</div>
36+
);
37+
38+
render() {
39+
const { loading, list } = repository;
40+
41+
return (
42+
<>
43+
<NavBar expand="lg" brand="NavBar">
44+
<NavLink href=".">Home</NavLink>
45+
<NavLink href="components/navbar">Link</NavLink>
46+
<NavLink href="#" disabled>
47+
Disabled
48+
</NavLink>
49+
<NavLink title="Dropdown">
50+
<DropMenuItem>Action</DropMenuItem>
51+
<DropMenuItem>Another action</DropMenuItem>
52+
<DropMenuItem />
53+
<DropMenuItem>Something else here</DropMenuItem>
54+
</NavLink>
55+
<Form inline className="my-2 my-lg-0">
56+
<Field
57+
type="search"
58+
className="mr-sm-2"
59+
placeholder="Search"
60+
aria-label="Search"
61+
/>
62+
<Button
63+
type="submit"
64+
color="success"
65+
outline
66+
className="my-2 my-sm-0"
67+
>
68+
Search
69+
</Button>
70+
</Form>
71+
</NavBar>
72+
73+
<Jumbotron
74+
fluid
75+
title="Hello, world!"
76+
description="This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique."
77+
>
78+
<Button color="primary" size="lg">
79+
Learn more »
80+
</Button>
81+
</Jumbotron>
82+
83+
<main className="container">
84+
<SpinnerBox className="row" cover={loading}>
85+
{list.slice(0, 3).map(this.renderItem)}
86+
</SpinnerBox>
87+
<hr />
88+
</main>
89+
<footer className="container">
90+
<p>© Company 2017-{new Date().getFullYear()}</p>
91+
</footer>
92+
</>
93+
);
94+
}
95+
}

source/page/Example/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export default [
2323
paths: ['example/carousel'],
2424
component: async () => (await import('./Carousel')).CarouselPage
2525
},
26+
{
27+
paths: ['example/jumbotron'],
28+
component: async () => (await import('./Jumbotron')).JumbotronPage
29+
},
2630
{
2731
paths: ['example/offcanvas'],
2832
component: async () => (await import('./Offcanvas')).OffcanvasPage

0 commit comments

Comments
 (0)