Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ https://github.com/user-attachments/assets/aab8d8e8-248f-46a1-919c-9b0601236ac1
- **[Cava](https://github.com/amnweb/yasb/wiki/(Widget)-Cava)**: Displays audio visualizer using Cava.
- **[Copilot](https://github.com/amnweb/yasb/wiki/(Widget)-Copilot)**: GitHub Copilot usage with a detailed menu showing statistics
- **[CPU](https://github.com/amnweb/yasb/wiki/(Widget)-CPU)**: Shows the current CPU usage.
- **[Clipboard](https://github.com/amnweb/yasb/wiki/(Widget)-Clipboard)**: A powerful, persistent clipboard manager for YASB.
- **[Clock](https://github.com/amnweb/yasb/wiki/(Widget)-Clock)**: Displays the current time and date.
- **[Custom](https://github.com/amnweb/yasb/wiki/(Widget)-Custom)**: Create a custom widget.
- **[Github](https://github.com/amnweb/yasb/wiki/(Widget)-Github)**: Shows notifications from GitHub.
Expand Down
163 changes: 163 additions & 0 deletions docs/widgets/(Widget)-Clipboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Clipboard Widget for YASB

A lightweight, modern clipboard manager for YASB that integrates directly with the native Windows Clipboard History (Win + V). This widget provides real-time access to your system's clip buffer without the need for heavy local storage or complex background monitoring.

**Note for Users:** This widget requires the following Python packages to interact with Windows APIs:
`pip install winrt-Windows.ApplicationModel.DataTransfer winrt-Windows.Foundation`

## Features
- **Native Windows Sync**: Syncs in real-time with your official Windows Clipboard History.
- **Search**: Built-in real-time search bar to filter through your text-based history.
- **Image Support**: Full support for previewing and re-copying images directly from the history list.
- **Long text preview**: Hover over a copied long piece of text to display complete text preview.
- **Zero-SDK Footprint**: Uses modular WinRT bindings to keep the installation under 10MB.

## Options

| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `type` | `string` | `yasb.clipboard.ClipboardWidget` | The widget class identifier. |
| `label` | `string` | `<span>\udb80\udd4d</span> {clipboard}` | Primary label format. Supports `{clipboard}` token. |
| `label_alt` | `string` | `{clipboard}` | Alternative label format (swapped on right-click). |
| `max_length` | `integer` | `30` | Max characters to display in the bar before truncation. |
| `max_history` | `integer` | `50` | Maximum number of history items to fetch from Windows. |
| `class_name` | `string` | `""` | Additional CSS class for the widget container. |
| `menu` | `dict` | (See Schema) | Configuration for the popup menu (blur, corners, alignment). |
| `icons` | `dict` | (See Schema) | Custom icons for clipboard, clear, and search. |

## Icons Configuration Defaults

| Key | Default | Description |
| :--- | :--- | :--- |
| `clipboard` | `\udb80\udd4d` | Main widget icon used on the bar and in the "Copied!" flash. |
| `clear` | `\uf1f8` | Global clear icon (Clears the system's unpinned history). |
| `search_clear` | `\uf00d` | Icon used for general UI elements. |

## Callbacks

| Function | Description |
| :--- | :--- |
| `toggle_menu` | Opens/closes the clipboard history popup (Scheduled asynchronously). |
| `toggle_label` | Switches display between `label` and `label_alt` on the bar. |
| `do_nothing` | No action. |

---


## Configuration Example

```yaml
clipboard:
type: "yasb.clipboard.ClipboardWidget"
options:
label: "<span>\udb80\udd4d</span> {clipboard}"
label_alt: "<span>CLIPBOARD:</span> {clipboard}"
max_length: 25
menu:
blur: false
round_corners: false
alignment: "right"
direction: "down"
callbacks:
on_left: "toggle_menu"
on_middle: "do_nothing"
on_right: "toggle_label"
```

## Styling

### Example CSS

```css
.clipboard-widget {
font-family: "JetBrainsMono Nerd Font", "Segoe UI Variable";
}
/* Widget on the bar */
.clipboard-widget .label {
padding: 0 6px;
color: var(--mauve);
}

/* Main Popup Container */
.clipboard-menu {
background-color: var(--bg-color1);
border: 1px solid var(--bg-color2);
border-radius: 10px;
padding: 8px;
}

/* Search Bar */
.clipboard-menu .search-input {
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 6px 10px;
margin-bottom: 6px;
color: var(--text1);
font-size: 13px;
}

.clipboard-menu .search-input:focus {
border: 1px solid var(--blue);
}

/* Global Clear Button */
.clipboard-menu .clear-button {
background-color: rgba(243, 139, 168, 0.1);
color: var(--red);
border-radius: 6px;
padding: 5px;
margin-bottom: 8px;
font-weight: bold;
font-size: 11px;
}

.clipboard-menu .clear-button:hover {
background-color: rgba(243, 139, 168, 0.2);
}

/* Scroll Area Styling */
.clipboard-menu .scroll-area {
background: transparent;
border: none;
}

/* Individual Clipboard Items (Buttons) */
.clipboard-menu .clipboard-item {
background-color: rgba(255, 255, 255, 0.03);
border: 1px solid transparent;
border-radius: 5px;
padding: 8px;
margin-bottom: 4px;
text-align: left;
color: var(--text1);
font-size: 12px;
}

.clipboard-menu .clipboard-item:hover {
background-color: rgba(255, 255, 255, 0.08);
border: 1px solid var(--bg-color2);
}

/* Image Item Specifics (if needed) */
.clipboard-menu .clipboard-item [icon] {
margin-right: 8px;
}

/* Scrollbar Styling (Optional but looks better) */
QScrollBar:vertical {
border: none;
background: transparent;
width: 4px;
}

QScrollBar::handle:vertical {
background: var(--bg-color2);
border-radius: 2px;
}

/* Styling for the temporary 'Copied!' flash */
.clipboard-widget .label {
transition: all 0.2s ease-in-out;
}
```
95 changes: 95 additions & 0 deletions src/core/validation/widgets/yasb/clipboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
DEFAULTS = {
"label": "<span>\udb80\udd4d</span> {clipboard}",
"label_alt": "{clipboard}",
"class_name": "",
"max_length": 30,
"max_history": 50,
"container_padding": {"top": 0, "left": 0, "bottom": 0, "right": 0},
"animation": {"enabled": True, "type": "fadeInOut", "duration": 200},
"menu": {
"blur": True,
"round_corners": True,
"round_corners_type": "normal",
"border_color": "System",
"alignment": "right",
"direction": "down",
"offset_top": 6,
"offset_left": 0,
"max_item_length": 50,
},
"icons": {
"clipboard": "\udb80\udd4d",
"clear": "\uf1f8",
"search_clear": "\uf00d",
},
"callbacks": {"on_left": "toggle_menu", "on_middle": "do_nothing", "on_right": "toggle_label"},
}

VALIDATION_SCHEMA = {
"label": {"type": "string", "default": DEFAULTS["label"]},
"label_alt": {"type": "string", "default": DEFAULTS["label_alt"]},
"class_name": {"type": "string", "required": False, "default": DEFAULTS["class_name"]},
"max_length": {"type": "integer", "required": False, "default": DEFAULTS["max_length"], "min": 5, "max": 100},
"max_history": {"type": "integer", "required": False, "default": DEFAULTS["max_history"], "min": 10, "max": 500},
"container_padding": {
"type": "dict",
"required": False,
"schema": {
"top": {"type": "integer", "default": DEFAULTS["container_padding"]["top"]},
"left": {"type": "integer", "default": DEFAULTS["container_padding"]["left"]},
"bottom": {"type": "integer", "default": DEFAULTS["container_padding"]["bottom"]},
"right": {"type": "integer", "default": DEFAULTS["container_padding"]["right"]},
},
"default": DEFAULTS["container_padding"],
},
"animation": {
"type": "dict",
"required": False,
"schema": {
"enabled": {"type": "boolean", "default": DEFAULTS["animation"]["enabled"]},
"type": {"type": "string", "default": DEFAULTS["animation"]["type"]},
"duration": {"type": "integer", "default": DEFAULTS["animation"]["duration"]},
},
"default": DEFAULTS["animation"],
},
"menu": {
"type": "dict",
"required": False,
"schema": {
"blur": {"type": "boolean", "default": DEFAULTS["menu"]["blur"]},
"round_corners": {"type": "boolean", "default": DEFAULTS["menu"]["round_corners"]},
"round_corners_type": {
"type": "string",
"default": DEFAULTS["menu"]["round_corners_type"],
"allowed": ["normal", "small"],
},
"border_color": {"type": "string", "default": DEFAULTS["menu"]["border_color"]},
"alignment": {"type": "string", "default": DEFAULTS["menu"]["alignment"]},
"direction": {"type": "string", "default": DEFAULTS["menu"]["direction"]},
"offset_top": {"type": "integer", "default": DEFAULTS["menu"]["offset_top"]},
"offset_left": {"type": "integer", "default": DEFAULTS["menu"]["offset_left"]},
"max_item_length": {"type": "integer", "default": DEFAULTS["menu"]["max_item_length"]},
},
"default": DEFAULTS["menu"],
},
"icons": {
"type": "dict",
"required": False,
"schema": {
"clipboard": {"type": "string", "default": DEFAULTS["icons"]["clipboard"]},
"clear": {"type": "string", "default": DEFAULTS["icons"]["clear"]},
"search_clear": {"type": "string", "default": DEFAULTS["icons"]["search_clear"]},
},
"default": DEFAULTS["icons"],
},
"callbacks": {
"type": "dict",
"required": False,
"schema": {
"on_left": {"type": "string", "default": DEFAULTS["callbacks"]["on_left"]},
"on_middle": {"type": "string", "default": DEFAULTS["callbacks"]["on_middle"]},
"on_right": {"type": "string", "default": DEFAULTS["callbacks"]["on_right"]},
},
"default": DEFAULTS["callbacks"],
},
}
Loading