Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added footer component #61

Merged
merged 29 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
afe1860
Added footer component
Dejiah Dec 3, 2023
1abfe08
Added note to footer component to README.md
Dejiah Dec 4, 2023
06aa679
Merge branch 'main' into footer-component
Dejiah Dec 4, 2023
f4c8658
Made extraText camelcase in frontend
Dejiah Dec 4, 2023
f57dd79
Merge remote-tracking branch 'origin/footer-component' into footer-co…
Dejiah Dec 4, 2023
5d98ef7
Moved bootstrap-specific code out of generic footer
Dejiah Dec 5, 2023
2277be4
Fixed imports
Dejiah Dec 5, 2023
f9427df
Merge branch 'main' into footer-component
Dejiah Dec 5, 2023
4d757dd
Fixed merge conflicts
Dejiah Dec 5, 2023
3568341
Fixed merge conflicts
Dejiah Dec 5, 2023
0e2f544
Fixed python typing hints in footer
Dejiah Dec 5, 2023
1126c57
Merge branch 'main' into footer-component
Dejiah Dec 11, 2023
68c8a53
Made Footer extraText a string
Dejiah Dec 11, 2023
2fce090
Fixed class_name field in footer
Dejiah Dec 11, 2023
0660854
Made tests pass
Dejiah Dec 11, 2023
2f1c5c0
Merge branch 'main' into footer-component
Dejiah Dec 14, 2023
0ed11ba
Changed pydantic to _p
Dejiah Dec 14, 2023
b521ebf
fied Footer pydantic fields
samuelcolvin Dec 17, 2023
b8baa9e
Update demo/shared.py
Dejiah Dec 19, 2023
583feb8
Added Github as footer link
Dejiah Dec 19, 2023
4b33658
Removed horizontal line in footer
Dejiah Dec 19, 2023
aa4e045
Merge branch 'main' into footer-component
Dejiah Dec 19, 2023
4393fe8
Applied linting
Dejiah Dec 19, 2023
93044f1
Fixed demo tests
Dejiah Dec 19, 2023
991335b
Merge branch 'main' into Dejiah-footer-component
samuelcolvin Dec 22, 2023
c1f8d81
fix possitioning
samuelcolvin Dec 22, 2023
0b5bb54
fix tests
samuelcolvin Dec 22, 2023
126f037
stop rendering to root
samuelcolvin Dec 28, 2023
c53dfe9
revert prebuilt_html
samuelcolvin Dec 28, 2023
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
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