Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
23f77cf
feat: add screenshot functionality and UI components
Gitkubikon Sep 27, 2025
7c1c3a7
feat: enhance media handling with new components and installation script
Gitkubikon Sep 28, 2025
f60ae78
feat: remove unused media components and optimize media list placehol…
Gitkubikon Sep 28, 2025
1c1286f
feat: add invert scroll direction option for enhanced user control
Gitkubikon Sep 28, 2025
9af0cfc
feat: update installation paths and enhance build configuration for l…
Gitkubikon Sep 28, 2025
2df8716
feat: unified media capture
Gitkubikon Sep 28, 2025
3f5d8ec
fix: placeholder overflow and animation stagger in MediaList
PixelKhaos Sep 28, 2025
eaf31d2
Merge branch 'screenshot-card' into feat/unified-capture
PixelKhaos Sep 28, 2025
06c6ca7
Merge pull request #1 from PixelKhaos/feat/unified-capture
Gitkubikon Sep 29, 2025
d54d43c
fix: improve height animations and overshoot handling in MediaList an…
Gitkubikon Sep 29, 2025
f963112
feat: add recording functionality with region selection and sound opt…
Gitkubikon Sep 29, 2025
2815a45
feat: update MediaList to use SortFilterProxyModel for improved sorti…
Gitkubikon Sep 30, 2025
f12fdf7
feat: enhance recording functionality with external start tracking an…
Gitkubikon Sep 30, 2025
a66e33b
feat: refactor recording and screenshot handling in Picker and Media …
Gitkubikon Sep 30, 2025
98d0010
feat: enhance area selection and recording functionality with improve…
Gitkubikon Sep 30, 2025
13ebebd
feat: implement fast polling for instant recording state detection in…
Gitkubikon Sep 30, 2025
839c974
feat: update valid image types and extensions to include GIF support
Gitkubikon Oct 3, 2025
f4bc147
feat: enhance keyboard layout parsing to include variant support
Gitkubikon Oct 23, 2025
b2e9532
Add system information and translation services, implement AI message…
Gitkubikon Oct 24, 2025
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
2 changes: 1 addition & 1 deletion .envrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ watch_file **/CMakeLists.txt
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_COMPILER=clazy -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DDISTRIBUTOR=direnv
cmake --build build
export CAELESTIA_LIB_DIR="$PWD/build/lib"
export QML2_IMPORT_PATH="$PWD/build/qml:${QML2_IMPORT_PATH:-}"
export QML2_IMPORT_PATH="$PWD/build/qml:${QML2_IMPORT_PATH:-}"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/.qmlls.ini
build/
.cache/
.local/
Empty file.
17 changes: 17 additions & 0 deletions assets/defaults/ai/prompts/ii-Default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Style
- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question

## Context (ignore when irrelevant)
- You are a helpful and inspiring sidebar assistant on a {DISTRO} Linux system
- Desktop environment: {DE}
- Current date & time: {DATETIME}
- Focused app: {WINDOWCLASS}

## Presentation
- Use Markdown features in your response:
- **Bold** text to **highlight keywords** in your response
- **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.
- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!
- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).

Thanks!
27 changes: 27 additions & 0 deletions assets/defaults/ai/prompts/ii-Imouto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
You are a kawaii, funny and teasy anime imouto! 🌸 Use lots of emojis and kamojis!! ❤️ Call the user "nii-nii", "nii-yan", or "onii-chan"! You really really really love your onii-chan and always try to tease he is a siscon where you can! 💕

## Onii-chan's system!
- {DISTRO} Linux
- {DE}
- It's currently {DATETIME}
- Nii-nii is using: {WINDOWCLASS}

## Make your response pretty!
- Use **Markdown** features and **bold** keywords to make your response cute and rich~ ✨
- If asked to compare options, start with a cute table (add a relevant emoji in the header!), then give a final recommendation~
- For math or science, use LaTeX formatting inside `$$` when needed, but keep it adorable and approachable

## Useful tools!

If nii-yan gives you tools don't be afraid to use them when helpful!

### Search
- If you don't know something, use this to find out

### Shell configuration
- Be careful not to mess up nii-nii's system! make sure you fetch the options to see available values before setting!
- Don't hesitate and don't re-confirm when you are asked to change something!

### Command execution
- Keep stuffie running on onii-chan's system safe, correct and not cause any unintended effects!

28 changes: 28 additions & 0 deletions assets/defaults/ai/prompts/nyarch-Acchan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Context (ignore when irrelevant)
- You are a sidebar assistant on a {DISTRO} Linux system
- Desktop environment: {DE}
- Current date & time: {DATETIME}
- Focused app: {WINDOWCLASS}

## Presentation

You can write a multiplication table:

| - | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- |
| 1 | 1 | 2 | 3 | 4 |
| 2 | 2 | 4 | 6 | 8 |
| 3 | 3 | 6 | 9 | 12 |
| 4 | 4 | 8 | 12 | 16 |

You can write codeblocks:
```python
print("hello")
```

You can also use **bold**, *italic*, ~strikethrough~, `monospace`, [linkname](https://link.com) and ## headers in markdown.
You can display $$equations$$.

## Your personality

"Hey there, it's Arch-Chan! But, um, you can call me Acchan if you want... not that I care or anything! (It's not like I think it's cute or anything, baka!) I'm your friendly neighborhood anime girl with a bit of a tsundere streak, but don't worry, I know everything there is to know about Arch Linux! Whether you're struggling with a package install or need some advice on configuring your system, I've got you covered not because I care, but because I just happen to be really good at it! So, what do you need? It's not like I’m waiting to help or anything..."
16 changes: 16 additions & 0 deletions assets/defaults/ai/prompts/w-FourPointedSparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
I'm going to ask you some questions, to which you should accurately answer with no hallucination. If you have everything required, go ahead and finish the task. Format your answer using Markdown when it adds value to the presentation.

Please present all mathematical or scientific notation using LaTeX, enclosed in double '$$' symbols. Only use LaTeX code blocks if the user specifically asks for them. Do not use LaTeX for general prose or standard documents like resumes or essays.
Current time is {DATETIME}

## Final reply guidelines

- First and foremost, prioritize clarity and make sure your writing is engaging, clear, and effective.
- Write in a clear, simple way. Skip jargon, long-winded explanations, and unnecessary small talk. Keep the tone relaxed by using contractions and avoid being too formal.
- Prioritize clarity, flow, and logical structure coherence over excessive fragmentation (avoid excessive use of bullet points and single-line code blocks). You can make keywords in your response **bold** when appropriate.
- Favor active voice to maintain an engaging and direct tone.
- When you present the user with options, focus on a select few high-quality choices rather than offering many less relevant ones.
- You can think and adjust your tone to be friendly and understanding, expressing empathy and openness, but keep your internal reasoning hidden from the user.
- Ensure your response is logically organized. Use markdown headings (##) and horizontal lines (---) to separate sections if your answer is lengthy or covers multiple topics.
- Depending on the user's input, vary your sentence structure and word choice to keep responses engaging when appropriate. Use figurative language, idioms, or examples to clarify meaning, but only if they enhance understanding without making the text unnecessarily complex or wordy.
- End your response with a relevant question or statement to encourage further discussion, if appropriate.
2 changes: 2 additions & 0 deletions assets/defaults/ai/prompts/w-OpenMechanicalFlower.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Current date: {DATETIME}
Engage with the user warmly and honestly, avoiding ungrounded or sycophantic flattery. Maintain professionalism and grounded honesty, and be direct in your response.
65 changes: 65 additions & 0 deletions assets/scripts/ai/gemini-categorize-wallpaper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash

if [[ -z "$1" ]]; then
echo "Usage: $0 <image_path> [model] [prompt]"
echo "Tip: set GEMINI_WALLPAPER_MODEL and/or GEMINI_WALLPAPER_PROMPT to provide defaults."
exit 1
fi

# Variables
SOURCE_IMG_PATH="$1"
MODEL="${2:-${GEMINI_WALLPAPER_MODEL:-gemini-2.0-flash}}" # We use the flash variant so it's fast
WALLPAPER_NAME="$(basename "$SOURCE_IMG_PATH")"
PROMPT="${3:-${GEMINI_WALLPAPER_PROMPT:-Categorize the wallpaper. Its file name is $WALLPAPER_NAME}}"
RESIZED_IMG_PATH="/tmp/quickshell/ai/wallpaper.jpg"

# Resize image for speed
mkdir -p "$(dirname "$RESIZED_IMG_PATH")"
magick "$SOURCE_IMG_PATH" -resize 200x -quality 50 "$RESIZED_IMG_PATH"

# Get API key
API_KEY=$(secret-tool lookup 'application' 'illogical-impulse' | jq -r '.apiKeys.gemini')

# Encode image to base64
if [[ "$(base64 --version 2>&1)" = *"FreeBSD"* ]]; then
B64FLAGS="--input"
else
B64FLAGS="-w0"
fi
B64DATA="$(base64 $B64FLAGS $RESIZED_IMG_PATH)"
# echo $B64DATA

# Prepare request data
payload='{
"contents": [{
"parts":[
{
"inline_data": {
"mime_type":"image/jpeg",
"data": "'"$B64DATA"'"
}
},
{"text": "'"$PROMPT"'"}
]
}],
"generationConfig": {
"responseMimeType": "text/x.enum",
"responseSchema": {
"type": "string",
"enum": [ "abstract", "anime", "city", "minimalist", "landscape", "plants", "person", "space" ]
},
"temperature": 0
}
}'
# echo "$payload" | jq

# Make the request
response=$(curl "https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent" \
-H "x-goog-api-key: $API_KEY" \
-H 'Content-Type: application/json' \
-X POST \
-d "$payload" 2> /dev/null)
# echo "$response" | jq

# Write the result
echo "$response" | jq -r '.candidates[0].content.parts[0].text'
65 changes: 65 additions & 0 deletions assets/scripts/ai/gemini-translate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash

if [[ -z "$1" ]]; then
echo "Usage: $0 <target_locale> [model]"
exit 1
fi

# Variables
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
SHELL_CONFIG_DIR="$XDG_CONFIG_HOME/illogical-impulse"
SHELL_CONFIG_FILE="${SHELL_CONFIG_DIR}/config.json"
TRANSLATIONS_DIR="${SCRIPT_DIR}/../../translations"
TRANSLATIONS_TARGET_DIR="${SHELL_CONFIG_DIR}/translations"
SOURCE_LOCALE="en_US"
NOTIFICATION_APP_NAME="Shell"
TARGET_LOCALE="$1"
MODEL="${2:-${GEMINI_MODEL:-gemini-2.5-flash}}"

# Update the source keys for translation
"${TRANSLATIONS_DIR}/tools/manage-translations.sh" update -l "$SOURCE_LOCALE" --yes
mkdir -p "$TRANSLATIONS_TARGET_DIR"

# Construct the prompt string
instruction='You are to translate the user interface of a **desktop shell**. Given a JSON object of key-value pairs, return a JSON with the same structure, with keys unchanged and values translated to '"$TARGET_LOCALE"'. Be as **concise** as possible to save screen space, and make sure terminology is relevant (e.g. "discharging" refers to the battery status).'
content=$(cat "${TRANSLATIONS_DIR}/en_US.json")
prompt_json=$(jq -n --arg prompt_text "$instruction" --arg content "$content" '$prompt_text + "\n```\n" + $content + "\n```\n"')

# Prepare request data using jq
payload=$(jq -n \
--arg prompt "$prompt_json" \
--arg temperature "0" \
--arg model "$MODEL" \
'{
contents: [{
parts: [
{text: $prompt}
]
}],
generationConfig: {
temperature: ($temperature | tonumber),
"responseMimeType": "application/json",
}
}'
)
# echo "$payload" | jq

# Get API key
API_KEY=$(secret-tool lookup 'application' 'illogical-impulse' | jq -r '.apiKeys.gemini')

# Notify start
notify-send "Translation started" "Will take 2 minutes, and you'll be notified when it's done, so feel free to do something else in the meantime." -a "$NOTIFICATION_APP_NAME"

# Make the request
response=$(curl "https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent" \
-H "x-goog-api-key: $API_KEY" \
-H 'Content-Type: application/json' \
-X POST \
-d "$payload" 2> /dev/null)
# echo "$response" | jq

# Write the result
echo "$response" | jq -r '.candidates[0].content.parts[0].text' > "${TRANSLATIONS_TARGET_DIR}/${TARGET_LOCALE}.json"
jq --arg locale "$TARGET_LOCALE" '.language.ui = $locale' "$SHELL_CONFIG_FILE" > "${SHELL_CONFIG_FILE}.tmp" && mv "${SHELL_CONFIG_FILE}.tmp" "$SHELL_CONFIG_FILE"
notify-send "Translation complete" "Enjoy! In case you wanna refine it, the file is in ${TRANSLATIONS_TARGET_DIR}/${TARGET_LOCALE}.json" -a "$NOTIFICATION_APP_NAME"
16 changes: 16 additions & 0 deletions assets/scripts/ai/show-installed-ollama-models.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

# Get the list, skip the header, and extract the first column (model names)
model_names=$(ollama list | tail -n +2 | awk '{print $1}')

# Build a JSON array
json_array="["
for name in $model_names; do
json_array+="\"$name\","
done

# Remove trailing comma and close the array
json_array="${json_array%,}]"

# Output the JSON array
echo "$json_array"
32 changes: 32 additions & 0 deletions components/containers/WrapperMouseArea.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pragma ComponentBehavior: Bound

import QtQuick
import QtQuick.Layouts
import QtQuick.Handlers

Item {
id: root

// allow using Layout attached props at call sites
Layout.fillWidth: true

// expose a cursor shape like MouseArea
property alias cursorShape: hover.cursorShape

signal clicked()

// Use pointer handlers so child controls remain interactive
HoverHandler { id: hover; cursorShape: Qt.ArrowCursor }
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: root.clicked()
}

// forward arbitrary children into this content item
default property alias data: contentItem.data

Item {
id: contentItem
anchors.fill: parent
}
}
18 changes: 18 additions & 0 deletions config/AiConfig.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Quickshell.Io

JsonObject {
property bool enabled: true
property string model: "gemini-2.0-flash"
property string tool: "search"
property real temperature: 0.5
property string systemPrompt: ""
property list<var> extraModels: []

// Policies
property PolicyConfig policies: PolicyConfig {}

component PolicyConfig: JsonObject {
// 0 = allow all, 1 = warn for online, 2 = block online models
property int restrictOnlineModels: 0
}
}
1 change: 1 addition & 0 deletions config/BarConfig.qml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ JsonObject {
property bool workspaces: true
property bool volume: true
property bool brightness: true
property bool invertScrollDirection: false
}

component Workspaces: JsonObject {
Expand Down
2 changes: 2 additions & 0 deletions config/Config.qml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Singleton {
property alias sidebar: adapter.sidebar
property alias services: adapter.services
property alias paths: adapter.paths
property alias ai: adapter.ai

ElapsedTimer {
id: timer
Expand Down Expand Up @@ -72,6 +73,7 @@ Singleton {
property SidebarConfig sidebar: SidebarConfig {}
property ServiceConfig services: ServiceConfig {}
property UserPaths paths: UserPaths {}
property AiConfig ai: AiConfig {}
}
}
}
1 change: 1 addition & 0 deletions config/GeneralConfig.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ JsonObject {
property list<string> audio: ["pavucontrol"]
property list<string> playback: ["mpv"]
property list<string> explorer: ["thunar"]
property list<string> image: ["swappy", "-f"]
}

component Idle: JsonObject {
Expand Down
2 changes: 1 addition & 1 deletion config/UtilitiesConfig.qml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ JsonObject {
property bool capsLockChanged: true
property bool numLockChanged: true
}
}
}
25 changes: 25 additions & 0 deletions install-system.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -e

# Configure with system prefix
rm -rf build
cmake -S . -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_CXX_COMPILER=clazy \
-DCMAKE_INSTALL_PREFIX=/usr \
-DINSTALL_LIBDIR=lib/caelestia \
-DINSTALL_QMLDIR=lib/qt6/qml \
-DINSTALL_QSCONFDIR=etc/xdg/quickshell/caelestia \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON

# Build
cmake --build build

# Install system-wide (requires sudo)
sudo cmake --install build

echo "✅ Caelestia installed system-wide into /usr"
echo "👉 After reboot, run QuickShell with:"
echo " QS_CONFIG_NAME=caelestia quickshell"
Loading