Skip to content

Commit

Permalink
Added footer component (#61)
Browse files Browse the repository at this point in the history
Co-authored-by: Samuel Colvin <s@muelcolvin.com>
  • Loading branch information
Dejiah and samuelcolvin authored Dec 28, 2023
1 parent 106d6c5 commit 85b48fc
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 38 deletions.
1 change: 1 addition & 0 deletions demo/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def api_index() -> list[AnyComponent]:
* `Link` — example [here](/components#link-list)
* `LinkList` — example [here](/components#link-list)
* `Navbar` — see the top of this page
* `Footer` — see the bottom of this page
* `Modal` — static example [here](/components#button-and-modal), dynamic content example [here](/components#dynamic-modal)
* `ServerLoad` — see [dynamic modal example](/components#dynamic-modal) and [SSE example](/components#server-load-sse)
* `Image` - example [here](/components#image)
Expand Down
10 changes: 10 additions & 0 deletions demo/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,14 @@ def demo_page(*components: AnyComponent, title: str | None = None) -> list[AnyCo
*components,
],
),
c.Footer(
extra_text='FastUI Demo',
links=[
c.Link(
components=[c.Text(text='Github')], on_click=GoToEvent(url='https://github.com/pydantic/FastUI')
),
c.Link(components=[c.Text(text='PyPI')], on_click=GoToEvent(url='https://pypi.org/project/fastui/')),
c.Link(components=[c.Text(text='NPM')], on_click=GoToEvent(url='https://www.npmjs.com/org/pydantic/')),
],
),
]
5 changes: 5 additions & 0 deletions demo/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def test_api_root():
],
'type': 'Page',
},
{
'extraText': 'FastUI Demo',
'links': IsList(length=3),
'type': 'Footer',
},
]


Expand Down
22 changes: 22 additions & 0 deletions src/npm-fastui-bootstrap/src/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC } from 'react'
import { components, models, useClassName } from 'fastui'

export const Footer: FC<models.Footer> = (props) => {
const links = props.links.map((link) => {
link.mode = link.mode || 'footer'
return link
})
const extraProp = useClassName(props, { el: 'extra' })
return (
<footer className={useClassName(props)}>
<ul className={useClassName(props, { el: 'link-list' })}>
{links.map((link, i) => (
<li key={i} className="nav-item">
<components.LinkComp {...link} />
</li>
))}
</ul>
{props.extraText && <div className={extraProp}>{props.extraText}</div>}
</footer>
)
}
17 changes: 15 additions & 2 deletions src/npm-fastui-bootstrap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import type { ClassNameGenerator, CustomRender, models } from 'fastui'
import { Modal } from './modal'
import { Navbar } from './navbar'
import { Pagination } from './pagination'
import { Footer } from './footer'

export const customRender: CustomRender = (props) => {
const { type } = props
switch (type) {
case 'Navbar':
return () => <Navbar {...props} />
case 'Footer':
return () => <Footer {...props} />
case 'Modal':
return () => <Modal {...props} />
case 'Pagination':
Expand All @@ -26,7 +29,7 @@ export const classNameGenerator: ClassNameGenerator = ({
const { type } = props
switch (type) {
case 'Page':
return 'container mt-80'
return 'container mt-80 mb-3 page'
case 'Button':
return 'btn btn-primary'
case 'Table':
Expand Down Expand Up @@ -104,10 +107,20 @@ export const classNameGenerator: ClassNameGenerator = ({
default:
return 'border-bottom fixed-top bg-body'
}
case 'Footer':
switch (subElement) {
case 'link-list':
return 'nav justify-content-center pb-1'
case 'extra':
return 'text-center text-muted pb-3'
default:
return 'border-top pt-1 mt-auto bg-body'
}
case 'Link':
return {
active: pathMatch(props.active, fullPath),
'nav-link': props.mode === 'navbar' || props.mode === 'tabs',
'nav-link': props.mode === 'navbar' || props.mode === 'tabs' || props.mode === 'footer',
'text-muted': props.mode === 'footer',
}
case 'LinkList':
if (subElement === 'link-list-item' && props.mode) {
Expand Down
22 changes: 10 additions & 12 deletions src/npm-fastui-prebuilt/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ import { FC, ReactNode } from 'react'

export default function App() {
return (
<div className="top-offset">
<FastUI
rootUrl="/api"
classNameGenerator={bootstrap.classNameGenerator}
customRender={customRender}
NotFound={NotFound}
Spinner={Spinner}
Transition={Transition}
/>
</div>
<FastUI
rootUrl="/api"
classNameGenerator={bootstrap.classNameGenerator}
customRender={customRender}
NotFound={NotFound}
Spinner={Spinner}
Transition={Transition}
/>
)
}

Expand All @@ -33,10 +31,10 @@ const Spinner = () => (
)

const Transition: FC<{ children: ReactNode; transitioning: boolean }> = ({ children, transitioning }) => (
<div>
<>
<div className={renderClassName({ 'transition-overlay': true, transitioning })} />
{children}
</div>
</>
)

const customRender: CustomRender = (props) => {
Expand Down
26 changes: 16 additions & 10 deletions src/npm-fastui-prebuilt/src/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ $link-color: #0d6efd; // bootstrap primary

@import 'bootstrap/scss/bootstrap';

html, body, #root {
height: 100%;
}

#root {
display: flex;
flex-direction: column;
}

.page {
// margin-top because the top is sticky
margin-top: 70px;
}

:root {
--bs-font-sans-serif: 'IBM Plex Sans', sans-serif;
--bs-code-color: rgb(31, 35, 40);
Expand All @@ -19,16 +33,8 @@ body {
backdrop-filter: blur(8px);
}

.top-offset {
margin-top: 70px;
h1,
h2,
h3,
h4,
h5,
h6 {
scroll-margin-top: 60px;
}
h1, h2, h3, h4, h5, h6 {
scroll-margin-top: 60px;
}

.transition-overlay {
Expand Down
21 changes: 21 additions & 0 deletions src/npm-fastui/src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Footer } from '../models'

import { useClassName } from '../hooks/className'

import { LinkComp } from './link'

export const FooterComp = (props: Footer) => {
const links = props.links.map((link) => {
link.mode = link.mode || 'footer'
return link
})
const extraTextClassName = useClassName(props, { el: 'extra' })
return (
<footer className={useClassName(props)}>
{links.map((link, i) => (
<LinkComp key={i} {...link} />
))}
{props.extraText && <div className={extraTextClassName}>{props.extraText}</div>}
</footer>
)
}
4 changes: 4 additions & 0 deletions src/npm-fastui/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { PaginationComp } from './pagination'
import { DetailsComp } from './details'
import { DisplayComp } from './display'
import { JsonComp } from './Json'
import { FooterComp } from './footer'
import { ServerLoadComp } from './ServerLoad'
import { ImageComp } from './image'
import { IframeComp } from './Iframe'
Expand Down Expand Up @@ -63,6 +64,7 @@ export {
DetailsComp,
DisplayComp,
JsonComp,
FooterComp,
ServerLoadComp,
ImageComp,
IframeComp,
Expand Down Expand Up @@ -116,6 +118,8 @@ export const AnyComp: FC<FastProps> = (props) => {
return <LinkListComp {...props} />
case 'Navbar':
return <NavbarComp {...props} />
case 'Footer':
return <FooterComp {...props} />
case 'Form':
case 'ModelForm':
return <FormComp {...props} />
Expand Down
22 changes: 10 additions & 12 deletions src/npm-fastui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,15 @@ export interface FastUIProps {
export function FastUI(props: FastUIProps) {
const { classNameGenerator, DisplayError, devMode, ...rest } = props
return (
<div className="fastui">
<ErrorContextProvider DisplayError={DisplayError}>
<LocationProvider>
<ClassNameContext.Provider value={classNameGenerator ?? null}>
<ConfigContext.Provider value={rest}>
<DevReload enabled={devMode} />
<FastUIController />
</ConfigContext.Provider>
</ClassNameContext.Provider>
</LocationProvider>
</ErrorContextProvider>
</div>
<ErrorContextProvider DisplayError={DisplayError}>
<LocationProvider>
<ClassNameContext.Provider value={classNameGenerator ?? null}>
<ConfigContext.Provider value={rest}>
<DevReload enabled={devMode} />
<FastUIController />
</ConfigContext.Provider>
</ClassNameContext.Provider>
</LocationProvider>
</ErrorContextProvider>
)
}
9 changes: 8 additions & 1 deletion src/npm-fastui/src/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type FastProps =
| Link
| LinkList
| Navbar
| Footer
| Modal
| ServerLoad
| Image
Expand Down Expand Up @@ -153,7 +154,7 @@ export interface AuthEvent {
export interface Link {
components: FastProps[]
onClick?: PageEvent | GoToEvent | BackEvent | AuthEvent
mode?: 'navbar' | 'tabs' | 'vertical' | 'pagination'
mode?: 'navbar' | 'footer' | 'tabs' | 'vertical' | 'pagination'
active?: string | boolean
locked?: boolean
className?: ClassName
Expand All @@ -172,6 +173,12 @@ export interface Navbar {
className?: ClassName
type: 'Navbar'
}
export interface Footer {
links: Link[]
extraText?: string
className?: ClassName
type: 'Footer'
}
export interface Modal {
title: string
body: FastProps[]
Expand Down
11 changes: 10 additions & 1 deletion src/python-fastui/fastui/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
'Form',
'FormField',
'ModelForm',
'Footer',
# then `AnyComponent` itself
'AnyComponent',
# then the other form field types which are included in `AnyComponent` via the `FormField` union
Expand Down Expand Up @@ -158,7 +159,7 @@ class Button(_p.BaseModel, extra='forbid'):
class Link(_p.BaseModel, extra='forbid'):
components: '_t.List[AnyComponent]'
on_click: _t.Union[events.AnyEvent, None] = _p.Field(default=None, serialization_alias='onClick')
mode: _t.Union[_t.Literal['navbar', 'tabs', 'vertical', 'pagination'], None] = None
mode: _t.Union[_t.Literal['navbar', 'footer', 'tabs', 'vertical', 'pagination'], None] = None
active: _t.Union[str, bool, None] = None
locked: _t.Union[bool, None] = None
class_name: _class_name.ClassNameField = None
Expand Down Expand Up @@ -189,6 +190,13 @@ def __get_pydantic_json_schema__(
return json_schema


class Footer(_p.BaseModel, extra='forbid'):
links: _t.List[Link]
extra_text: _t.Union[str, None] = _p.Field(default=None, serialization_alias='extraText')
class_name: _class_name.ClassNameField = None
type: _t.Literal['Footer'] = 'Footer'


class Modal(_p.BaseModel, extra='forbid'):
title: str
body: '_t.List[AnyComponent]'
Expand Down Expand Up @@ -286,6 +294,7 @@ class Custom(_p.BaseModel, extra='forbid'):
Link,
LinkList,
Navbar,
Footer,
Modal,
ServerLoad,
Image,
Expand Down

0 comments on commit 85b48fc

Please sign in to comment.