Folder System | vasak-desktop

Detailed guide to the project’s folder structure.

Root Structure#

graph TD Root["πŸ“ vasak-desktop/"] Root --> Src["πŸ“ src/
Vue.js frontend"] Root --> SrcTauri["πŸ“ src-tauri/
Rust backend"] Root --> IndexHTML["πŸ“„ index.html"] Root --> PackageJSON["πŸ“„ package.json"] Root --> TSConfig["πŸ“„ tsconfig.json"] Root --> ViteConfig["πŸ“„ vite.config.ts"] Root --> License["πŸ“„ LICENSE"] Root --> Readme["πŸ“„ README.md"] Root --> GitIgnore["πŸ“„ .gitignore"] style Root fill:#667eea,stroke:#764ba2,color:#fff style Src fill:#f093fb,stroke:#f5576c,color:#fff style SrcTauri fill:#4facfe,stroke:#00f2fe,color:#fff style IndexHTML fill:#fa709a,stroke:#fee140,color:#fff style PackageJSON fill:#30cfd0,stroke:#330867,color:#fff style TSConfig fill:#a8edea,stroke:#fed6e3,color:#333 style ViteConfig fill:#ffecd2,stroke:#fcb69f,color:#333 style License fill:#ff9a9e,stroke:#fecfef,color:#333 style Readme fill:#fbc2eb,stroke:#a6c1ee,color:#333 style GitIgnore fill:#fdcbf1,stroke:#e6dee9,color:#333

Frontend (src/)#

Frontend Root#

graph TD SrcRoot["πŸ“ src/"] SrcRoot --> AppVue["πŸ“„ App.vue
Root component"] SrcRoot --> MainTs["πŸ“„ main.ts
Entry point"] SrcRoot --> StyleCss["πŸ“„ style.css
Global styles"] SrcRoot --> ViteEnv["πŸ“„ vite-env.d.ts
Vite types"] SrcRoot --> AssetsDir["πŸ“ assets/
Static assets"] SrcRoot --> ComponentsDir["πŸ“ components/
Reusable components"] SrcRoot --> InterfacesDir["πŸ“ interfaces/
TS interfaces"] SrcRoot --> LayoutsDir["πŸ“ layouts/
Layouts/templates"] SrcRoot --> RoutesDir["πŸ“ routes/
Routing"] SrcRoot --> ToolsDir["πŸ“ tools/
Controllers"] SrcRoot --> TypesDir["πŸ“ types/
TS types"] SrcRoot --> ViewsDir["πŸ“ views/
Views/pages"] style SrcRoot fill:#667eea,stroke:#764ba2,color:#fff style AppVue fill:#f093fb,stroke:#f5576c,color:#fff style MainTs fill:#f093fb,stroke:#f5576c,color:#fff style StyleCss fill:#f093fb,stroke:#f5576c,color:#fff style ViteEnv fill:#f093fb,stroke:#f5576c,color:#fff style AssetsDir fill:#4facfe,stroke:#00f2fe,color:#fff style ComponentsDir fill:#4facfe,stroke:#00f2fe,color:#fff style InterfacesDir fill:#4facfe,stroke:#00f2fe,color:#fff style LayoutsDir fill:#4facfe,stroke:#00f2fe,color:#fff style RoutesDir fill:#4facfe,stroke:#00f2fe,color:#fff style ToolsDir fill:#4facfe,stroke:#00f2fe,color:#fff style TypesDir fill:#4facfe,stroke:#00f2fe,color:#fff style ViewsDir fill:#4facfe,stroke:#00f2fe,color:#fff

src/assets/#

Static assets (images, vectors):

graph TD Assets["πŸ“ src/assets/"] Assets --> Img["πŸ“ img/
Raster images"] Assets --> Vectors["πŸ“ vectors/
Vector graphics"] Img --> Logo["πŸ–ΌοΈ logo.png"] Img --> BgJpg["πŸ–ΌοΈ background.jpg"] Img --> ImgMore["πŸ“„ ..."] Vectors --> Icons["πŸ“ icons/"] Vectors --> Illustrations["πŸ“ illustrations/"] Vectors --> VecMore["πŸ“„ ..."] style Assets fill:#667eea,stroke:#764ba2,color:#fff style Img fill:#4facfe,stroke:#00f2fe,color:#fff style Vectors fill:#4facfe,stroke:#00f2fe,color:#fff style Logo fill:#43e97b,stroke:#38f9d7,color:#fff style BgJpg fill:#43e97b,stroke:#38f9d7,color:#fff style ImgMore fill:#43e97b,stroke:#38f9d7,color:#fff style Icons fill:#43e97b,stroke:#38f9d7,color:#fff style Illustrations fill:#43e97b,stroke:#38f9d7,color:#fff style VecMore fill:#43e97b,stroke:#38f9d7,color:#fff

Usage:

1
2
3
import logo from '@/assets/img/logo.png';
// Available in templates as:
// <img src="@/assets/img/logo.png" />

src/components/#

Reusable Vue components:

graph LR Components["πŸ“ src/components/"] Components --> SearchMenu["πŸ“„ SearchMenuComponent.vue
Menu search"] Components --> Areas["πŸ“ areas/
Large areas"] Components --> Buttons["πŸ“ buttons/
Buttons"] Components --> Cards["πŸ“ cards/
Cards"] Components --> Controls["πŸ“ controls/
Interactive controls"] Components --> Icon["πŸ“ icon/
Icons"] Components --> Widgets["πŸ“ widgets/
Reusable widgets"] Areas --> Audio["πŸ”Š audio/"] Areas --> Bluetooth["πŸ“± bluetooth/"] Areas --> Network["🌐 network/"] Areas --> Panel["πŸ“Š panel/"] Areas --> ControlCenter["βš™οΈ control-center/"] Areas --> Menu["🎯 menu/"] Areas --> Configuration["βš™οΈ configuration/"] Buttons --> BtnMenu["πŸ”˜ AppMenuButton.vue"] Buttons --> BtnCategory["πŸ”˜ CategoryMenuPill.vue"] Buttons --> BtnSidebar["πŸ”˜ ConfigSidebarButton.vue"] Buttons --> BtnSession["πŸ”˜ SessionButton.vue"] Buttons --> BtnBattery["πŸ”Œ TrayIconBattery.vue"] Cards --> CardMenu["🎴 AppMenuCard.vue"] Cards --> CardBT["🎴 BluetoothDeviceCard.vue"] Cards --> CardWeather["🎴 CurrentWeatherCard.vue"] Cards --> CardWiFi["🎴 NetworkWiFiCard.vue"] Controls --> CtrlAudio["🎚️ AudioDeviceSelector.vue"] Controls --> CtrlBT["🎚️ BluetoothControl.vue"] Controls --> CtrlBrightness["🎚️ BrightnessControl.vue"] Controls --> CtrlNetwork["🎚️ NetworkControl.vue"] Widgets --> ClockWidget["⏰ DesktopClockWidget.vue"] Widgets --> MusicWidget["🎡 MusicWidget.vue"] Widgets --> WeatherWidget["🌀️ WeatherWidget.vue"] style Components fill:#667eea,stroke:#764ba2,color:#fff style SearchMenu fill:#f093fb,stroke:#f5576c,color:#fff style Areas fill:#4facfe,stroke:#00f2fe,color:#fff style Buttons fill:#4facfe,stroke:#00f2fe,color:#fff style Cards fill:#4facfe,stroke:#00f2fe,color:#fff style Controls fill:#4facfe,stroke:#00f2fe,color:#fff style Icon fill:#4facfe,stroke:#00f2fe,color:#fff style Widgets fill:#4facfe,stroke:#00f2fe,color:#fff

Structure of a component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<template>
  <div class="component">
    <!-- Content -->
  </div>
</template>

<script setup lang="ts">
// Component logic
</script>

<style scoped>
/* Local styles */
</style>

src/interfaces/#

TypeScript interface definitions:

graph TD Interfaces["πŸ“ src/interfaces/"] Interfaces --> Battery["πŸ“„ battery.ts
Battery interface"] Interfaces --> Notifications["πŸ“„ notifications.ts
Notification interface"] Interfaces --> Tray["πŸ“„ tray.ts
Tray interface"] style Interfaces fill:#667eea,stroke:#764ba2,color:#fff style Battery fill:#43e97b,stroke:#38f9d7,color:#fff style Notifications fill:#43e97b,stroke:#38f9d7,color:#fff style Tray fill:#43e97b,stroke:#38f9d7,color:#fff

Example:

1
2
3
4
5
6
// battery.ts
export interface Battery {
  level: number;
  status: 'charging' | 'discharging' | 'full';
  timeRemaining?: number;
}

src/layouts/#

Page layouts/templates:

graph TD Layouts["πŸ“ src/layouts/"] Layouts --> ConfigLayout["πŸ“„ ConfigAppLayout.vue
Layout for the configuration"] style Layouts fill:#667eea,stroke:#764ba2,color:#fff style ConfigLayout fill:#f093fb,stroke:#f5576c,color:#fff

Usage: wraps views to keep the structure consistent

src/routes/#

Vue Router routing configuration:

graph TD Routes["πŸ“ src/routes/"] Routes --> IndexTs["πŸ“„ index.ts
Route configuration"] style Routes fill:#667eea,stroke:#764ba2,color:#fff style IndexTs fill:#4facfe,stroke:#00f2fe,color:#fff

Example:

1
2
3
4
5
export const routes = [
  { path: '/', component: DesktopView },
  { path: '/panel', component: PanelView },
  { path: '/menu', component: MenuView },
];

src/tools/#

Controllers and services (business logic):

graph TD Tools["πŸ“ src/tools/"] Tools --> BatteryCtrl["πŸ“„ battery.controller.ts
Battery logic"] Tools --> BluetoothCtrl["πŸ“„ bluetooth.controller.ts
Bluetooth logic"] Tools --> NetworkCtrl["πŸ“„ network.controller.ts
Network logic"] Tools --> TrayCtrl["πŸ“„ tray.controller.ts
Tray logic"] style Tools fill:#667eea,stroke:#764ba2,color:#fff style BatteryCtrl fill:#feca57,stroke:#ff9a56,color:#fff style BluetoothCtrl fill:#feca57,stroke:#ff9a56,color:#fff style NetworkCtrl fill:#feca57,stroke:#ff9a56,color:#fff style TrayCtrl fill:#feca57,stroke:#ff9a56,color:#fff

Responsibility:

  • Call backend commands
  • Process data
  • Handle complex logic

src/types/#

TypeScript type definitions:

graph TD Types["πŸ“ src/types/"] Types --> LibVasakTypes["πŸ“„ vue-libvasak.d.ts
Types from external libraries"] style Types fill:#667eea,stroke:#764ba2,color:#fff style LibVasakTypes fill:#fa709a,stroke:#f5576c,color:#fff

Usage: extends library types or defines global types

src/views/#

Main views/pages:

graph TD Views["πŸ“ views/"] Views --> ControlCenter["πŸ“„ ControlCenterView.vue
Control center"] Views --> Desktop["πŸ“„ DesktopView.vue
Desktop"] Views --> Menu["πŸ“„ MenuView.vue
App menu"] Views --> Panel["πŸ“„ PanelView.vue
Panel"] Views --> Applets["πŸ“ applets/
Mini-applications"] Views --> Apps["πŸ“ apps/
Applications"] Applets --> AudioApplet["πŸ“„ AudioAppletView.vue
Audio applet"] Applets --> BluetoothApplet["πŸ“„ BluetoothAppletView.vue
Bluetooth applet"] Applets --> NetworkApplet["πŸ“„ NetworkAppletView.vue
Network applet"] Apps --> Settings["πŸ“„ SettingsApp.vue
Settings application"] Apps --> FileManager["πŸ“„ FileManagerView.vue
File manager"] style Views fill:#667eea,stroke:#764ba2,color:#fff style ControlCenter fill:#f093fb,stroke:#f5576c,color:#fff style Desktop fill:#f093fb,stroke:#f5576c,color:#fff style Menu fill:#f093fb,stroke:#f5576c,color:#fff style Panel fill:#f093fb,stroke:#f5576c,color:#fff style Applets fill:#4facfe,stroke:#00f2fe,color:#fff style Apps fill:#4facfe,stroke:#00f2fe,color:#fff style AudioApplet fill:#43e97b,stroke:#38f9d7,color:#fff style BluetoothApplet fill:#43e97b,stroke:#38f9d7,color:#fff style NetworkApplet fill:#43e97b,stroke:#38f9d7,color:#fff style Settings fill:#43e97b,stroke:#38f9d7,color:#fff style FileManager fill:#43e97b,stroke:#38f9d7,color:#fff

Backend (src-tauri/)#

Tauri Structure#

graph LR TauriRoot["πŸ“ src-tauri/"] TauriRoot --> CargoToml["πŸ“„ Cargo.toml"] TauriRoot --> CargoLock["πŸ“„ Cargo.lock"] TauriRoot --> BuildRs["πŸ“„ build.rs"] TauriRoot --> TauriConf["πŸ“„ tauri.conf.json"] TauriRoot --> Capabilities["πŸ“ capabilities/"] TauriRoot --> Gen["πŸ“ gen/"] TauriRoot --> Icons["πŸ“ icons/"] TauriRoot --> Src["πŸ“ src/
Rust source code"] TauriRoot --> Target["πŸ“ target/
Build"] TauriRoot --> Tests["πŸ“ tests/"] Src --> LibRs["πŸ“„ lib.rs
Main modules"] Src --> MainRs["πŸ“„ main.rs
Entry point"] Src --> ErrorRs["πŸ“„ error.rs"] Src --> StructsRs["πŸ“„ structs.rs"] Src --> Commands["πŸ“ commands/
IPC handlers"] Src --> WindowMgr["πŸ“ window_manager/"] Src --> Audio["πŸ“ audio.rs"] Src --> DBus["πŸ“ dbus_service.rs"] Src --> Tray["πŸ“ tray/"] Src --> Utils["πŸ“ utils/"] Icons --> Icon128["πŸ–ΌοΈ 128x128.png"] Icons --> Icon256["πŸ–ΌοΈ 256x256.png"] Commands --> ModRs["πŸ“„ mod.rs"] Commands --> AudioCmd["πŸ“„ audio_commands.rs"] Commands --> BTCmd["πŸ“„ bluetooth_commands.rs"] WindowMgr --> WinCtrl["πŸ“„ window_controller.rs"] WindowMgr --> MonitorH["πŸ“„ monitor_handler.rs"] Tray --> TrayMod["πŸ“„ mod.rs"] Tray --> TrayIcon["πŸ“„ tray_icon.rs"] style TauriRoot fill:#667eea,stroke:#764ba2,color:#fff style CargoToml fill:#f093fb,stroke:#f5576c,color:#fff style CargoLock fill:#f093fb,stroke:#f5576c,color:#fff style BuildRs fill:#f093fb,stroke:#f5576c,color:#fff style TauriConf fill:#f093fb,stroke:#f5576c,color:#fff style Src fill:#4facfe,stroke:#00f2fe,color:#fff style Commands fill:#4facfe,stroke:#00f2fe,color:#fff style WindowMgr fill:#4facfe,stroke:#00f2fe,color:#fff style Tray fill:#4facfe,stroke:#00f2fe,color:#fff style Utils fill:#4facfe,stroke:#00f2fe,color:#fff

src-tauri/src/lib.rs#

Defines the main modules:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Core modules - core modules
mod app_url;
mod constants;
mod error;
mod structs;

// Feature modules - feature modules
mod applets;
mod audio;
mod brightness;
mod commands;
mod dbus_service;
mod eventloops;
mod menu_manager;
mod monitor_manager;
mod notifications;
mod tray;
mod utils;
mod window_manager;
mod windows_apps;

src-tauri/src/main.rs#

Simple entry point:

1
2
3
fn main() {
    vasak_desktop_lib::run()
}

src-tauri/src/commands/#

IPC command handlers:

1
2
3
4
5
6
7
8
9
// Reachable from the frontend
#[tauri::command]
pub fn get_volume() -> Result<u32, String> { ... }

#[tauri::command]
pub fn set_volume(level: u32) -> Result<(), String> { ... }

#[tauri::command]
pub async fn list_wifi_networks() -> Result<Vec<Network>, String> { ... }

src-tauri/src/window_manager/#

Window and monitor management:

1
2
3
4
5
6
7
// window_controller.rs - Window control
pub fn create_window() { ... }
pub fn close_window() { ... }

// monitor_handler.rs - Monitor handling
pub fn detect_monitors() { ... }
pub fn arrange_windows() { ... }

System Integration Modules#

1
2
3
4
5
6
audio.rs              - Volume control, devices
brightness.rs        - Screen brightness control
bluetooth.rs         - Pairing, device connection
network.rs           - WiFi scanning, connecting to networks
notifications.rs     - Showing system notifications
dbus_service.rs      - D-Bus initialization and handling

src-tauri/tauri.conf.json#

Tauri configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
  "build": {
    "beforeDevCommand": "bun run dev",
    "devUrl": "http://localhost:5173",
    "beforeBuildCommand": "bun run build",
    "devPath": "../src",
    "distDir": "../dist",
    "withGlobalTauri": false
  },
  "app": {
    "windows": [
      {
        "title": "Vasak Desktop",
        "label": "main",
        "width": 1024,
        "height": 768
      }
    ]
  }
}

Configuration (/.)#

package.json#

Defines the frontend scripts and dependencies:

1
2
3
4
5
6
7
8
{
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "tauri": "tauri"
  }
}

Available scripts:

  • bun run dev - Development
  • bun run build - Build
  • bun run preview - Preview the build
  • bun run tauri - Tauri CLI

tsconfig.json#

TypeScript configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

vite.config.ts#

Vite configuration:

1
2
3
4
5
// Controls:
// - The frontend build
// - Hot reload
// - Optimizations
// - Aliases

.env File#

Environment variables (if it exists):

1
2
VITE_API_URL=http://localhost:3000
VITE_DEBUG=true

Generated Directories (Do Not Commit)#

node_modules/#

Frontend dependencies (generated by bun install):

1
2
3
4
5
node_modules/
β”œβ”€β”€ vue/
β”œβ”€β”€ @tauri-apps/
β”œβ”€β”€ tailwindcss/
└── (hundreds more)

Ignored in: .gitignore

src-tauri/target/#

Rust build artifacts:

1
2
3
4
5
6
7
8
target/
β”œβ”€β”€ debug/
β”‚   β”œβ”€β”€ vasak-desktop      # Debug binary
β”‚   └── deps/
β”œβ”€β”€ release/
β”‚   β”œβ”€β”€ vasak-desktop      # Release binary
β”‚   └── deps/
└── (intermediate builds)

Ignored in: .gitignore

dist/#

Frontend build output:

1
2
3
4
5
6
dist/
β”œβ”€β”€ index.html
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ main.xxxxx.js     # Compiled JS
β”‚   └── main.xxxxx.css    # Compiled CSS
└── (other assets)

Generated by: npm run build

Naming Patterns#

Vue Components#

  • PascalCase: UserCard.vue, AudioControl.vue
  • The file must match the component name

Rust Files#

  • snake_case: audio_commands.rs, window_controller.rs
  • Modules match the file names

Import Paths#

1
2
3
4
5
6
7
// Frontend
import Component from '@/components/cards/UserCard.vue';
import { battery } from '@/tools/battery.controller';

// Backend (Rust)
use crate::audio::get_volume;
use crate::dbus_service::DbusService;

Structure Best Practices#

βœ… Do:#

  • Keep components small and focused
  • Group related things in folders
  • Use clear naming conventions
  • Document complex modules

❌ Don’t:#

  • Mix responsibilities in one file
  • Create purposeless “misc folders”
  • Ignore the established structure
  • Create excessive folder depth