How to Create a New UI Component
Relevant source files
The following files were used as context for generating this wiki page:This guide outlines the process for creating new UI components within the Scripty application. Scripty is a React-based desktop application built with Tauri and Vite. Components are functional, utilize React Hooks for state and lifecycle management, and are styled using Tailwind CSS. Global state is managed via Zustand.
Creating a new component involves defining its structure with JSX, managing its state, applying styles, and integrating it into the main application layout. Components may also interact with the Rust backend through Tauri's API to perform system-level operations, such as file I/O or running scripts.
1. Component Structure and File Organization
Components are organized within the src/components directory. A new component should be created as a .jsx file, typically named after the component itself (e.g., MyComponent.jsx).
The basic structure of a component is a JavaScript function that returns JSX. It should be exported as the default export.
Sources: src/components/Form/Form.jsx, src/components/DetailView/DetailView.jsx
Example Component Skeleton
// src/components/MyComponent.jsx
import { useState } from "react";
// Import other necessary hooks, libraries, or components
export default function MyComponent({ prop1, prop2 }) {
// Component logic, state, and effects go here
const [internalState, setInternalState] = useState(null);
return (
<div className="p-4 bg-main text-text">
<h1>My New Component</h1>
{/* More JSX structure */}
</div>
);
}
Sources: src/components/Form/Form.jsx:8-11, src/components/Form/Form.jsx:80-85
2. Integrating into the Application
Once a component is created, it must be imported and rendered within a parent component. The main application component, App.jsx, serves as the primary integration point for top-level UI elements.
The following diagram illustrates the component hierarchy originating from App.jsx.
This diagram shows the primary components rendered by App.jsx and their children.
Sources: src/App.jsx:2-10, src/components/Form/List.jsx:4-23
Components like Form, FormTag, and DetailView are rendered conditionally based on the application's state, managed by useState hooks within App.jsx. The AnimatePresence component from motion/react is used to animate their appearance and disappearance.
// src/App.jsx:54-55
function App() {
const [prewOpen, setPrewOpen] = useState(false);
const [popOpen, setPopOpen] = useState(false);
const [tagOpen, setTagOpen] = useState(false);
// ...
return (
<>
{/* ... */}
<AnimatePresence>
{popOpen && <Form key={1} isVisible={setPopOpen} />}
{tagOpen && <FormTag key={2} isVisible={setTagOpen} />}
{prewOpen && <DetailView key={3} setIsVisible={setPrewOpen} />}
</AnimatePresence>
{/* ... */}
</>
);
}
Sources: src/App.jsx:54-57, src/App.jsx:90-94
3. State Management with Zustand
Global application state is managed by a Zustand store defined in src/Hooks/useListStore.js. This store handles the list of scripts (items), tags, the currently selected item, and filtering logic. New components can access and manipulate this global state by using the useListStore hook.
Store Structure
The useListStore provides the following state and actions:
| Name | Type | Description |
|---|---|---|
items | Array | An array of script objects. |
tags | Array | An array of available tag strings. |
selectedItem | Object | null | The currently selected script object. |
filterTag | String | null | The tag used to filter the script list. |
addItem(item) | Function | Adds a new script item to the items array. |
addTag(tag) | Function | Adds a new tag to the tags array if it doesn't exist. |
removeItem(id) | Function | Removes a script item by its ID. |
selectItem(item) | Function | Sets the selectedItem. |
getFilteredItems() | Function | Returns a filtered list of items based on filterTag. |
Sources: src/Hooks/useListStore.js:28-79
The diagram below shows the data structure of the Zustand store.
This diagram outlines the state and actions available in the useListStore.
Sources: src/Hooks/useListStore.js:28-79
4. Styling with Tailwind CSS and Custom Themes
Styling is handled primarily through Tailwind CSS utility classes applied directly in the JSX. The project defines a custom theme with CSS variables for colors and other properties in src/App.css.
Custom Theme Variables
The root theme defines several CSS variables for consistent styling.
| Variable | Default Value | Description |
|---|---|---|
--main | #677397 | Primary UI color. |
--main2 | #5a6380 | Secondary UI color. |
--back | #515a77 | Background color. |
--acc | #857cbf | Accent color for buttons and highlights. |
--form | #363c4e | Background color for forms. |
--text | #ffffff | Primary text color. |
--radius | 15px 15px 15px 15px | Default border radius. |
Sources: src/App.css:21-29
To apply these styles, use Tailwind's arbitrary value support or the custom color names defined in the theme configuration. For example, bg-main applies the --main color.
<div className="bg-main text-text rad">
Styled Content
</div>
Sources: src/components/Form/List.jsx:10, src/App.css:5
5. Interacting with the Tauri Backend
Components can interact with the Rust backend by invoking commands defined in src-tauri/src/lib.rs. The @tauri-apps/api/core package provides the invoke function for this purpose.
Available Tauri Commands
| Command | Parameters | Description |
|---|---|---|
open_terminal | content: String | Opens a new PowerShell terminal and runs the provided content. |
open_admin_terminal | content: String | Opens a new PowerShell terminal with administrator privileges. |
run_sys_terminal | content: Option<String> | Runs a command in a SYSTEM-level PowerShell instance. |
read_ps1 | path: String | Reads the content of a .ps1 file and returns its path and content. |
Sources: src-tauri/src/lib.rs:29-70
Example: Reading a File
The Form.jsx component uses invoke("read_ps1", ...) to read a PowerShell script file selected by the user.
The sequence diagram below illustrates this process.
This diagram shows the flow of reading a file from the frontend, invoking the backend, and updating the state.
Sources: src/components/Form/Form.jsx:12-36, src/components/Form/Form.jsx:49-65, src-tauri/src/lib.rs:64-69
Summary
Creating a new UI component in Scripty is a structured process:
- Create the File: Add a new
.jsxfile insrc/components. - Build the Component: Write a functional React component, using JSX for structure and hooks for local state.
- Apply Styles: Use Tailwind CSS utility classes and the project's custom theme variables from
src/App.css. - Manage State: Interact with the global Zustand store (
useListStore) for shared application data. - Add Backend Logic: If needed, use
invoketo call commands defined in the Tauri Rust backend. - Integrate: Import and render the new component within
App.jsxor another parent component, often using conditional rendering based on application state.
By following these steps, new components will be consistent with the existing architecture and easily integrated into the application.
Sources: src/App.jsx, src/components/Form/Form.jsx, src/Hooks/useListStore.js