🎉 BadGUI v0.2.0 - Complete UI Component Suite & Enhanced Developer Experience
## 🚀 Major New Features ### Complete Component Ecosystem - **Card Components**: `bg.card()`, `bg.card_section()`, `bg.card_actions()` with NiceGUI-style API - **Tab Navigation**: `bg.tabs()`, `bg.tab()`, `bg.tab_panels()`, `bg.tab_panel()` for interactive content - **Layout Components**: `bg.header()`, `bg.footer()` with context manager support - **Media Components**: `bg.image()`, `bg.icon()` with Material Design icon integration ### Enhanced Responsive Design - **Flex Utilities**: Added Quasar flex classes (`wrap`, `col-12 col-md-4`) to prevent overflow - **Context Manager Excellence**: Fixed AttributeError issues with proper component access patterns - **Material Design**: Full icon library support with color, size, and styling options ### Developer Experience Revolution - **Comprehensive Examples**: 7+ new example files demonstrating all components and patterns - **Context Manager Guide**: Detailed documentation for proper usage patterns - **Overflow Prevention**: Responsive layout patterns that prevent UI overflow issues ## 🔧 Technical Improvements ### Core Framework - Enhanced `Component` class with proper Vue.js component mapping - Added Quasar component mapping (`q-card`, `q-tabs`, `q-img`, `q-icon`, etc.) - Fixed context manager attribute access for all container components ### API Consistency - All components support NiceGUI-style method chaining - Consistent `.classes()`, `.props()`, `.style()` method support - Proper context manager patterns: `with bg.component() as name:` → `name.classes()` ## 📁 Files Added/Modified ### New Example Files - `simple_card_test.py` - Card component demonstrations - `simple_image_icon_test.py` - Image and icon usage examples - `tabs_examples.py` - Tab navigation and content management - `simple_header_footer_test.py` - Layout component examples - `flex_layout_test.py` - Responsive layout and overflow prevention - `enhanced_navigation_example.py` - Complete website showcase - `context_manager_guide.py` - Comprehensive usage guide ### Documentation Updates - Updated `README.md` with new component showcase and responsive examples - Enhanced `docs/source/components.rst` with all new components - Expanded `docs/source/examples.rst` with comprehensive usage patterns - Added `CHANGELOG.md` with detailed release notes ### Core Framework - `badgui/core.py` - Added all new components with proper Quasar mapping - `badgui/__init__.py` - Added convenience functions for all new components - `badgui/generator.py` - Removed blue header bar from default layout - Version bump to 0.2.0 ## 🎯 Key Usage Patterns Established ### Context Manager Excellence ```python # ✅ Correct pattern (now documented and examples provided) with bg.card() as my_card: my_card.classes("q-ma-md") with bg.card_section(): bg.label("Content") ``` ### Responsive Design ```python # Overflow prevention with proper flex utilities with bg.row() as grid: grid.classes("q-gutter-md wrap") # Prevents overflow with bg.card() as card: card.classes("col-12 col-sm-6 col-md-4") # Responsive breakpoints ``` ### Material Design Integration ```python # Full Material Design icon support bg.icon("home", size="2rem", color="primary") bg.image("https://example.com/image.jpg").classes("rounded-lg full-width") ``` ## 🚀 Impact & Value ### For Developers - **Zero Breaking Changes**: All existing code continues to work - **Enhanced Productivity**: Complete UI component suite reduces development time - **Better Documentation**: Comprehensive examples and usage guides - **Responsive by Default**: Built-in overflow prevention and mobile-first design ### For Applications - **Professional UI**: Material Design components with Quasar integration - **Mobile Responsive**: Proper breakpoints and flex utilities - **Modern Architecture**: Vue.js 3 + Quasar Framework output - **Instant Development**: `bg.dev()` workflow unchanged and enhanced ## 🎨 Component Coverage **Now Complete:** - ✅ Basic: `label`, `button`, `input`, `link` - ✅ Cards: `card`, `card_section`, `card_actions` - ✅ Tabs: `tabs`, `tab`, `tab_panels`, `tab_panel` - ✅ Layout: `header`, `footer`, `row`, `column` - ✅ Media: `image`, `icon` - ✅ Navigation: Router links with Vue Router **Foundation for Future:** - 🚧 Forms, Dialogs, Tables, Menus - 🚧 Advanced interactions and data binding - 🚧 Theming and customization system This release establishes BadGUI as a complete UI framework for building modern, responsive web applications with Python syntax. The comprehensive example suite and documentation ensure developers can immediately leverage all new capabilities. --- **Migration**: No changes required - all new features are additive **Compatibility**: Full backward compatibility maintained **Testing**: All examples tested with `bg.dev()` instant development
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
badgui.components module
|
||||
========================
|
||||
|
||||
.. automodule:: badgui.components
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,7 @@
|
||||
badgui.core module
|
||||
==================
|
||||
|
||||
.. automodule:: badgui.core
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,7 @@
|
||||
badgui.generator module
|
||||
=======================
|
||||
|
||||
.. automodule:: badgui.generator
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,7 @@
|
||||
badgui.layouts module
|
||||
=====================
|
||||
|
||||
.. automodule:: badgui.layouts
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,21 @@
|
||||
badgui package
|
||||
==============
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
badgui.components
|
||||
badgui.core
|
||||
badgui.generator
|
||||
badgui.layouts
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: badgui
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,7 @@
|
||||
badgui
|
||||
======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
badgui
|
||||
@@ -0,0 +1,400 @@
|
||||
Components
|
||||
==========
|
||||
|
||||
BadGUI provides a comprehensive set of components that map to Quasar Framework components, giving you access to a rich, Material Design-based UI library. All components support NiceGUI-style method chaining and proper context manager patterns.
|
||||
|
||||
Base Component
|
||||
--------------
|
||||
|
||||
All BadGUI components inherit from the ``Component`` class, which provides common styling methods.
|
||||
|
||||
.. autoclass:: badgui.core.Component
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Text Components
|
||||
---------------
|
||||
|
||||
Label
|
||||
~~~~~
|
||||
|
||||
The ``label`` component creates text elements and headings.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Basic label
|
||||
bg.label("Hello World")
|
||||
|
||||
# With styling
|
||||
bg.label("Title").classes("text-h3 text-primary")
|
||||
bg.label("Subtitle").classes("text-h6 text-grey-7")
|
||||
|
||||
# With inline styles
|
||||
bg.label("Custom").style("color: red; font-weight: bold")
|
||||
|
||||
**Generated Output:** ``<q-item-label>``
|
||||
|
||||
Input Components
|
||||
----------------
|
||||
|
||||
Input
|
||||
~~~~~
|
||||
|
||||
The ``input`` component creates text input fields.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic input
|
||||
bg.input(placeholder="Enter text")
|
||||
|
||||
# Styled input
|
||||
bg.input(placeholder="Name").props("filled dense")
|
||||
bg.input(placeholder="Email").props('outlined label="Email Address"')
|
||||
|
||||
# With validation styling
|
||||
bg.input().classes("q-mb-md").props("filled error-message=Required")
|
||||
|
||||
**Generated Output:** ``<q-input>``
|
||||
|
||||
Interactive Components
|
||||
----------------------
|
||||
|
||||
Button
|
||||
~~~~~~
|
||||
|
||||
The ``button`` component creates clickable buttons.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic button
|
||||
bg.button("Click Me")
|
||||
|
||||
# Styled buttons
|
||||
bg.button("Primary").props("color=primary")
|
||||
bg.button("Secondary").props("color=secondary outline")
|
||||
bg.button("Icon").props("icon=star push")
|
||||
|
||||
# With custom styling
|
||||
bg.button("Custom").classes("my-custom-button").style("border-radius: 20px")
|
||||
|
||||
**Generated Output:** ``<q-btn>``
|
||||
|
||||
Card Components
|
||||
---------------
|
||||
|
||||
Card
|
||||
~~~~
|
||||
|
||||
The ``card`` component creates Material Design cards for grouping content.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic card
|
||||
with bg.card() as my_card:
|
||||
my_card.classes("q-ma-md")
|
||||
with bg.card_section():
|
||||
bg.label("Card Title").classes("text-h5")
|
||||
bg.label("Card content goes here")
|
||||
|
||||
**Generated Output:** ``<q-card>``
|
||||
|
||||
Card Section
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The ``card_section`` component creates sections within cards.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.card():
|
||||
with bg.card_section():
|
||||
bg.label("Main content")
|
||||
with bg.card_section():
|
||||
bg.label("Additional content")
|
||||
|
||||
**Generated Output:** ``<q-card-section>``
|
||||
|
||||
Card Actions
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The ``card_actions`` component creates action areas in cards.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.card():
|
||||
with bg.card_section():
|
||||
bg.label("Card content")
|
||||
with bg.card_actions():
|
||||
bg.button("Action 1")
|
||||
bg.button("Action 2")
|
||||
|
||||
**Generated Output:** ``<q-card-actions>``
|
||||
|
||||
Tab Components
|
||||
--------------
|
||||
|
||||
Tabs
|
||||
~~~~
|
||||
|
||||
The ``tabs`` component creates tab navigation.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.tabs() as main_tabs:
|
||||
main_tabs.classes("text-primary")
|
||||
with bg.tab("tab1", "Tab 1"):
|
||||
pass
|
||||
with bg.tab("tab2", "Tab 2"):
|
||||
pass
|
||||
|
||||
**Generated Output:** ``<q-tabs>``
|
||||
|
||||
Tab
|
||||
~~~
|
||||
|
||||
The ``tab`` component creates individual tab items.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.tabs():
|
||||
with bg.tab("home", "Home"):
|
||||
pass # Tab content defined in tab_panel
|
||||
|
||||
**Generated Output:** ``<q-tab>``
|
||||
|
||||
Tab Panels
|
||||
~~~~~~~~~~
|
||||
|
||||
The ``tab_panels`` component creates content containers for tabs.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.tab_panels() as panels:
|
||||
panels.classes("q-pa-md")
|
||||
with bg.tab_panel("tab1"):
|
||||
bg.label("Content for Tab 1")
|
||||
with bg.tab_panel("tab2"):
|
||||
bg.label("Content for Tab 2")
|
||||
|
||||
**Generated Output:** ``<q-tab-panels>``
|
||||
|
||||
Layout Components
|
||||
-----------------
|
||||
|
||||
Header
|
||||
~~~~~~
|
||||
|
||||
The ``header`` component creates page headers with navigation.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.header() as page_header:
|
||||
page_header.classes("bg-primary text-white q-pa-md")
|
||||
with bg.row() as nav_row:
|
||||
nav_row.classes("items-center justify-between")
|
||||
bg.label("Site Title").classes("text-h4")
|
||||
# Navigation items...
|
||||
|
||||
**Generated Output:** ``<q-header>``
|
||||
|
||||
Footer
|
||||
~~~~~~
|
||||
|
||||
The ``footer`` component creates page footers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.footer() as page_footer:
|
||||
page_footer.classes("bg-dark text-white q-pa-md")
|
||||
bg.label("© 2024 My Website. Built with BadGUI.")
|
||||
|
||||
**Generated Output:** ``<q-footer>``
|
||||
|
||||
Media Components
|
||||
----------------
|
||||
|
||||
Image
|
||||
~~~~~
|
||||
|
||||
The ``image`` component displays images with Quasar's optimized image loading.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic image
|
||||
bg.image("https://example.com/image.jpg")
|
||||
|
||||
# With styling
|
||||
bg.image("https://picsum.photos/300/200").classes("rounded-lg shadow-md")
|
||||
|
||||
# Responsive image
|
||||
bg.image("/local/image.png").classes("full-width")
|
||||
|
||||
**Generated Output:** ``<q-img>``
|
||||
|
||||
Icon
|
||||
~~~~
|
||||
|
||||
The ``icon`` component displays Material Design icons.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic icon
|
||||
bg.icon("home")
|
||||
|
||||
# With color and size
|
||||
bg.icon("star", color="yellow", size="2rem")
|
||||
|
||||
# With styling
|
||||
bg.icon("favorite", color="red").classes("q-mr-sm")
|
||||
|
||||
**Generated Output:** ``<q-icon>``
|
||||
|
||||
Navigation Components
|
||||
|
||||
Link
|
||||
~~~~
|
||||
|
||||
The ``link`` component creates router navigation links.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic link
|
||||
bg.link("Home", "/")
|
||||
|
||||
# Styled as button
|
||||
bg.link("About", "/about").classes("q-btn q-btn-primary")
|
||||
|
||||
# With props
|
||||
bg.link("Contact", "/contact").props("exact")
|
||||
|
||||
**Generated Output:** ``<router-link>``
|
||||
|
||||
Layout Components
|
||||
-----------------
|
||||
|
||||
Row
|
||||
~~~
|
||||
|
||||
The ``row`` component creates horizontal layout containers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic row
|
||||
with bg.row():
|
||||
bg.label("Item 1")
|
||||
bg.label("Item 2")
|
||||
|
||||
# Styled row
|
||||
with bg.row().classes("q-gutter-md justify-center") as row:
|
||||
row.style("background: #f5f5f5; padding: 16px")
|
||||
bg.button("Button 1")
|
||||
bg.button("Button 2")
|
||||
|
||||
**Generated Output:** ``<div class="row">``
|
||||
|
||||
Column
|
||||
~~~~~~
|
||||
|
||||
The ``column`` component creates vertical layout containers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic column
|
||||
with bg.column():
|
||||
bg.label("Item 1")
|
||||
bg.label("Item 2")
|
||||
|
||||
# Styled column
|
||||
with bg.column().classes("q-gutter-sm items-center") as col:
|
||||
col.style("min-height: 200px")
|
||||
bg.label("Centered Item 1")
|
||||
bg.label("Centered Item 2")
|
||||
|
||||
**Generated Output:** ``<div class="column">``
|
||||
|
||||
Component Properties
|
||||
--------------------
|
||||
|
||||
All components support these common properties:
|
||||
|
||||
Classes
|
||||
~~~~~~~
|
||||
|
||||
Set CSS classes using the ``.classes()`` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
component.classes("class1 class2 class3")
|
||||
component.classes(add="new-class", remove="old-class")
|
||||
component.classes(replace="completely-new-classes")
|
||||
|
||||
Props
|
||||
~~~~~
|
||||
|
||||
Set component properties using the ``.props()`` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
component.props("prop1 prop2=value")
|
||||
component.props('prop3="quoted value"')
|
||||
component.props(prop4=True, prop5="value")
|
||||
|
||||
Styles
|
||||
~~~~~~
|
||||
|
||||
Set inline CSS styles using the ``.style()`` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
component.style("color: blue; background: white")
|
||||
component.style(color="blue", backgroundColor="white")
|
||||
|
||||
Method Chaining
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
All styling methods return the component, allowing for method chaining:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
bg.button("Styled Button")\
|
||||
.classes("q-btn-primary q-ma-md")\
|
||||
.props("push icon=star")\
|
||||
.style("border-radius: 10px")
|
||||
|
||||
Component Lifecycle
|
||||
-------------------
|
||||
|
||||
Components are created when you call their factory functions (``bg.label()``, ``bg.button()``, etc.) and are automatically added to the current page context. The component tree is built during Python execution and then converted to Vue.js templates during the build process.
|
||||
|
||||
Custom Components
|
||||
-----------------
|
||||
|
||||
While BadGUI focuses on providing a curated set of components, you can extend the framework by creating custom components:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from badgui.core import Component
|
||||
import badgui as bg
|
||||
|
||||
def custom_card(title, content):
|
||||
\"\"\"Create a custom card component.\"\"\"
|
||||
component = Component('q-card')
|
||||
component.classes("q-ma-md")
|
||||
|
||||
# Add title
|
||||
title_comp = Component('q-card-section', text=title)
|
||||
title_comp.classes("text-h6")
|
||||
component.add_child(title_comp)
|
||||
|
||||
# Add content
|
||||
content_comp = Component('q-card-section', text=content)
|
||||
component.add_child(content_comp)
|
||||
|
||||
return bg.app._get_current_page()._add_component(component)
|
||||
|
||||
# Usage
|
||||
with bg.page("/", "CustomDemo"):
|
||||
custom_card("My Card", "This is custom card content")
|
||||
|
||||
This approach allows you to create reusable custom components while maintaining compatibility with BadGUI's styling system.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = 'BadGUI'
|
||||
copyright = '2025, BadGUI Team'
|
||||
author = 'BadGUI Team'
|
||||
release = '1.0.0'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../../')) # Add badgui to path
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx_autodoc_typehints',
|
||||
'myst_parser',
|
||||
]
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = []
|
||||
|
||||
language = 'en'
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_static_path = ['_static']
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# Napoleon settings
|
||||
napoleon_google_docstring = True
|
||||
napoleon_numpy_docstring = True
|
||||
napoleon_include_init_with_doc = False
|
||||
napoleon_include_private_with_doc = False
|
||||
|
||||
# Intersphinx mapping
|
||||
intersphinx_mapping = {
|
||||
'python': ('https://docs.python.org/3', None),
|
||||
}
|
||||
|
||||
# MyST parser settings
|
||||
myst_heading_anchors = 3
|
||||
myst_enable_extensions = [
|
||||
"colon_fence",
|
||||
"deflist",
|
||||
"html_admonition",
|
||||
"html_image",
|
||||
"linkify",
|
||||
"replacements",
|
||||
"smartquotes",
|
||||
"strikethrough",
|
||||
"substitution",
|
||||
"tasklist",
|
||||
]
|
||||
@@ -0,0 +1,248 @@
|
||||
Development Mode
|
||||
================
|
||||
|
||||
BadGUI provides two development workflows: **Instant Development** with ``bg.dev()`` and **Static Project Generation** with ``bg.build()``.
|
||||
|
||||
Instant Development with bg.dev()
|
||||
----------------------------------
|
||||
|
||||
The ``bg.dev()`` method provides the fastest development experience by automatically:
|
||||
|
||||
1. Creating a temporary project build
|
||||
2. Installing npm dependencies
|
||||
3. Starting the development server
|
||||
4. Opening your app in the browser
|
||||
5. Cleaning up temporary files on exit
|
||||
|
||||
Basic Usage
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "HomePage", "My App"):
|
||||
bg.label("Hello World!").classes("text-h3 text-primary")
|
||||
bg.button("Click Me").classes("q-btn-primary")
|
||||
|
||||
# 🚀 One command does it all!
|
||||
bg.dev()
|
||||
|
||||
Run your script::
|
||||
|
||||
python my_app.py
|
||||
|
||||
The server starts automatically at ``http://localhost:9000``.
|
||||
|
||||
Configuration Options
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Customize the development server:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
bg.dev(
|
||||
port=3000, # Custom port (default: 9000)
|
||||
host="localhost", # Bind to specific host (default: localhost)
|
||||
auto_reload=False, # Auto-rebuild on file changes (default: False)
|
||||
project_name="my-app" # Temporary project name (default: badgui-dev)
|
||||
)
|
||||
|
||||
Advanced Example
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_app():
|
||||
with bg.page("/", "HomePage", "Development Demo"):
|
||||
bg.label("🚀 Live Development Mode").classes("text-h2 text-center q-mb-lg")
|
||||
|
||||
with bg.row().classes("justify-center q-gutter-md") as row:
|
||||
bg.button("Primary").classes("q-btn-primary")
|
||||
bg.button("Secondary").classes("q-btn-secondary")
|
||||
bg.button("Accent").classes("q-btn-accent")
|
||||
|
||||
with bg.column().classes("q-mt-lg max-width-sm mx-auto") as form:
|
||||
bg.input(placeholder="Name").classes("q-mb-md").props("filled")
|
||||
bg.input(placeholder="Email").classes("q-mb-md").props("filled type=email")
|
||||
bg.button("Submit").classes("q-btn-primary full-width")
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_app()
|
||||
|
||||
# Development mode with custom settings
|
||||
bg.dev(
|
||||
port=3000,
|
||||
host="0.0.0.0", # Accept connections from any IP
|
||||
project_name="live-demo"
|
||||
)
|
||||
|
||||
Benefits of bg.dev()
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Zero Setup**: No manual ``npm install`` or server commands
|
||||
- **Fast Iteration**: Make changes and refresh browser
|
||||
- **Temporary Files**: No clutter in your project directory
|
||||
- **Automatic Cleanup**: Temp files removed on exit
|
||||
- **Cross-Platform**: Works on Windows, macOS, and Linux
|
||||
|
||||
Multi-Page Development
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``bg.dev()`` works seamlessly with multi-page applications:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Home page
|
||||
with bg.page("/", "HomePage", "Home"):
|
||||
bg.label("Welcome Home").classes("text-h3")
|
||||
bg.link("Go to About", "/about").classes("q-btn q-btn-primary")
|
||||
|
||||
# About page
|
||||
with bg.page("/about", "AboutPage", "About"):
|
||||
bg.label("About Us").classes("text-h3")
|
||||
bg.link("Back Home", "/").classes("q-btn q-btn-secondary")
|
||||
|
||||
# Contact page
|
||||
with bg.page("/contact", "ContactPage", "Contact"):
|
||||
bg.label("Contact Us").classes("text-h3")
|
||||
bg.input(placeholder="Message").props("filled type=textarea")
|
||||
bg.button("Send").classes("q-btn-primary")
|
||||
|
||||
# Start development server
|
||||
bg.dev(port=8080)
|
||||
|
||||
Static Project Generation
|
||||
-------------------------
|
||||
|
||||
For production deployment or when you need full control over the build process, use ``bg.build()``.
|
||||
|
||||
Basic Build
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "HomePage", "Production App"):
|
||||
bg.label("Production Ready").classes("text-h3")
|
||||
|
||||
# Generate static project
|
||||
bg.build(
|
||||
output_dir="./dist", # Output directory
|
||||
project_name="my-prod-app", # Project name
|
||||
)
|
||||
|
||||
Manual Development
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After building, you can develop manually::
|
||||
|
||||
cd dist
|
||||
npm install
|
||||
npm run dev # Development server
|
||||
npm run build # Production build
|
||||
|
||||
Deployment
|
||||
~~~~~~~~~~
|
||||
|
||||
Build for production deployment::
|
||||
|
||||
cd dist
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Deploy the dist/ folder contents to your web server
|
||||
|
||||
When to Use Each Mode
|
||||
---------------------
|
||||
|
||||
**Use bg.dev() when:**
|
||||
|
||||
- 🚀 Rapid prototyping and development
|
||||
- ⚡ Quick testing of UI changes
|
||||
- 🔧 Learning BadGUI features
|
||||
- 💻 Local development and experimentation
|
||||
|
||||
**Use bg.build() when:**
|
||||
|
||||
- 🌐 Preparing for production deployment
|
||||
- 📦 Need to customize the build process
|
||||
- 🔧 Integrating with CI/CD pipelines
|
||||
- 📝 Sharing projects with frontend developers
|
||||
|
||||
Best Practices
|
||||
--------------
|
||||
|
||||
Development Workflow
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. **Start with bg.dev()** for rapid development
|
||||
2. **Use version control** to track your Python code
|
||||
3. **Test different devices** using ``host="0.0.0.0"``
|
||||
4. **Switch to bg.build()** when ready for deployment
|
||||
|
||||
Project Organization
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# main.py
|
||||
import badgui as bg
|
||||
from pages import home, about, contact
|
||||
|
||||
def main():
|
||||
home.create_page()
|
||||
about.create_page()
|
||||
contact.create_page()
|
||||
|
||||
if __name__ == "__main__":
|
||||
bg.dev(port=3000)
|
||||
|
||||
# pages/home.py
|
||||
import badgui as bg
|
||||
|
||||
def create_page():
|
||||
with bg.page("/", "HomePage", "Home"):
|
||||
bg.label("Home Page Content")
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
**Port Already in Use**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Try a different port
|
||||
bg.dev(port=3001)
|
||||
|
||||
**npm Not Found**
|
||||
|
||||
Install Node.js from https://nodejs.org/
|
||||
|
||||
**Permission Errors**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Linux/macOS - fix npm permissions
|
||||
sudo chown -R $(whoami) ~/.npm
|
||||
|
||||
**Slow Dependencies Install**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# The first run installs dependencies (can take 1-2 minutes)
|
||||
# Subsequent runs are much faster
|
||||
|
||||
**Browser Not Opening**
|
||||
|
||||
Manually navigate to the URL shown in the terminal output.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Complete examples using ``bg.dev()`` are available in the :doc:`examples` section.
|
||||
@@ -0,0 +1,747 @@
|
||||
Examples
|
||||
========
|
||||
|
||||
This section contains practical examples demonstrating BadGUI features, including new components like cards, tabs, headers, footers, images, and icons, with emphasis on the **🚀 Instant Development** workflow using ``bg.dev()``.
|
||||
|
||||
🚀 Quick Start with bg.dev()
|
||||
-----------------------------
|
||||
|
||||
The fastest way to get started - one command does it all:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "HomePage", "Quick Start"):
|
||||
bg.label("Hello BadGUI!").classes("text-h2 text-primary text-center")
|
||||
bg.button("Click Me").classes("q-btn-primary q-btn-lg")
|
||||
|
||||
# 🚀 INSTANT DEVELOPMENT - Creates temp build, installs deps, starts server!
|
||||
bg.dev()
|
||||
|
||||
Save as ``quick_start.py`` and run::
|
||||
|
||||
python quick_start.py
|
||||
|
||||
Your app opens automatically at ``http://localhost:9000`` ✨
|
||||
|
||||
Modern Website with New Components
|
||||
----------------------------------
|
||||
|
||||
A complete website demonstrating all the new components:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Home page with full component showcase
|
||||
with bg.page("/", "HomePage", "Modern Website"):
|
||||
|
||||
# Header with navigation
|
||||
with bg.header() as nav_header:
|
||||
nav_header.classes("bg-primary text-white q-pa-md")
|
||||
with bg.row() as nav_row:
|
||||
nav_row.classes("items-center justify-between")
|
||||
|
||||
# Logo with icon
|
||||
with bg.row() as logo:
|
||||
logo.classes("items-center q-gutter-sm")
|
||||
bg.icon("home", size="2rem", color="white")
|
||||
bg.label("My Website").classes("text-h4")
|
||||
|
||||
# Navigation links
|
||||
with bg.row() as nav_links:
|
||||
nav_links.classes("q-gutter-md")
|
||||
bg.link("Home", "/").classes("text-white")
|
||||
bg.link("About", "/about").classes("text-white")
|
||||
|
||||
# Main content
|
||||
with bg.column() as main_content:
|
||||
main_content.classes("q-pa-lg")
|
||||
|
||||
# Hero card
|
||||
with bg.card() as hero:
|
||||
hero.classes("bg-blue-1 q-pa-xl q-mb-lg")
|
||||
with bg.card_section():
|
||||
bg.label("Welcome to BadGUI").classes("text-h3 text-primary q-mb-md")
|
||||
bg.label("Build modern web applications with Python syntax")
|
||||
with bg.card_actions():
|
||||
bg.button("Get Started").classes("q-btn-primary")
|
||||
bg.button("Learn More").classes("q-btn-secondary")
|
||||
|
||||
# Feature cards with responsive layout
|
||||
with bg.row() as features:
|
||||
features.classes("q-gutter-md wrap")
|
||||
|
||||
# Feature 1
|
||||
with bg.card() as feature1:
|
||||
feature1.classes("col-12 col-md-4")
|
||||
with bg.card_section():
|
||||
bg.icon("speed", size="3rem", color="primary").classes("q-mb-md")
|
||||
bg.label("Fast Development").classes("text-h5 q-mb-md")
|
||||
bg.label("Rapid prototyping with Python syntax")
|
||||
|
||||
# Feature 2
|
||||
with bg.card() as feature2:
|
||||
feature2.classes("col-12 col-md-4")
|
||||
with bg.card_section():
|
||||
bg.icon("build", size="3rem", color="secondary").classes("q-mb-md")
|
||||
bg.label("Modern Stack").classes("text-h5 q-mb-md")
|
||||
bg.label("Vue.js 3 + Quasar Framework")
|
||||
|
||||
# Feature 3
|
||||
with bg.card() as feature3:
|
||||
feature3.classes("col-12 col-md-4")
|
||||
with bg.card_section():
|
||||
bg.icon("code", size="3rem", color="accent").classes("q-mb-md")
|
||||
bg.label("NiceGUI Compatible").classes("text-h5 q-mb-md")
|
||||
bg.label("Familiar syntax and patterns")
|
||||
|
||||
# Image gallery
|
||||
with bg.card() as gallery:
|
||||
gallery.classes("q-mt-lg")
|
||||
with bg.card_section():
|
||||
with bg.row() as gallery_header:
|
||||
gallery_header.classes("items-center q-gutter-sm q-mb-lg")
|
||||
bg.icon("photo_library", size="2rem", color="primary")
|
||||
bg.label("Project Gallery").classes("text-h4")
|
||||
|
||||
with bg.row() as gallery_row:
|
||||
gallery_row.classes("q-gutter-md wrap")
|
||||
|
||||
# Gallery items
|
||||
projects = [
|
||||
("E-commerce Platform", "Modern shopping experience"),
|
||||
("Dashboard App", "Data visualization tool"),
|
||||
("Mobile App", "Cross-platform solution")
|
||||
]
|
||||
|
||||
for i, (title, desc) in enumerate(projects, 1):
|
||||
with bg.column() as gallery_item:
|
||||
gallery_item.classes("col-12 col-sm-6 col-md-4 text-center")
|
||||
bg.image(f"https://picsum.photos/300/200?random={i}").classes("rounded-lg shadow-md q-mb-sm full-width")
|
||||
bg.label(title).classes("text-h6")
|
||||
bg.label(desc)
|
||||
|
||||
# Tabs example
|
||||
with bg.tabs() as main_tabs:
|
||||
main_tabs.classes("text-primary q-mt-lg")
|
||||
with bg.tab("features", "Features"):
|
||||
pass
|
||||
with bg.tab("pricing", "Pricing"):
|
||||
pass
|
||||
with bg.tab("support", "Support"):
|
||||
pass
|
||||
|
||||
with bg.tab_panels() as panels:
|
||||
panels.classes("q-pa-md")
|
||||
|
||||
with bg.tab_panel("features"):
|
||||
with bg.column() as features_content:
|
||||
features_content.classes("q-gutter-md")
|
||||
bg.label("Comprehensive Feature Set").classes("text-h5 q-mb-md")
|
||||
|
||||
features_list = [
|
||||
("Context Managers", "Proper component nesting with 'with' statements"),
|
||||
("Responsive Design", "Built-in flex utilities and breakpoints"),
|
||||
("Material Icons", "Full Material Design icon library"),
|
||||
("NiceGUI API", "Familiar method chaining and styling")
|
||||
]
|
||||
|
||||
for title, desc in features_list:
|
||||
with bg.card() as feature_card:
|
||||
feature_card.classes("q-pa-md")
|
||||
with bg.card_section():
|
||||
with bg.row() as feature_row:
|
||||
feature_row.classes("items-center q-gutter-md")
|
||||
bg.icon("check_circle", color="positive")
|
||||
with bg.column():
|
||||
bg.label(title).classes("text-h6")
|
||||
bg.label(desc)
|
||||
|
||||
with bg.tab_panel("pricing"):
|
||||
bg.label("Pricing information goes here").classes("text-h5")
|
||||
bg.label("BadGUI is open source and free to use!")
|
||||
|
||||
with bg.tab_panel("support"):
|
||||
bg.label("Support & Documentation").classes("text-h5 q-mb-md")
|
||||
bg.label("Visit our GitHub repository for documentation and support")
|
||||
|
||||
# Footer
|
||||
with bg.footer() as page_footer:
|
||||
page_footer.classes("bg-dark text-white q-pa-lg")
|
||||
with bg.column():
|
||||
with bg.row() as footer_content:
|
||||
footer_content.classes("justify-between items-center")
|
||||
|
||||
# Company info
|
||||
with bg.column():
|
||||
with bg.row() as footer_logo:
|
||||
footer_logo.classes("items-center q-gutter-sm q-mb-md")
|
||||
bg.icon("home", size="1.5rem", color="white")
|
||||
bg.label("My Website").classes("text-h6")
|
||||
bg.label("Building the future of web development")
|
||||
|
||||
# Social icons
|
||||
with bg.row() as social_icons:
|
||||
social_icons.classes("q-gutter-md")
|
||||
bg.icon("facebook", size="1.5rem", color="blue")
|
||||
bg.icon("twitter", size="1.5rem", color="light-blue")
|
||||
bg.icon("github", size="1.5rem", color="white")
|
||||
|
||||
# Copyright
|
||||
with bg.row() as copyright:
|
||||
copyright.classes("justify-center q-pt-lg border-t border-gray-600")
|
||||
bg.label("© 2024 My Website. Built with BadGUI.").classes("opacity-75")
|
||||
|
||||
# 🚀 Start instant development
|
||||
bg.dev(port=3000)
|
||||
|
||||
Context Manager Usage Guide
|
||||
---------------------------
|
||||
|
||||
Proper usage of BadGUI's context managers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# ✅ CORRECT: Use 'as' to capture the component
|
||||
with bg.column() as main_col:
|
||||
main_col.classes("q-pa-lg")
|
||||
|
||||
with bg.row() as header_row:
|
||||
header_row.classes("items-center justify-between")
|
||||
bg.label("Title")
|
||||
|
||||
# ❌ WRONG: Cannot call .classes() on context manager directly
|
||||
# with bg.column().classes("q-pa-lg"): # This will cause AttributeError
|
||||
|
||||
# ✅ CORRECT: Cards with proper nesting
|
||||
with bg.card() as my_card:
|
||||
my_card.classes("q-ma-md shadow-5")
|
||||
|
||||
with bg.card_section():
|
||||
bg.label("Card Title").classes("text-h5")
|
||||
bg.label("Card content")
|
||||
|
||||
with bg.card_actions():
|
||||
bg.button("Action 1")
|
||||
bg.button("Action 2")
|
||||
|
||||
Responsive Layout Examples
|
||||
--------------------------
|
||||
|
||||
Preventing card overflow with proper flex utilities:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/responsive", "ResponsivePage", "Responsive Layouts"):
|
||||
|
||||
with bg.column() as main:
|
||||
main.classes("q-pa-lg")
|
||||
|
||||
# Card grid that wraps properly
|
||||
with bg.row() as card_grid:
|
||||
card_grid.classes("q-gutter-md wrap") # 'wrap' prevents overflow
|
||||
|
||||
# Cards with responsive column classes
|
||||
for i in range(6):
|
||||
with bg.card() as grid_card:
|
||||
grid_card.classes("col-12 col-sm-6 col-md-4 col-lg-2") # Responsive breakpoints
|
||||
with bg.card_section():
|
||||
bg.label(f"Card {i+1}").classes("text-h6")
|
||||
bg.label("Responsive card content")
|
||||
|
||||
# Mixed responsive layout
|
||||
with bg.row() as mixed_layout:
|
||||
mixed_layout.classes("q-gutter-md wrap")
|
||||
|
||||
# Main content area
|
||||
with bg.column() as main_content:
|
||||
main_content.classes("col-12 col-md-8") # Full width on mobile, 2/3 on desktop
|
||||
|
||||
with bg.card() as main_card:
|
||||
main_card.classes("q-pa-lg")
|
||||
bg.label("Main Content").classes("text-h4 q-mb-md")
|
||||
bg.label("This content area is responsive and adapts to screen size")
|
||||
|
||||
# Sidebar
|
||||
with bg.column() as sidebar:
|
||||
sidebar.classes("col-12 col-md-4") # Full width on mobile, 1/3 on desktop
|
||||
|
||||
with bg.card() as sidebar_card:
|
||||
sidebar_card.classes("q-pa-md bg-grey-1")
|
||||
bg.label("Sidebar").classes("text-h5 q-mb-md")
|
||||
bg.label("Sidebar content stacks below main content on mobile")
|
||||
|
||||
bg.dev(port=3001)
|
||||
|
||||
Dashboard Application
|
||||
---------------------
|
||||
|
||||
A complete dashboard with multiple sections:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_sidebar():
|
||||
\"\"\"Create sidebar navigation.\"\"\"
|
||||
with bg.column().classes("bg-grey-2 q-pa-md") as sidebar:
|
||||
sidebar.style("min-height: 100vh; width: 250px")
|
||||
|
||||
bg.label("Dashboard").classes("text-h5 q-mb-lg text-center")
|
||||
|
||||
# Navigation items
|
||||
nav_items = [
|
||||
("Overview", "/"),
|
||||
("Analytics", "/analytics"),
|
||||
("Users", "/users"),
|
||||
("Settings", "/settings")
|
||||
]
|
||||
|
||||
for label, path in nav_items:
|
||||
bg.link(label, path).classes("q-btn q-btn-flat full-width justify-start q-mb-sm")
|
||||
|
||||
def create_header(title):
|
||||
\"\"\"Create page header.\"\"\"
|
||||
with bg.row().classes("bg-primary text-white q-pa-md items-center justify-between"):
|
||||
bg.label(title).classes("text-h4")
|
||||
bg.label("Welcome, User").classes("text-body1")
|
||||
|
||||
def create_stat_card(title, value, icon, color):
|
||||
\"\"\"Create a statistics card.\"\"\"
|
||||
with bg.column().classes(f"bg-{color}-1 q-pa-lg rounded text-center") as card:
|
||||
bg.label(icon).classes(f"text-{color} text-h3 q-mb-md")
|
||||
bg.label(value).classes("text-h4 text-weight-bold q-mb-sm")
|
||||
bg.label(title).classes("text-body2 text-grey-7")
|
||||
|
||||
# Overview Page
|
||||
with bg.page("/", "OverviewPage", "Dashboard - Overview"):
|
||||
with bg.row().classes("no-wrap") as main_layout:
|
||||
create_sidebar()
|
||||
|
||||
with bg.column().classes("col"):
|
||||
create_header("Overview")
|
||||
|
||||
with bg.column().classes("q-pa-lg"):
|
||||
# Statistics row
|
||||
with bg.row().classes("q-col-gutter-lg q-mb-lg"):
|
||||
with bg.column().classes("col-12 col-md-3"):
|
||||
create_stat_card("Total Users", "1,234", "👥", "blue")
|
||||
with bg.column().classes("col-12 col-md-3"):
|
||||
create_stat_card("Revenue", "$12,345", "💰", "green")
|
||||
with bg.column().classes("col-12 col-md-3"):
|
||||
create_stat_card("Orders", "567", "📦", "orange")
|
||||
with bg.column().classes("col-12 col-md-3"):
|
||||
create_stat_card("Growth", "+23%", "📈", "purple")
|
||||
|
||||
# Recent activity
|
||||
bg.label("Recent Activity").classes("text-h5 q-mb-md")
|
||||
with bg.column().classes("bg-white rounded q-pa-lg shadow-1"):
|
||||
activities = [
|
||||
"New user registered",
|
||||
"Order #1234 completed",
|
||||
"Payment received",
|
||||
"Product updated"
|
||||
]
|
||||
for activity in activities:
|
||||
bg.label(f"• {activity}").classes("q-mb-sm")
|
||||
|
||||
# Analytics Page
|
||||
with bg.page("/analytics", "AnalyticsPage", "Dashboard - Analytics"):
|
||||
with bg.row().classes("no-wrap"):
|
||||
create_sidebar()
|
||||
|
||||
with bg.column().classes("col"):
|
||||
create_header("Analytics")
|
||||
|
||||
with bg.column().classes("q-pa-lg"):
|
||||
bg.label("Analytics Dashboard").classes("text-h4 q-mb-lg")
|
||||
|
||||
# Placeholder for charts
|
||||
with bg.row().classes("q-col-gutter-lg"):
|
||||
with bg.column().classes("col-12 col-md-6"):
|
||||
with bg.column().classes("bg-white q-pa-lg rounded shadow-1"):
|
||||
bg.label("Revenue Chart").classes("text-h6 q-mb-md")
|
||||
bg.label("Chart placeholder - integrate with Chart.js").classes("text-center q-pa-xl bg-grey-1")
|
||||
|
||||
with bg.column().classes("col-12 col-md-6"):
|
||||
with bg.column().classes("bg-white q-pa-lg rounded shadow-1"):
|
||||
bg.label("User Growth").classes("text-h6 q-mb-md")
|
||||
bg.label("Chart placeholder - integrate with Chart.js").classes("text-center q-pa-xl bg-grey-1")
|
||||
|
||||
# Users Page
|
||||
with bg.page("/users", "UsersPage", "Dashboard - Users"):
|
||||
with bg.row().classes("no-wrap"):
|
||||
create_sidebar()
|
||||
|
||||
with bg.column().classes("col"):
|
||||
create_header("Users")
|
||||
|
||||
with bg.column().classes("q-pa-lg"):
|
||||
bg.label("User Management").classes("text-h4 q-mb-lg")
|
||||
|
||||
# User table header
|
||||
with bg.row().classes("bg-grey-3 q-pa-md rounded-top"):
|
||||
bg.label("Name").classes("col-3 text-weight-bold")
|
||||
bg.label("Email").classes("col-4 text-weight-bold")
|
||||
bg.label("Role").classes("col-2 text-weight-bold")
|
||||
bg.label("Actions").classes("col-3 text-weight-bold")
|
||||
|
||||
# User rows
|
||||
users = [
|
||||
("John Doe", "john@example.com", "Admin"),
|
||||
("Jane Smith", "jane@example.com", "User"),
|
||||
("Bob Johnson", "bob@example.com", "Editor")
|
||||
]
|
||||
|
||||
for name, email, role in users:
|
||||
with bg.row().classes("bg-white q-pa-md border-bottom"):
|
||||
bg.label(name).classes("col-3")
|
||||
bg.label(email).classes("col-4")
|
||||
bg.label(role).classes("col-2")
|
||||
with bg.row().classes("col-3 q-gutter-sm"):
|
||||
bg.button("Edit").classes("q-btn-sm q-btn-primary")
|
||||
bg.button("Delete").classes("q-btn-sm q-btn-negative")
|
||||
|
||||
bg.build("dashboard-app")
|
||||
|
||||
E-commerce Store
|
||||
----------------
|
||||
|
||||
A complete e-commerce store example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_navbar():
|
||||
\"\"\"Create store navigation bar.\"\"\"
|
||||
with bg.row().classes("bg-white shadow-1 q-pa-md items-center justify-between"):
|
||||
bg.label("🛍️ MyStore").classes("text-h5 text-primary text-weight-bold")
|
||||
|
||||
with bg.row().classes("q-gutter-md items-center"):
|
||||
bg.input(placeholder="Search products...").classes("").props("outlined dense")
|
||||
bg.link("Products", "/products").classes("text-grey-8 no-underline")
|
||||
bg.link("Cart (0)", "/cart").classes("text-grey-8 no-underline")
|
||||
bg.button("Login").classes("q-btn-primary q-btn-sm")
|
||||
|
||||
def create_product_card(name, price, image_placeholder):
|
||||
\"\"\"Create a product card.\"\"\"
|
||||
with bg.column().classes("bg-white rounded shadow-2 q-pa-md"):
|
||||
# Product image placeholder
|
||||
with bg.column().classes("bg-grey-3 rounded q-mb-md text-center q-pa-xl"):
|
||||
bg.label("📷").classes("text-h3")
|
||||
bg.label(image_placeholder).classes("text-caption")
|
||||
|
||||
bg.label(name).classes("text-h6 q-mb-sm")
|
||||
bg.label(f"${price}").classes("text-h5 text-green-6 text-weight-bold q-mb-md")
|
||||
|
||||
with bg.row().classes("q-gutter-sm"):
|
||||
bg.button("Add to Cart").classes("q-btn-primary col")
|
||||
bg.button("♡").classes("q-btn-outline col-auto")
|
||||
|
||||
# Home Page
|
||||
with bg.page("/", "HomePage", "MyStore - Home"):
|
||||
create_navbar()
|
||||
|
||||
# Hero section
|
||||
with bg.column().classes("bg-gradient-to-r from-purple-400 to-pink-400 text-white text-center q-pa-xl"):
|
||||
bg.label("Welcome to MyStore").classes("text-h2 q-mb-md")
|
||||
bg.label("Discover amazing products at great prices").classes("text-h6 q-mb-lg")
|
||||
bg.link("Shop Now", "/products").classes("q-btn q-btn-lg q-btn-white text-primary")
|
||||
|
||||
# Featured products
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("Featured Products").classes("text-h4 text-center q-mb-lg")
|
||||
|
||||
with bg.row().classes("q-col-gutter-lg"):
|
||||
products = [
|
||||
("Wireless Headphones", "99.99", "Headphones Image"),
|
||||
("Smart Watch", "199.99", "Watch Image"),
|
||||
("Laptop Stand", "49.99", "Stand Image"),
|
||||
("USB-C Cable", "19.99", "Cable Image")
|
||||
]
|
||||
|
||||
for name, price, image in products:
|
||||
with bg.column().classes("col-12 col-sm-6 col-md-3"):
|
||||
create_product_card(name, price, image)
|
||||
|
||||
# Products Page
|
||||
with bg.page("/products", "ProductsPage", "Products"):
|
||||
create_navbar()
|
||||
|
||||
with bg.row().classes("q-pa-lg"):
|
||||
# Sidebar filters
|
||||
with bg.column().classes("col-12 col-md-3 q-pr-lg"):
|
||||
bg.label("Filters").classes("text-h6 q-mb-md")
|
||||
|
||||
with bg.column().classes("bg-white rounded q-pa-md shadow-1"):
|
||||
bg.label("Category").classes("text-weight-bold q-mb-sm")
|
||||
categories = ["Electronics", "Clothing", "Home", "Sports"]
|
||||
for category in categories:
|
||||
with bg.row().classes("items-center q-mb-sm"):
|
||||
bg.label(f"☐ {category}").classes("text-body2")
|
||||
|
||||
bg.label("Price Range").classes("text-weight-bold q-mb-sm q-mt-md")
|
||||
bg.input(placeholder="Min").classes("q-mb-sm").props("outlined dense type=number")
|
||||
bg.input(placeholder="Max").classes("q-mb-md").props("outlined dense type=number")
|
||||
|
||||
bg.button("Apply Filters").classes("q-btn-primary full-width")
|
||||
|
||||
# Products grid
|
||||
with bg.column().classes("col-12 col-md-9"):
|
||||
bg.label("All Products").classes("text-h5 q-mb-lg")
|
||||
|
||||
with bg.row().classes("q-col-gutter-lg"):
|
||||
# Generate more products
|
||||
all_products = [
|
||||
("Gaming Mouse", "79.99", "Mouse Image"),
|
||||
("Mechanical Keyboard", "129.99", "Keyboard Image"),
|
||||
("4K Monitor", "299.99", "Monitor Image"),
|
||||
("Webcam", "89.99", "Camera Image"),
|
||||
("Phone Case", "24.99", "Case Image"),
|
||||
("Power Bank", "39.99", "Battery Image")
|
||||
]
|
||||
|
||||
for name, price, image in all_products:
|
||||
with bg.column().classes("col-12 col-sm-6 col-lg-4"):
|
||||
create_product_card(name, price, image)
|
||||
|
||||
# Cart Page
|
||||
with bg.page("/cart", "CartPage", "Shopping Cart"):
|
||||
create_navbar()
|
||||
|
||||
with bg.column().classes("q-pa-xl max-width-md mx-auto"):
|
||||
bg.label("Shopping Cart").classes("text-h4 q-mb-lg")
|
||||
|
||||
# Cart items
|
||||
cart_items = [
|
||||
("Wireless Headphones", "99.99", "1"),
|
||||
("Smart Watch", "199.99", "1")
|
||||
]
|
||||
|
||||
for name, price, qty in cart_items:
|
||||
with bg.row().classes("bg-white rounded q-pa-md q-mb-md shadow-1 items-center"):
|
||||
with bg.column().classes("col"):
|
||||
bg.label(name).classes("text-h6")
|
||||
bg.label(f"${price}").classes("text-green-6")
|
||||
|
||||
with bg.column().classes("col-auto"):
|
||||
bg.input(value=qty).classes("text-center").props("outlined dense type=number style=width:60px")
|
||||
|
||||
with bg.column().classes("col-auto"):
|
||||
bg.button("Remove").classes("q-btn-sm q-btn-negative")
|
||||
|
||||
# Cart total
|
||||
with bg.row().classes("bg-grey-1 q-pa-md rounded justify-between items-center q-mt-lg"):
|
||||
bg.label("Total: $299.98").classes("text-h5 text-weight-bold")
|
||||
bg.button("Checkout").classes("q-btn-lg q-btn-primary")
|
||||
|
||||
bg.build("ecommerce-store")
|
||||
|
||||
Portfolio Website
|
||||
-----------------
|
||||
|
||||
A personal portfolio website:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_nav():
|
||||
\"\"\"Create navigation menu.\"\"\"
|
||||
with bg.row().classes("bg-white shadow-1 q-pa-md justify-between items-center sticky-top"):
|
||||
bg.label("John Developer").classes("text-h6 text-primary text-weight-bold")
|
||||
|
||||
with bg.row().classes("q-gutter-lg"):
|
||||
bg.link("Home", "/").classes("text-grey-8 no-underline hover-primary")
|
||||
bg.link("About", "/about").classes("text-grey-8 no-underline hover-primary")
|
||||
bg.link("Projects", "/projects").classes("text-grey-8 no-underline hover-primary")
|
||||
bg.link("Contact", "/contact").classes("text-grey-8 no-underline hover-primary")
|
||||
|
||||
# Home Page
|
||||
with bg.page("/", "HomePage", "John Developer - Portfolio"):
|
||||
create_nav()
|
||||
|
||||
# Hero section
|
||||
with bg.column().classes("text-center q-pa-xl bg-gradient-to-br from-blue-50 to-indigo-100"):
|
||||
bg.label("Hi, I'm John").classes("text-h2 q-mb-md")
|
||||
bg.label("Full Stack Developer").classes("text-h4 text-grey-7 q-mb-lg")
|
||||
bg.label("I create beautiful, functional web applications").classes("text-h6 text-grey-6 q-mb-xl")
|
||||
|
||||
with bg.row().classes("justify-center q-gutter-md"):
|
||||
bg.link("View My Work", "/projects").classes("q-btn q-btn-lg q-btn-primary")
|
||||
bg.link("Get In Touch", "/contact").classes("q-btn q-btn-lg q-btn-outline")
|
||||
|
||||
# Skills section
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("Technologies I Work With").classes("text-h4 text-center q-mb-lg")
|
||||
|
||||
with bg.row().classes("justify-center q-col-gutter-lg"):
|
||||
skills = [
|
||||
("Python", "🐍"),
|
||||
("JavaScript", "⚡"),
|
||||
("Vue.js", "💚"),
|
||||
("React", "⚛️"),
|
||||
("Node.js", "🟢"),
|
||||
("Database", "🗄️")
|
||||
]
|
||||
|
||||
for skill, icon in skills:
|
||||
with bg.column().classes("col-6 col-sm-4 col-md-2 text-center"):
|
||||
with bg.column().classes("bg-white rounded shadow-2 q-pa-lg"):
|
||||
bg.label(icon).classes("text-h2 q-mb-md")
|
||||
bg.label(skill).classes("text-weight-bold")
|
||||
|
||||
# Projects Page
|
||||
with bg.page("/projects", "ProjectsPage", "Projects"):
|
||||
create_nav()
|
||||
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("My Projects").classes("text-h3 text-center q-mb-xl")
|
||||
|
||||
projects = [
|
||||
("E-commerce Platform", "Full-stack online store with payment integration", "🛒"),
|
||||
("Task Management App", "Collaborative project management tool", "✅"),
|
||||
("Weather Dashboard", "Real-time weather data visualization", "🌤️"),
|
||||
("Blog Platform", "Content management system with admin panel", "📝")
|
||||
]
|
||||
|
||||
with bg.row().classes("q-col-gutter-xl"):
|
||||
for title, desc, icon in projects:
|
||||
with bg.column().classes("col-12 col-md-6"):
|
||||
with bg.column().classes("bg-white rounded shadow-4 q-pa-lg"):
|
||||
bg.label(icon).classes("text-h1 text-center q-mb-md")
|
||||
bg.label(title).classes("text-h5 text-center q-mb-md")
|
||||
bg.label(desc).classes("text-body1 text-grey-7 text-center q-mb-lg")
|
||||
|
||||
with bg.row().classes("justify-center q-gutter-sm"):
|
||||
bg.button("Live Demo").classes("q-btn-primary")
|
||||
bg.button("Source Code").classes("q-btn-outline")
|
||||
|
||||
bg.build("portfolio-website")
|
||||
|
||||
Blog Platform
|
||||
-------------
|
||||
|
||||
A complete blog with admin features:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_header():
|
||||
\"\"\"Create blog header.\"\"\"
|
||||
with bg.row().classes("bg-white shadow-1 q-pa-md justify-between items-center"):
|
||||
bg.link("Tech Blog", "/").classes("text-h5 text-primary text-weight-bold no-underline")
|
||||
|
||||
with bg.row().classes("q-gutter-md"):
|
||||
bg.link("Home", "/").classes("text-grey-8 no-underline")
|
||||
bg.link("Categories", "/categories").classes("text-grey-8 no-underline")
|
||||
bg.link("About", "/about").classes("text-grey-8 no-underline")
|
||||
bg.input(placeholder="Search...").classes("").props("outlined dense")
|
||||
|
||||
def create_post_card(title, excerpt, date, category):
|
||||
\"\"\"Create blog post card.\"\"\"
|
||||
with bg.column().classes("bg-white rounded shadow-2 q-pa-lg"):
|
||||
bg.label(category).classes("text-caption text-primary text-weight-bold q-mb-sm")
|
||||
bg.label(title).classes("text-h6 q-mb-md")
|
||||
bg.label(excerpt).classes("text-body2 text-grey-7 q-mb-md")
|
||||
|
||||
with bg.row().classes("justify-between items-center"):
|
||||
bg.label(date).classes("text-caption text-grey-6")
|
||||
bg.button("Read More").classes("q-btn-sm q-btn-primary")
|
||||
|
||||
# Home Page
|
||||
with bg.page("/", "HomePage", "Tech Blog"):
|
||||
create_header()
|
||||
|
||||
# Featured post
|
||||
with bg.column().classes("bg-gradient-to-r from-purple-600 to-blue-600 text-white q-pa-xl text-center"):
|
||||
bg.label("Featured Article").classes("text-caption q-mb-md opacity-80")
|
||||
bg.label("The Future of Web Development").classes("text-h3 q-mb-md")
|
||||
bg.label("Exploring emerging technologies and trends shaping the web").classes("text-h6 q-mb-lg opacity-90")
|
||||
bg.button("Read Article").classes("q-btn q-btn-lg q-btn-white text-primary")
|
||||
|
||||
# Recent posts
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("Recent Posts").classes("text-h4 q-mb-lg")
|
||||
|
||||
with bg.row().classes("q-col-gutter-lg"):
|
||||
posts = [
|
||||
("Getting Started with Vue.js 3", "Learn the basics of Vue.js 3 and its composition API...", "March 15, 2025", "Vue.js"),
|
||||
("Python Best Practices", "Write cleaner, more maintainable Python code...", "March 12, 2025", "Python"),
|
||||
("CSS Grid vs Flexbox", "When to use Grid and when to use Flexbox...", "March 10, 2025", "CSS"),
|
||||
("API Design Principles", "Building RESTful APIs that developers love...", "March 8, 2025", "Backend")
|
||||
]
|
||||
|
||||
for title, excerpt, date, category in posts:
|
||||
with bg.column().classes("col-12 col-md-6 col-lg-3"):
|
||||
create_post_card(title, excerpt, date, category)
|
||||
|
||||
# Single Post Page
|
||||
with bg.page("/post/:slug", "PostPage", "Blog Post"):
|
||||
create_header()
|
||||
|
||||
with bg.column().classes("q-pa-xl max-width-md mx-auto"):
|
||||
# Post header
|
||||
bg.label("Vue.js").classes("text-caption text-primary text-weight-bold q-mb-sm")
|
||||
bg.label("Getting Started with Vue.js 3").classes("text-h3 q-mb-md")
|
||||
|
||||
with bg.row().classes("text-grey-6 q-mb-xl"):
|
||||
bg.label("Published on March 15, 2025")
|
||||
bg.label(" • ")
|
||||
bg.label("5 min read")
|
||||
|
||||
# Post content
|
||||
bg.label("Introduction").classes("text-h5 q-mb-md q-mt-lg")
|
||||
bg.label("Vue.js 3 brings many exciting features...").classes("text-body1 q-mb-lg")
|
||||
|
||||
bg.label("Key Features").classes("text-h5 q-mb-md q-mt-lg")
|
||||
bg.label("The Composition API is one of the biggest additions...").classes("text-body1 q-mb-lg")
|
||||
|
||||
# Related posts
|
||||
bg.label("Related Posts").classes("text-h5 q-mb-md q-mt-xl")
|
||||
with bg.row().classes("q-col-gutter-md"):
|
||||
for i in range(2):
|
||||
with bg.column().classes("col-12 col-md-6"):
|
||||
create_post_card("Related Post", "Short excerpt...", "March 10, 2025", "Vue.js")
|
||||
|
||||
bg.build("blog-platform")
|
||||
|
||||
Running the Examples
|
||||
--------------------
|
||||
|
||||
To generate and run any of these examples:
|
||||
|
||||
1. **Save the code** to a Python file (e.g., ``dashboard.py``)
|
||||
|
||||
2. **Generate the project**::
|
||||
|
||||
python dashboard.py
|
||||
|
||||
3. **Run the project**::
|
||||
|
||||
cd dashboard-app # or whatever you named it
|
||||
npm install
|
||||
npm run dev
|
||||
|
||||
4. **Open in browser**: Navigate to ``http://localhost:9000``
|
||||
|
||||
Customization Tips
|
||||
------------------
|
||||
|
||||
All examples can be customized by:
|
||||
|
||||
1. **Modifying styles**: Update CSS classes and inline styles
|
||||
2. **Adding components**: Insert additional BadGUI components
|
||||
3. **Changing layouts**: Reorganize with different row/column structures
|
||||
4. **Updating content**: Replace placeholder text with real content
|
||||
5. **Adding pages**: Create additional routes for more functionality
|
||||
|
||||
The generated Vue.js projects are fully editable, so you can continue development with standard Vue.js tools and practices.
|
||||
@@ -0,0 +1,88 @@
|
||||
.. BadGUI documentation master file, created by
|
||||
sphinx-quickstart on Sat Sep 27 21:52:16 2025.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
BadGUI Documentation
|
||||
====================
|
||||
|
||||
.. image:: https://img.shields.io/badge/Python-3.8+-blue.svg
|
||||
:target: https://python.org
|
||||
:alt: Python Version
|
||||
|
||||
.. image:: https://img.shields.io/badge/Framework-Vue.js%203-green.svg
|
||||
:target: https://vuejs.org
|
||||
:alt: Vue.js 3
|
||||
|
||||
.. image:: https://img.shields.io/badge/UI-Quasar-blue.svg
|
||||
:target: https://quasar.dev
|
||||
:alt: Quasar Framework
|
||||
|
||||
**BadGUI** is a Python framework that generates Vue.js/Quasar projects using syntax similar to NiceGUI. Instead of running a live server, BadGUI creates a complete, editable Vue.js project that you can further customize and deploy.
|
||||
|
||||
Key Features
|
||||
------------
|
||||
|
||||
- **NiceGUI-like syntax**: Write familiar Python code to define your UI
|
||||
- **Vue.js/Quasar output**: Generates modern, responsive web applications
|
||||
- **Static project generation**: Creates editable Vue projects, not live servers
|
||||
- **🚀 Instant Development**: ``bg.dev()`` creates temp build, installs deps, and starts server automatically
|
||||
- **Component-based**: Modular component system for reusable UI elements
|
||||
- **Layout system**: Built-in row/column layouts with context managers
|
||||
- **Multi-page routing**: Create multiple pages with Vue Router integration
|
||||
- **Styling methods**: NiceGUI-style ``.classes()``, ``.props()``, and ``.style()`` methods
|
||||
- **Method chaining**: Fluent API for building components
|
||||
- **Dual workflow**: Instant dev mode OR static project generation
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
Installation::
|
||||
|
||||
pip install badgui
|
||||
|
||||
Basic Usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Create a page using context manager
|
||||
with bg.page("/", "HomePage", "Welcome"):
|
||||
# Basic components with styling
|
||||
bg.label("Hello BadGUI!").classes("text-h3 text-primary")
|
||||
|
||||
# Styled button with method chaining
|
||||
bg.button("Click me!").classes("q-btn-primary").props("outline")
|
||||
|
||||
# Layout containers
|
||||
with bg.row().classes("q-gutter-md") as row:
|
||||
bg.label("Item 1").classes("bg-blue-100 p-4")
|
||||
bg.label("Item 2").classes("bg-green-100 p-4")
|
||||
|
||||
# 🚀 INSTANT DEVELOPMENT - One command does it all!
|
||||
bg.dev(port=3000) # Creates temp build, installs deps, starts server!
|
||||
|
||||
# OR build static project for deployment
|
||||
# bg.build(output_dir="./my-vue-app")
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
installation
|
||||
quickstart
|
||||
development
|
||||
components
|
||||
styling
|
||||
routing
|
||||
examples
|
||||
api/modules
|
||||
|
||||
Indices and Tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
BadGUI requires:
|
||||
|
||||
- Python 3.8 or higher
|
||||
- Node.js 16+ (for running generated Vue.js projects)
|
||||
- npm or yarn (for package management)
|
||||
|
||||
Install BadGUI
|
||||
--------------
|
||||
|
||||
Install from PyPI using pip::
|
||||
|
||||
pip install badgui
|
||||
|
||||
Development Installation
|
||||
------------------------
|
||||
|
||||
To install BadGUI for development::
|
||||
|
||||
git clone https://github.com/your-username/badgui.git
|
||||
cd badgui
|
||||
pip install -e .
|
||||
|
||||
Verify Installation
|
||||
-------------------
|
||||
|
||||
To verify that BadGUI is installed correctly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
print(bg.__version__)
|
||||
|
||||
System Dependencies
|
||||
-------------------
|
||||
|
||||
For generated Vue.js projects, you'll need:
|
||||
|
||||
**Node.js and npm**::
|
||||
|
||||
# Ubuntu/Debian
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# macOS
|
||||
brew install node
|
||||
|
||||
# Windows
|
||||
# Download from https://nodejs.org/
|
||||
|
||||
**Verify Node.js installation**::
|
||||
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
**ImportError: No module named 'badgui'**
|
||||
Make sure BadGUI is installed in the correct Python environment.
|
||||
|
||||
**Command 'npm' not found**
|
||||
Install Node.js which includes npm.
|
||||
|
||||
**Permission denied errors**
|
||||
Use ``pip install --user badgui`` to install in user directory.
|
||||
@@ -0,0 +1,147 @@
|
||||
Quick Start Guide
|
||||
=================
|
||||
|
||||
This guide will get you up and running with BadGUI in minutes.
|
||||
|
||||
Your First BadGUI App
|
||||
---------------------
|
||||
|
||||
Create a new Python file called ``hello_world.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Create a page using context manager
|
||||
with bg.page("/", "HomePage", "Hello World"):
|
||||
bg.label("Hello, World!").classes("text-h2 text-primary")
|
||||
bg.label("Welcome to BadGUI").classes("text-body1 text-grey-7")
|
||||
|
||||
with bg.row().classes("q-gutter-md q-mt-md") as row:
|
||||
bg.button("Primary Button").classes("q-btn-primary")
|
||||
bg.button("Secondary Button").classes("q-btn-secondary")
|
||||
|
||||
# 🚀 INSTANT DEVELOPMENT MODE - One command does it all!
|
||||
bg.dev(port=3000) # Creates temp build, installs deps, starts server!
|
||||
|
||||
Run the script::
|
||||
|
||||
python hello_world.py
|
||||
|
||||
**That's it!** The server automatically starts at ``http://localhost:3000`` - no manual setup needed!
|
||||
|
||||
Development Modes
|
||||
-----------------
|
||||
|
||||
**🚀 Instant Development (Recommended)**
|
||||
|
||||
BadGUI's ``bg.dev()`` method provides the fastest development experience:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# At the end of your script, use:
|
||||
bg.dev(port=3000) # Automatic build + install + server start
|
||||
|
||||
**📦 Static Project Generation**
|
||||
|
||||
For deployment or manual development, use ``bg.build()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Generate static project
|
||||
bg.build("hello-world-app")
|
||||
|
||||
Then manually run::
|
||||
|
||||
cd hello-world-app
|
||||
npm install
|
||||
npm run dev
|
||||
|
||||
Adding Components
|
||||
-----------------
|
||||
|
||||
BadGUI provides several built-in components:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "ComponentsDemo", "Components Demo"):
|
||||
# Text components
|
||||
bg.label("Main Title").classes("text-h3")
|
||||
bg.label("Subtitle").classes("text-h6 text-grey-7")
|
||||
|
||||
# Input components
|
||||
bg.input(placeholder="Enter your name").classes("q-mb-md")
|
||||
|
||||
# Buttons
|
||||
bg.button("Click Me").props("push color=primary")
|
||||
|
||||
# Navigation
|
||||
bg.link("Go to About", "/about").classes("q-btn q-btn-outline")
|
||||
|
||||
bg.build("components-demo")
|
||||
|
||||
Using Layouts
|
||||
-------------
|
||||
|
||||
Create structured layouts with row and column containers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "LayoutDemo", "Layout Demo"):
|
||||
bg.label("Layout Example").classes("text-h4 q-mb-lg")
|
||||
|
||||
# Horizontal layout
|
||||
with bg.row().classes("q-gutter-md q-mb-lg"):
|
||||
bg.label("Left Column").classes("bg-blue-1 p-4 rounded")
|
||||
bg.label("Middle Column").classes("bg-green-1 p-4 rounded")
|
||||
bg.label("Right Column").classes("bg-red-1 p-4 rounded")
|
||||
|
||||
# Vertical layout
|
||||
with bg.column().classes("q-gutter-sm"):
|
||||
bg.label("Row 1").classes("bg-grey-2 p-2")
|
||||
bg.label("Row 2").classes("bg-grey-2 p-2")
|
||||
bg.label("Row 3").classes("bg-grey-2 p-2")
|
||||
|
||||
bg.build("layout-demo")
|
||||
|
||||
Multi-Page Applications
|
||||
-----------------------
|
||||
|
||||
Create multiple pages with routing:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Home page
|
||||
with bg.page("/", "HomePage", "Home"):
|
||||
bg.label("Welcome to Home").classes("text-h3")
|
||||
bg.label("This is the home page content.")
|
||||
bg.link("Go to About", "/about").classes("q-btn q-btn-primary q-mt-md")
|
||||
|
||||
# About page
|
||||
with bg.page("/about", "AboutPage", "About"):
|
||||
bg.label("About Us").classes("text-h3")
|
||||
bg.label("Learn more about our application.")
|
||||
bg.link("Back to Home", "/").classes("q-btn q-btn-secondary q-mt-md")
|
||||
|
||||
# Contact page
|
||||
with bg.page("/contact", "ContactPage", "Contact"):
|
||||
bg.label("Contact Us").classes("text-h3")
|
||||
bg.input(placeholder="Your Name").classes("q-mb-md")
|
||||
bg.input(placeholder="Your Email").classes("q-mb-md")
|
||||
bg.button("Send Message").classes("q-btn q-btn-primary")
|
||||
|
||||
bg.build("multi-page-app")
|
||||
|
||||
Next Steps
|
||||
----------
|
||||
|
||||
- Learn about :doc:`components` for detailed component documentation
|
||||
- Explore :doc:`styling` for advanced styling techniques
|
||||
- Check out :doc:`examples` for complete application examples
|
||||
- Review the :doc:`api/modules` for full API reference
|
||||
@@ -0,0 +1,389 @@
|
||||
Routing and Multi-Page Apps
|
||||
===========================
|
||||
|
||||
BadGUI supports creating multi-page applications with Vue Router integration, allowing you to build complex single-page applications with client-side routing.
|
||||
|
||||
Page Management
|
||||
---------------
|
||||
|
||||
Pages in BadGUI are created using the ``page()`` function, which acts as both a page definer and a context manager.
|
||||
|
||||
Creating Pages
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
# Create a page with context manager
|
||||
with bg.page("/", "HomePage", "Home"):
|
||||
bg.label("Welcome to the Home Page")
|
||||
bg.label("This is the main landing page")
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- ``path``: URL path (e.g., ``"/"``, ``"/about"``, ``"/contact"``)
|
||||
- ``name``: Component name (e.g., ``"HomePage"``, ``"AboutPage"``)
|
||||
- ``title``: Page title displayed in browser tab (optional)
|
||||
|
||||
Page Context
|
||||
~~~~~~~~~~~~
|
||||
|
||||
All components created within a page context are automatically added to that page:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.page("/about", "AboutPage", "About Us"):
|
||||
# These components belong to the About page
|
||||
bg.label("About Our Company")
|
||||
bg.label("Founded in 2025")
|
||||
|
||||
with bg.row():
|
||||
bg.label("Mission")
|
||||
bg.label("Vision")
|
||||
|
||||
Navigation
|
||||
----------
|
||||
|
||||
Link Component
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Create navigation between pages using the ``link()`` component:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Basic link
|
||||
bg.link("Go to About", "/about")
|
||||
|
||||
# Styled as button
|
||||
bg.link("Contact Us", "/contact").classes("q-btn q-btn-primary")
|
||||
|
||||
# With additional props
|
||||
bg.link("Home", "/").props("exact").classes("nav-link")
|
||||
|
||||
**Generated Output:** ``<router-link to="/about">Go to About</router-link>``
|
||||
|
||||
Navigation Menu
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Create a navigation menu across multiple pages:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def create_nav():
|
||||
\"\"\"Create consistent navigation menu.\"\"\"
|
||||
with bg.row().classes("q-gutter-md q-mb-lg justify-center") as nav:
|
||||
nav.classes("bg-primary text-white q-pa-md rounded")
|
||||
bg.link("Home", "/").classes("text-white no-underline q-btn q-btn-flat")
|
||||
bg.link("About", "/about").classes("text-white no-underline q-btn q-btn-flat")
|
||||
bg.link("Services", "/services").classes("text-white no-underline q-btn q-btn-flat")
|
||||
bg.link("Contact", "/contact").classes("text-white no-underline q-btn q-btn-flat")
|
||||
|
||||
# Use in each page
|
||||
with bg.page("/", "HomePage", "Home"):
|
||||
create_nav()
|
||||
bg.label("Home Page Content")
|
||||
|
||||
with bg.page("/about", "AboutPage", "About"):
|
||||
create_nav()
|
||||
bg.label("About Page Content")
|
||||
|
||||
Route Parameters
|
||||
----------------
|
||||
|
||||
Dynamic Routes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Create routes with parameters:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Route with parameter
|
||||
with bg.page("/user/:id", "UserPage", "User Profile"):
|
||||
bg.label("User Profile Page")
|
||||
bg.label("User ID will be available in Vue component")
|
||||
|
||||
# Navigation to dynamic route
|
||||
bg.link("View User 123", "/user/123")
|
||||
|
||||
Nested Routes
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Create nested route structures:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Parent route
|
||||
with bg.page("/dashboard", "DashboardPage", "Dashboard"):
|
||||
bg.label("Dashboard").classes("text-h3")
|
||||
|
||||
# Navigation to child routes
|
||||
with bg.row().classes("q-gutter-md"):
|
||||
bg.link("Analytics", "/dashboard/analytics")
|
||||
bg.link("Settings", "/dashboard/settings")
|
||||
bg.link("Profile", "/dashboard/profile")
|
||||
|
||||
# Child routes
|
||||
with bg.page("/dashboard/analytics", "AnalyticsPage", "Analytics"):
|
||||
bg.label("Analytics Dashboard")
|
||||
bg.label("View your analytics data here")
|
||||
|
||||
with bg.page("/dashboard/settings", "SettingsPage", "Settings"):
|
||||
bg.label("Dashboard Settings")
|
||||
bg.input(placeholder="Setting 1")
|
||||
bg.input(placeholder="Setting 2")
|
||||
|
||||
Multi-Page Application Example
|
||||
------------------------------
|
||||
|
||||
Complete Blog Application
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Here's a complete multi-page blog application:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
def create_header():
|
||||
\"\"\"Create site header with navigation.\"\"\"
|
||||
with bg.row().classes("bg-primary text-white q-pa-md justify-between items-center") as header:
|
||||
bg.label("My Blog").classes("text-h5 text-weight-bold")
|
||||
|
||||
with bg.row().classes("q-gutter-md"):
|
||||
bg.link("Home", "/").classes("text-white q-btn q-btn-flat")
|
||||
bg.link("Posts", "/posts").classes("text-white q-btn q-btn-flat")
|
||||
bg.link("About", "/about").classes("text-white q-btn q-btn-flat")
|
||||
bg.link("Contact", "/contact").classes("text-white q-btn q-btn-flat")
|
||||
|
||||
def create_footer():
|
||||
\"\"\"Create site footer.\"\"\"
|
||||
with bg.row().classes("bg-grey-8 text-white q-pa-lg justify-center q-mt-xl"):
|
||||
bg.label("© 2025 My Blog. All rights reserved.").classes("text-body2")
|
||||
|
||||
# Home Page
|
||||
with bg.page("/", "HomePage", "My Blog - Home"):
|
||||
create_header()
|
||||
|
||||
# Hero section
|
||||
with bg.column().classes("text-center q-pa-xl bg-gradient-to-r from-blue-500 to-purple-600 text-white"):
|
||||
bg.label("Welcome to My Blog").classes("text-h2 q-mb-md")
|
||||
bg.label("Sharing thoughts and ideas").classes("text-h6 q-mb-lg")
|
||||
bg.link("Read Latest Posts", "/posts").classes("q-btn q-btn-lg q-btn-white text-primary")
|
||||
|
||||
# Featured posts
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("Featured Posts").classes("text-h4 q-mb-lg text-center")
|
||||
|
||||
with bg.row().classes("q-col-gutter-lg"):
|
||||
for i in range(3):
|
||||
with bg.column().classes("col-12 col-md-4"):
|
||||
with bg.column().classes("bg-white rounded-lg shadow-2 q-pa-lg"):
|
||||
bg.label(f"Post Title {i+1}").classes("text-h6 q-mb-md")
|
||||
bg.label("Post excerpt goes here...").classes("text-body2 q-mb-md")
|
||||
bg.link("Read More", f"/post/{i+1}").classes("q-btn q-btn-primary")
|
||||
|
||||
create_footer()
|
||||
|
||||
# Posts Page
|
||||
with bg.page("/posts", "PostsPage", "All Posts"):
|
||||
create_header()
|
||||
|
||||
with bg.column().classes("q-pa-xl"):
|
||||
bg.label("All Posts").classes("text-h3 q-mb-lg")
|
||||
|
||||
# Post list
|
||||
for i in range(10):
|
||||
with bg.row().classes("bg-white rounded q-pa-lg q-mb-md shadow-1"):
|
||||
with bg.column().classes("col-12"):
|
||||
bg.label(f"Blog Post {i+1}").classes("text-h6 q-mb-sm")
|
||||
bg.label("Published on January 1, 2025").classes("text-caption text-grey-6 q-mb-md")
|
||||
bg.label("This is a preview of the blog post content...").classes("text-body2 q-mb-md")
|
||||
bg.link("Read Full Post", f"/post/{i+1}").classes("q-btn q-btn-outline")
|
||||
|
||||
create_footer()
|
||||
|
||||
# Individual Post Page
|
||||
with bg.page("/post/:id", "PostPage", "Blog Post"):
|
||||
create_header()
|
||||
|
||||
with bg.column().classes("q-pa-xl max-width-md mx-auto"):
|
||||
bg.label("Blog Post Title").classes("text-h3 q-mb-md")
|
||||
bg.label("Published on January 1, 2025 by Author").classes("text-caption text-grey-6 q-mb-lg")
|
||||
|
||||
bg.label("Blog post content goes here...").classes("text-body1 q-mb-lg")
|
||||
bg.label("More content and paragraphs...").classes("text-body1 q-mb-lg")
|
||||
|
||||
with bg.row().classes("q-mt-xl"):
|
||||
bg.link("← Back to Posts", "/posts").classes("q-btn q-btn-outline")
|
||||
|
||||
create_footer()
|
||||
|
||||
# About Page
|
||||
with bg.page("/about", "AboutPage", "About"):
|
||||
create_header()
|
||||
|
||||
with bg.column().classes("q-pa-xl max-width-md mx-auto text-center"):
|
||||
bg.label("About Me").classes("text-h3 q-mb-lg")
|
||||
bg.label("Welcome to my personal blog...").classes("text-body1 q-mb-lg")
|
||||
bg.label("I write about technology, life, and everything in between.").classes("text-body1 q-mb-lg")
|
||||
|
||||
create_footer()
|
||||
|
||||
# Contact Page
|
||||
with bg.page("/contact", "ContactPage", "Contact"):
|
||||
create_header()
|
||||
|
||||
with bg.column().classes("q-pa-xl max-width-sm mx-auto"):
|
||||
bg.label("Contact Me").classes("text-h3 q-mb-lg text-center")
|
||||
|
||||
# Contact form
|
||||
bg.input(placeholder="Your Name").classes("q-mb-md").props("filled required")
|
||||
bg.input(placeholder="Your Email").classes("q-mb-md").props("filled required type=email")
|
||||
bg.input(placeholder="Subject").classes("q-mb-md").props("filled required")
|
||||
bg.input(placeholder="Your Message").classes("q-mb-lg").props("filled required type=textarea rows=4")
|
||||
|
||||
bg.button("Send Message").classes("q-btn q-btn-primary full-width")
|
||||
|
||||
create_footer()
|
||||
|
||||
# Build the application
|
||||
bg.build("blog-app")
|
||||
|
||||
Route Configuration
|
||||
-------------------
|
||||
|
||||
Generated Router Files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
BadGUI automatically generates Vue Router configuration files:
|
||||
|
||||
**``src/router/routes.js``:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [
|
||||
{ path: '', component: () => import('pages/HomePage.vue') },
|
||||
{ path: '/about', component: () => import('pages/AboutPage.vue') },
|
||||
{ path: '/posts', component: () => import('pages/PostsPage.vue') },
|
||||
{ path: '/post/:id', component: () => import('pages/PostPage.vue') },
|
||||
{ path: '/contact', component: () => import('pages/ContactPage.vue') }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
**``src/router/index.js``:**
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import routes from './routes'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
Page Components
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Each page generates a corresponding Vue component:
|
||||
|
||||
**``src/pages/HomePage.vue``:**
|
||||
|
||||
.. code-block:: vue
|
||||
|
||||
<template>
|
||||
<q-page class="row items-center justify-evenly">
|
||||
<!-- Generated components -->
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
// Component logic
|
||||
</script>
|
||||
|
||||
Best Practices
|
||||
--------------
|
||||
|
||||
URL Structure
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
1. **Use clear, descriptive URLs**: ``/about``, ``/contact``, ``/blog/post-title``
|
||||
2. **Keep URLs short and readable**: Avoid deep nesting
|
||||
3. **Use hyphens for multi-word URLs**: ``/user-profile`` not ``/userprofile``
|
||||
4. **Be consistent**: Choose a pattern and stick to it
|
||||
|
||||
Page Organization
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. **Group related pages**: Keep similar functionality together
|
||||
2. **Use consistent layouts**: Share common elements like headers/footers
|
||||
3. **Plan your navigation flow**: Make it easy for users to move between pages
|
||||
4. **Consider SEO**: Use descriptive page titles
|
||||
|
||||
Performance Considerations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. **Code splitting**: Vue Router automatically splits pages into separate chunks
|
||||
2. **Lazy loading**: Pages are loaded only when needed
|
||||
3. **Minimize page complexity**: Keep individual pages focused and lightweight
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
404 Error Page
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
BadGUI automatically generates a 404 error page:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# This is generated automatically
|
||||
with bg.page("/:catchAll(.*)*", "ErrorNotFound", "Page Not Found"):
|
||||
bg.label("Oops. Nothing here...").classes("text-h2")
|
||||
bg.link("Go Home", "/").classes("q-btn q-btn-primary")
|
||||
|
||||
The generated project includes proper error handling for routes that don't exist.
|
||||
|
||||
Advanced Routing
|
||||
----------------
|
||||
|
||||
Route Guards
|
||||
~~~~~~~~~~~~
|
||||
|
||||
While BadGUI generates static routes, you can add route guards in the generated Vue project:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
// In the generated router/index.js, you can add:
|
||||
router.beforeEach((to, from, next) => {
|
||||
// Add authentication, analytics, etc.
|
||||
next()
|
||||
})
|
||||
|
||||
Programmatic Navigation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the generated Vue components, you can add programmatic navigation:
|
||||
|
||||
.. code-block:: vue
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const navigateToAbout = () => {
|
||||
router.push('/about')
|
||||
}
|
||||
</script>
|
||||
|
||||
This allows for dynamic navigation based on user actions or application state.
|
||||
@@ -0,0 +1,351 @@
|
||||
Styling
|
||||
=======
|
||||
|
||||
BadGUI provides powerful styling capabilities inspired by NiceGUI, allowing you to style components using CSS classes, component properties, and inline styles.
|
||||
|
||||
Styling Methods
|
||||
---------------
|
||||
|
||||
BadGUI components support three main styling methods:
|
||||
|
||||
Classes Method
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The ``.classes()`` method manages CSS classes, supporting Tailwind CSS, Quasar classes, and custom CSS classes.
|
||||
|
||||
**Basic Usage:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Add classes
|
||||
label = bg.label("Styled Text")
|
||||
label.classes("text-h4 text-primary q-mb-md")
|
||||
|
||||
**Method Chaining:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
bg.label("Chained Styling")\
|
||||
.classes("text-center")\
|
||||
.classes("text-bold")\
|
||||
.classes("bg-blue-100 p-4")
|
||||
|
||||
**Advanced Class Management:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
label = bg.label("Dynamic Classes")
|
||||
|
||||
# Add specific classes
|
||||
label.classes(add="border rounded")
|
||||
|
||||
# Remove classes
|
||||
label.classes(remove="bg-blue-100")
|
||||
|
||||
# Replace all classes
|
||||
label.classes(replace="text-h3 text-success")
|
||||
|
||||
Props Method
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The ``.props()`` method sets component properties, supporting both string and keyword syntax.
|
||||
|
||||
**String Syntax:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Boolean properties
|
||||
button = bg.button("Button")
|
||||
button.props("outline rounded push")
|
||||
|
||||
# Key-value properties
|
||||
input_field = bg.input()
|
||||
input_field.props("color=primary dense filled")
|
||||
|
||||
# Quoted values
|
||||
input_field.props('label="Enter your name" placeholder="Full name"')
|
||||
|
||||
**Keyword Syntax:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
button.props(
|
||||
color="primary",
|
||||
outline=True,
|
||||
disabled=False,
|
||||
icon="star"
|
||||
)
|
||||
|
||||
**Mixed Syntax:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
component.props("dense filled", color="teal", label="Advanced Input")
|
||||
|
||||
Style Method
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The ``.style()`` method applies inline CSS styles.
|
||||
|
||||
**CSS String Syntax:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
label = bg.label("Custom Styled")
|
||||
label.style("color: #ff6b6b; font-size: 18px; padding: 10px")
|
||||
|
||||
**Keyword Syntax:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# camelCase is automatically converted to kebab-case
|
||||
label.style(
|
||||
color="#4ecdc4",
|
||||
backgroundColor="#f7f7f7",
|
||||
fontSize="16px",
|
||||
borderLeft="4px solid #4ecdc4"
|
||||
)
|
||||
|
||||
**Style Chaining:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
bg.label("Multi-Style")\
|
||||
.style("color: red; background: yellow")\
|
||||
.style("padding: 10px; border-radius: 5px")
|
||||
|
||||
CSS Frameworks
|
||||
--------------
|
||||
|
||||
BadGUI works seamlessly with popular CSS frameworks:
|
||||
|
||||
Quasar Classes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
BadGUI generates Quasar Framework projects, giving you access to all Quasar CSS classes:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Typography
|
||||
bg.label("Heading").classes("text-h3 text-weight-bold text-primary")
|
||||
bg.label("Body").classes("text-body1 text-grey-7")
|
||||
|
||||
# Spacing
|
||||
bg.button("Spaced").classes("q-ma-lg q-pa-md")
|
||||
|
||||
# Colors
|
||||
bg.label("Colored").classes("bg-positive text-white")
|
||||
|
||||
# Flexbox utilities
|
||||
with bg.row().classes("justify-center items-center q-gutter-md"):
|
||||
bg.button("Centered 1")
|
||||
bg.button("Centered 2")
|
||||
|
||||
Tailwind CSS
|
||||
~~~~~~~~~~~~
|
||||
|
||||
BadGUI supports Tailwind CSS classes out of the box:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Layout
|
||||
with bg.row().classes("flex flex-wrap gap-4"):
|
||||
bg.label("Item 1").classes("flex-1 bg-blue-100 p-4 rounded")
|
||||
bg.label("Item 2").classes("flex-1 bg-green-100 p-4 rounded")
|
||||
|
||||
# Typography
|
||||
bg.label("Title").classes("text-2xl font-bold text-gray-800")
|
||||
bg.label("Subtitle").classes("text-lg text-gray-600 italic")
|
||||
|
||||
# Responsive design
|
||||
bg.button("Responsive").classes("w-full md:w-auto px-6 py-2")
|
||||
|
||||
Custom CSS
|
||||
~~~~~~~~~~
|
||||
|
||||
Add your own custom CSS classes:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Assuming you have custom CSS defined
|
||||
bg.label("Custom").classes("my-custom-gradient-text shadow-custom")
|
||||
|
||||
# Mix with framework classes
|
||||
bg.button("Mixed").classes("q-btn-primary my-custom-hover-effect")
|
||||
|
||||
Layout Styling
|
||||
--------------
|
||||
|
||||
Style layout containers for complex designs:
|
||||
|
||||
Responsive Layouts
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with bg.row().classes("row q-col-gutter-md") as responsive_row:
|
||||
responsive_row.style("min-height: 300px")
|
||||
|
||||
# Responsive columns
|
||||
with bg.column().classes("col-12 col-md-6 col-lg-4"):
|
||||
bg.label("Column 1").classes("bg-blue-1 p-4 full-height")
|
||||
|
||||
with bg.column().classes("col-12 col-md-6 col-lg-4"):
|
||||
bg.label("Column 2").classes("bg-green-1 p-4 full-height")
|
||||
|
||||
with bg.column().classes("col-12 col-md-12 col-lg-4"):
|
||||
bg.label("Column 3").classes("bg-red-1 p-4 full-height")
|
||||
|
||||
Grid Layouts
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# CSS Grid using Tailwind
|
||||
with bg.row().classes("grid grid-cols-1 md:grid-cols-3 gap-4") as grid:
|
||||
for i in range(6):
|
||||
bg.label(f"Grid Item {i+1}").classes("bg-gray-100 p-4 rounded text-center")
|
||||
|
||||
Flexbox Layouts
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Flex container
|
||||
with bg.row().classes("flex justify-between items-center q-pa-md") as flex_row:
|
||||
flex_row.style("background: linear-gradient(45deg, #f0f0f0, #e0e0e0)")
|
||||
|
||||
bg.label("Left").classes("text-h6")
|
||||
bg.button("Center").classes("q-btn-primary")
|
||||
bg.label("Right").classes("text-caption")
|
||||
|
||||
Advanced Styling
|
||||
----------------
|
||||
|
||||
Dynamic Styling
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Create dynamic styles based on conditions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def create_status_label(text, status):
|
||||
label = bg.label(text)
|
||||
|
||||
if status == "success":
|
||||
label.classes("text-positive bg-light-green-1 q-pa-sm rounded")
|
||||
elif status == "warning":
|
||||
label.classes("text-warning bg-orange-1 q-pa-sm rounded")
|
||||
elif status == "error":
|
||||
label.classes("text-negative bg-red-1 q-pa-sm rounded")
|
||||
else:
|
||||
label.classes("text-grey-7 bg-grey-1 q-pa-sm rounded")
|
||||
|
||||
return label
|
||||
|
||||
# Usage
|
||||
with bg.page("/", "StatusDemo"):
|
||||
create_status_label("Success Message", "success")
|
||||
create_status_label("Warning Message", "warning")
|
||||
create_status_label("Error Message", "error")
|
||||
|
||||
Theme Integration
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Work with Quasar's theming system:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Using theme colors
|
||||
bg.button("Primary").props("color=primary")
|
||||
bg.button("Secondary").props("color=secondary")
|
||||
bg.button("Accent").props("color=accent")
|
||||
|
||||
# Dark mode classes
|
||||
bg.label("Dark Mode Text").classes("text-white bg-dark q-pa-md")
|
||||
|
||||
Animations and Transitions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add CSS animations and transitions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Hover effects
|
||||
bg.button("Hover Me").classes("transition-all duration-300 hover:scale-105")
|
||||
|
||||
# Loading states
|
||||
bg.button("Loading").props("loading").classes("q-btn-primary")
|
||||
|
||||
# Custom animations (requires custom CSS)
|
||||
bg.label("Animated").classes("fade-in-animation pulse-on-hover")
|
||||
|
||||
Best Practices
|
||||
--------------
|
||||
|
||||
1. **Use Semantic Classes**: Prefer semantic class names over purely visual ones
|
||||
2. **Mobile First**: Design for mobile devices first, then add desktop styles
|
||||
3. **Consistent Spacing**: Use consistent spacing units (Quasar's spacing system)
|
||||
4. **Color Harmony**: Stick to a consistent color palette
|
||||
5. **Performance**: Avoid excessive inline styles; prefer CSS classes
|
||||
|
||||
**Good Example:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Good: Semantic, consistent, mobile-first
|
||||
bg.label("Article Title").classes("text-h4 q-mb-md text-weight-medium")
|
||||
bg.label("Article Content").classes("text-body1 text-grey-8 line-height-md")
|
||||
|
||||
**Avoid:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Avoid: Too specific, hard to maintain
|
||||
bg.label("Title").style("font-size: 24px; margin-bottom: 16px; font-weight: 500; color: #1976d2")
|
||||
|
||||
Debugging Styles
|
||||
----------------
|
||||
|
||||
Tips for debugging styling issues:
|
||||
|
||||
1. **Inspect Generated HTML**: Check the generated Vue components in the build output
|
||||
2. **Browser DevTools**: Use browser inspector to see applied styles
|
||||
3. **Class Conflicts**: Be aware of CSS specificity and class order
|
||||
4. **Framework Documentation**: Refer to Quasar and Tailwind documentation
|
||||
|
||||
Example: Complete Styled Page
|
||||
-----------------------------
|
||||
|
||||
Here's a complete example showcasing various styling techniques:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import badgui as bg
|
||||
|
||||
with bg.page("/", "StyledDemo", "Styling Demo"):
|
||||
# Header
|
||||
bg.label("Styling Showcase").classes("text-h2 text-center text-primary q-mb-xl")
|
||||
|
||||
# Hero section
|
||||
with bg.row().classes("bg-gradient-to-r from-blue-400 to-purple-500 text-white q-pa-xl rounded-lg q-mb-lg") as hero:
|
||||
with bg.column().classes("items-center text-center"):
|
||||
bg.label("Welcome to BadGUI").classes("text-h3 q-mb-md")
|
||||
bg.label("Beautiful UIs with Python").classes("text-h6 opacity-80 q-mb-lg")
|
||||
bg.button("Get Started").classes("q-btn-lg").props("color=white text-color=primary")
|
||||
|
||||
# Feature cards
|
||||
with bg.row().classes("q-col-gutter-lg q-mb-lg"):
|
||||
for i, feature in enumerate(["Fast", "Simple", "Powerful"]):
|
||||
with bg.column().classes("col-12 col-md-4"):
|
||||
with bg.column().classes("bg-white rounded-lg shadow-2 q-pa-lg items-center text-center") as card:
|
||||
card.style("border-top: 4px solid #1976d2")
|
||||
bg.label(feature).classes("text-h5 text-primary q-mb-md")
|
||||
bg.label(f"Feature {i+1} description").classes("text-body2 text-grey-7")
|
||||
|
||||
# Call to action
|
||||
with bg.row().classes("justify-center q-mt-xl"):
|
||||
bg.button("Learn More").classes("q-btn-lg q-btn-primary q-mr-md")
|
||||
bg.button("Examples").classes("q-btn-lg q-btn-outline")
|
||||
|
||||
bg.build("styled-demo")
|
||||
Reference in New Issue
Block a user