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

Better demo #17

Merged
merged 2 commits into from
Dec 1, 2023
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ Of course, that's a very simple application, the [full demo](https://fastui-demo

### Components

FastUI already defines the following components:
FastUI already defines the following components, all are shown in the [demo app](https://fastui-demo.onrender.com):

- `Text` - renders a string
- `Paragraph` - renders a string as a paragraph
- `PageTitle` - renders nothing, sets the HTML page title
- `Div` - renders a `<div>` with arbitrary components inside
- `Page` - a container for components, [example](https://fastui-demo.onrender.com)
- `Heading` - renders a heading `<h1>` to `<h6>`, [example](https://fastui-demo.onrender.com)
- `Page` - a container for components
- `Heading` - renders a heading `<h1>` to `<h6>`
- `Markdown` - renders markdown, [example](https://fastui-demo.onrender.com)
- `Code` - renders code with highlighting in a `<pre>`
- `Button` - renders a `<button>`
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/fastui-bootstrap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pydantic/fastui-bootstrap",
"version": "0.0.8",
"version": "0.0.9",
"description": "Boostrap renderer for FastUI",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -29,6 +29,6 @@
"sass": "^1.69.5"
},
"peerDependencies": {
"@pydantic/fastui": "0.0.8"
"@pydantic/fastui": "0.0.9"
}
}
11 changes: 1 addition & 10 deletions packages/fastui-bootstrap/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { pathMatch } from 'fastui'

import type { components, ClassNameGenerator, CustomRender, ClassName } from 'fastui'
import type { ClassNameGenerator, CustomRender, ClassName } from 'fastui'

import { Modal } from './modal'
import { Navbar } from './navbar'
Expand All @@ -9,8 +9,6 @@ import { Pagination } from './pagination'
export const customRender: CustomRender = (props) => {
const { type } = props
switch (type) {
case 'DisplayPrimitive':
return displayPrimitiveRender(props)
case 'Navbar':
return () => <Navbar {...props} />
case 'Modal':
Expand All @@ -20,13 +18,6 @@ export const customRender: CustomRender = (props) => {
}
}

function displayPrimitiveRender(props: components.DisplayPrimitiveProps) {
const { value } = props
if (typeof value === 'boolean') {
return () => <>{value ? '👍' : '👎'}</>
}
}

export const classNameGenerator: ClassNameGenerator = ({ props, fullPath, subElement }): ClassName => {
const { type } = props
switch (type) {
Expand Down
2 changes: 1 addition & 1 deletion packages/fastui-prebuilt/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pydantic/fastui-prebuilt",
"version": "0.0.8",
"version": "0.0.9",
"description": "Pre-built files for FastUI",
"main": "dist/index.html",
"type": "module",
Expand Down
34 changes: 26 additions & 8 deletions packages/fastui-prebuilt/src/main.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
$primary: black;
$link-color: #0d6efd; // bootstrap primary
$link-color: #0d6efd; // bootstrap primary

@import 'bootstrap/scss/bootstrap';

:root {
--bs-font-sans-serif: 'IBM Plex Sans', sans-serif;
--bs-code-color: rgb(31, 35, 40);
//
}
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,400;0,500;1,400&display=swap');

body {
margin-bottom: 60px;
}

.bg-body {
--bs-bg-opacity: 0.6;
backdrop-filter: blur(8px);
}

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

.transition-overlay {
position: fixed;
top: 0;
Expand All @@ -27,13 +45,13 @@ $link-color: #0d6efd; // bootstrap primary
}
}

.bg-body {
--bs-bg-opacity: 0.6;
backdrop-filter: blur(8px);
}

.top-offset {
margin-top: 80px;
.fastui-markdown code {
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
white-space: break-spaces;
background-color: rgba(175, 184, 193, 0.2);
border-radius: 6px;
}

// custom spinner from https://cssloaders.github.io/
Expand Down
2 changes: 1 addition & 1 deletion packages/fastui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pydantic/fastui",
"version": "0.0.8",
"version": "0.0.9",
"description": "Build better UIs faster.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
25 changes: 23 additions & 2 deletions packages/fastui/src/components/MarkdownLazy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ const MarkdownComp: FC<MarkdownProps> = (props) => {
}

return (
<Markdown className={useClassName(props)} remarkPlugins={[remarkGfm]} components={components}>
<Markdown
className={useClassName(props, { dft: 'fastui-markdown' })}
remarkPlugins={[remarkGfm]}
components={components}
>
{text}
</Markdown>
)
Expand Down Expand Up @@ -75,7 +79,24 @@ interface MarkdownCodeProps {

const MarkdownCode: FC<MarkdownCodeProps> = ({ children, className, codeStyle }) => {
const match = /language-(\w+)/.exec(className || '')
const language = match ? match[1] : undefined
if (match) {
return (
<MarkdownCodeHighlight codeStyle={codeStyle} language={match[1]}>
{children}
</MarkdownCodeHighlight>
)
} else {
return <code className={className}>{children}</code>
}
}

interface MarkdownCodeHighlightProps {
children: ReactNode
language?: string
codeStyle?: string
}

const MarkdownCodeHighlight: FC<MarkdownCodeHighlightProps> = ({ children, codeStyle, language }) => {
const codeProps: CodeProps = {
type: 'Code',
text: String(children).replace(/\n$/, ''),
Expand Down
19 changes: 18 additions & 1 deletion packages/fastui/src/components/ServerLoad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export const ServerLoadFetch: FC<{ path: string; devReload?: number }> = ({ path
promise.then(([status, data]) => {
if (status === 200) {
setComponentProps(data as FastProps[])
// if there's a fragment, scroll to that ID once the page is loaded
const fragment = getFragment(path)
if (fragment) {
setTimeout(() => {
const element = document.getElementById(fragment)
if (element) {
element.scrollIntoView()
}
}, 50)
}
} else {
setNotFoundUrl(url)
}
Expand All @@ -71,7 +81,7 @@ export const ServerLoadFetch: FC<{ path: string; devReload?: number }> = ({ path
return () => {
promise.then(() => null)
}
}, [url, request, devReload])
}, [url, path, request, devReload])

useEffect(() => {
setNotFoundUrl(undefined)
Expand Down Expand Up @@ -129,3 +139,10 @@ function useServerUrl(path: string): string {
return rootUrl + requestPath
}
}

function getFragment(path: string): string | undefined {
const index = path.indexOf('#')
if (index !== -1) {
return path.slice(index + 1)
}
}
3 changes: 2 additions & 1 deletion packages/fastui/src/components/heading.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FC } from 'react'

import { ClassName, useClassName } from '../hooks/className'
import { slugify } from '../tools'

export interface HeadingProps {
type: 'Heading'
Expand All @@ -13,7 +14,7 @@ export interface HeadingProps {
export const HeadingComp: FC<HeadingProps> = (props) => {
const { level, text, htmlId } = props
const HeadingComponent = getComponent(level)
return <HeadingComponent text={text} id={htmlId} className={useClassName(props)} />
return <HeadingComponent text={text} id={htmlId || slugify(text)} className={useClassName(props)} />
}

function getComponent(level: 1 | 2 | 3 | 4 | 5 | 6): FC<{ text: string; id?: string; className?: string }> {
Expand Down
8 changes: 6 additions & 2 deletions packages/fastui/src/hooks/locationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,12 @@ export function LocationProvider({ children }: { children: ReactNode }) {
fullPath,
goto: useCallback(
(newPath) => {
const path = pushPath(newPath)
fireLoadEvent({ path })
if (newPath.startsWith('http')) {
window.location.href = newPath
} else {
const path = pushPath(newPath)
fireLoadEvent({ path })
}
},
[pushPath],
),
Expand Down
9 changes: 9 additions & 0 deletions packages/fastui/src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,12 @@ export async function sleep(ms: number): Promise<void> {

// usage `as_title('what_ever') > 'What Ever'`
export const asTitle = (s: string): string => s.replace(/[_-]/g, ' ').replace(/(_|\b)\w/g, (l) => l.toUpperCase())

export const slugify = (s: string): string =>
s
.toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w-]+/g, '') // Remove all non-word characters
.replace(/--+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, '') // Trim - from end of text
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ classifiers = [
"Framework :: FastAPI",
]
requires-python = ">=3.8"
dependencies = ["pydantic>=2.5.2"]
dependencies = ["pydantic[email]>=2.5.2"]
dynamic = ["version"]

[project.optional-dependencies]
Expand Down
4 changes: 4 additions & 0 deletions python/demo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from fastui.dev import dev_fastapi_app
from httpx import AsyncClient

from .components_list import router as components_router
from .forms import router as forms_router
from .main import router as main_router
from .tables import router as table_router

Expand All @@ -27,7 +29,9 @@ async def lifespan(app_: FastAPI):
else:
app = FastAPI(lifespan=lifespan)

app.include_router(components_router, prefix='/api/components')
app.include_router(table_router, prefix='/api/table')
app.include_router(forms_router, prefix='/api/forms')
app.include_router(main_router, prefix='/api')


Expand Down
Loading