From 327608cc36b5d7532205c8bf14d1b19c377005b5 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Sat, 29 Nov 2025 23:09:58 +0100 Subject: [PATCH 1/7] add normal layout keyboard --- src-tauri/src/lib.rs | 27 +++++++++++++++++++- src/app/app.component.css | 47 ++++++++++++++++++++++++++++++++++ src/app/app.component.html | 52 ++++++++++++++++++++++++++++++++++++++ src/app/app.component.ts | 37 +++++++++++++++++++++++++-- 4 files changed, 160 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f9a0b96..a60f0d7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,5 @@ use enigo::{Direction::Click, Enigo, Key, Keyboard, Settings}; +#[cfg(target_os = "linux")] use std::ptr; use tauri::Manager; @@ -10,10 +11,34 @@ fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } +#[tauri::command] +fn send_key(key: String) -> Result<(), String> { + let mut enigo = Enigo::new(&Settings::default()).map_err(|e| format!("Enigo error: {}", e))?; + + if key.len() == 1 { + // Single letter (a-z, A-Z) + enigo.key(Key::Unicode(key.chars().next().unwrap()), Click) + .map_err(|e| format!("Key error: {}", e))?; + } else { + // Special keys + match key.as_str() { + "Enter" => enigo.key(Key::Return, Click) + .map_err(|e| format!("Key error: {}", e))?, + "Space" => enigo.key(Key::Space, Click) + .map_err(|e| format!("Key error: {}", e))?, + "Backspace" => enigo.key(Key::Backspace, Click) + .map_err(|e| format!("Key error: {}", e))?, + _ => return Err("Unknown key".to_string()), + } + } + Ok(()) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .setup(|app| { + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] let window = app.get_webview_window("main").unwrap(); #[cfg(target_os = "linux")] { @@ -40,7 +65,7 @@ pub fn run() { Ok(()) }) .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![greet]) + .invoke_handler(tauri::generate_handler![greet, send_key]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src/app/app.component.css b/src/app/app.component.css index c68d181..20354c4 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -110,3 +110,50 @@ button { background-color: #0f0f0f69; } } + +.keyboard { + display: flex; + flex-direction: column; + gap: 8px; + padding: 20px; + background: #f5f5f5; + border-radius: 10px; +} + +.keyboard-row { + display: flex; + gap: 6px; + justify-content: center; +} + +.key-button { + min-width: 60px; + height: 60px; + font-size: 20px; + font-weight: bold; + border: 2px solid #ddd; + border-radius: 8px; + background: rgb(58, 56, 56); + cursor: pointer; + transition: all 0.1s; +} + +.key-button:hover { + background: #979797; + border-color: #999; +} + +.key-button:active { + background: #d0d0d0; + transform: scale(0.95); +} + +.shift-key.active { + background: #4CAF50; + color: white; + border-color: #45a049; +} + +.space-key { + min-width: 300px; +} diff --git a/src/app/app.component.html b/src/app/app.component.html index e447606..b5d1d17 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -16,4 +16,56 @@

{{ greetingMessage }}

+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + + + + +
+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index ad8d5ff..5f66c57 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterOutlet } from '@angular/router'; import { invoke } from "@tauri-apps/api/core"; @@ -10,9 +10,16 @@ import { invoke } from "@tauri-apps/api/core"; templateUrl: './app.component.html', styleUrl: './app.component.css' }) -export class AppComponent { +export class AppComponent implements AfterViewInit { greetingMessage = ""; + @ViewChild('greetInput') inputElement!: ElementRef; + + ngAfterViewInit() { + // Beim Start fokussieren + this.inputElement.nativeElement.focus(); + } + greet(event: SubmitEvent, name: string): void { event.preventDefault(); @@ -21,4 +28,30 @@ export class AppComponent { this.greetingMessage = text; }); } + + // Keyboard Layout + row1 = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']; + row2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']; + row3 = ['Z', 'X', 'C', 'V', 'B', 'N', 'M']; + + shiftActive = false; + + toggleShift(): void { + this.shiftActive = !this.shiftActive; + } + + async sendKey(key: string): Promise { + this.inputElement.nativeElement.focus(); + + let finalKey = key; + if (key.length === 1) { + finalKey = this.shiftActive ? key.toUpperCase() : key.toLowerCase(); + } + + await invoke("send_key", { key: finalKey }); + + if (this.shiftActive && key.length === 1) { + this.shiftActive = false; + } + } } From 2ad8b7fffb187fe2e9ae5b619e32390ad0bae979 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Mon, 1 Dec 2025 16:40:31 +0100 Subject: [PATCH 2/7] remove initial html code --- src/app/app.component.html | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index b5d1d17..e654b54 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,16 +1,4 @@
-

Welcome to Tauri + Angular!

- - -

Click on the logos to learn more about the frameworks

-
@@ -44,7 +32,7 @@ - +
- +
- +
+ + +
+ +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5f66c57..9c357c2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -29,16 +29,33 @@ export class AppComponent implements AfterViewInit { }); } - // Keyboard Layout - row1 = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']; - row2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']; - row3 = ['Z', 'X', 'C', 'V', 'B', 'N', 'M']; + // Keyboard Layout State + currentLayout: 'qwerty' | 'dvorak' = 'qwerty'; + + // QWERTY Layout + qwertyRow1 = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']; + qwertyRow2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']; + qwertyRow3 = ['Z', 'X', 'C', 'V', 'B', 'N', 'M', ",", "."]; + + // DVORAK Layout + dvorakRow1 = [',', '.', 'P', 'Y', 'F', 'G', 'C', 'R', 'L']; + dvorakRow2 = ['A', 'O', 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S']; + dvorakRow3 = ['Q', 'J', 'K', 'X', 'B', 'M', 'W', 'V', 'Z']; shiftActive = false; + + // Getters for current layout + get row1() { return this.currentLayout === 'qwerty' ? this.qwertyRow1 : this.dvorakRow1; } + get row2() { return this.currentLayout === 'qwerty' ? this.qwertyRow2 : this.dvorakRow2; } + get row3() { return this.currentLayout === 'qwerty' ? this.qwertyRow3 : this.dvorakRow3; } toggleShift(): void { this.shiftActive = !this.shiftActive; } + + switchLayout(): void { + this.currentLayout = this.currentLayout === 'qwerty' ? 'dvorak' : 'qwerty'; + } async sendKey(key: string): Promise { this.inputElement.nativeElement.focus(); From ef740ca9ddffdd4c7677013218bc0ac1e7bb74a9 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Thu, 4 Dec 2025 18:54:10 +0100 Subject: [PATCH 4/7] add first implementation of circle keyboard and better switching of keyboards --- src-tauri/src/lib.rs | 31 ++- src/app/app.component.html | 80 +++----- src/app/app.component.ts | 46 ++--- .../keyboards/circle-keyboard.component.ts | 190 ++++++++++++++++++ .../keyboards/dvorak-keyboard.component.ts | 68 +++++++ .../keyboards/qwerty-keyboard.component.ts | 68 +++++++ 6 files changed, 393 insertions(+), 90 deletions(-) create mode 100644 src/app/keyboards/circle-keyboard.component.ts create mode 100644 src/app/keyboards/dvorak-keyboard.component.ts create mode 100644 src/app/keyboards/qwerty-keyboard.component.ts diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a60f0d7..bb4c272 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,4 @@ -use enigo::{Direction::Click, Enigo, Key, Keyboard, Settings}; +use enigo::{Direction, Enigo, Key, Keyboard, Settings}; #[cfg(target_os = "linux")] use std::ptr; use tauri::Manager; @@ -6,8 +6,8 @@ use tauri::Manager; // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ #[tauri::command] fn greet(name: &str) -> String { - let mut enigo = Enigo::new(&Settings::default()).unwrap(); - enigo.key(Key::Unicode('a'), Click); + // let mut enigo = Enigo::new(&Settings::default()).unwrap(); + // enigo.key(Key::Unicode('a'), Click); format!("Hello, {}! You've been greeted from Rust!", name) } @@ -16,17 +16,30 @@ fn send_key(key: String) -> Result<(), String> { let mut enigo = Enigo::new(&Settings::default()).map_err(|e| format!("Enigo error: {}", e))?; if key.len() == 1 { - // Single letter (a-z, A-Z) - enigo.key(Key::Unicode(key.chars().next().unwrap()), Click) - .map_err(|e| format!("Key error: {}", e))?; + let ch = key.chars().next().unwrap(); + + // Check if uppercase letter + if ch.is_uppercase() && ch.is_alphabetic() { + // Send Shift + lowercase letter + enigo.key(Key::Shift, Direction::Press) + .map_err(|e| format!("Shift press error: {}", e))?; + enigo.key(Key::Unicode(ch.to_lowercase().next().unwrap()), Direction::Click) + .map_err(|e| format!("Key error: {}", e))?; + enigo.key(Key::Shift, Direction::Release) + .map_err(|e| format!("Shift release error: {}", e))?; + } else { + // Send character as-is (lowercase or non-letter) + enigo.key(Key::Unicode(ch), Direction::Click) + .map_err(|e| format!("Key error: {}", e))?; + } } else { // Special keys match key.as_str() { - "Enter" => enigo.key(Key::Return, Click) + "Enter" => enigo.key(Key::Return, Direction::Click) .map_err(|e| format!("Key error: {}", e))?, - "Space" => enigo.key(Key::Space, Click) + "Space" => enigo.key(Key::Space, Direction::Click) .map_err(|e| format!("Key error: {}", e))?, - "Backspace" => enigo.key(Key::Backspace, Click) + "Backspace" => enigo.key(Key::Backspace, Direction::Click) .map_err(|e| format!("Key error: {}", e))?, _ => return Err("Unknown key".to_string()), } diff --git a/src/app/app.component.html b/src/app/app.component.html index f641c00..3585f69 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -3,65 +3,35 @@ +

{{ greetingMessage }}

-
- -
-
- -
- -
+ + + - -
- -
+ + - -
- - - - - - - -
- - -
- -
-
+ + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 9c357c2..0597add 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -2,62 +2,56 @@ import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterOutlet } from '@angular/router'; import { invoke } from "@tauri-apps/api/core"; +import { QwertyKeyboardComponent } from './keyboards/qwerty-keyboard.component'; +import { DvorakKeyboardComponent } from './keyboards/dvorak-keyboard.component'; +import { CircleKeyboardComponent } from './keyboards/circle-keyboard.component'; @Component({ selector: 'app-root', standalone: true, - imports: [CommonModule, RouterOutlet], + imports: [ + CommonModule, + RouterOutlet, + QwertyKeyboardComponent, + DvorakKeyboardComponent, + CircleKeyboardComponent + ], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent implements AfterViewInit { greetingMessage = ""; + currentLayout: 'qwerty' | 'dvorak' | 'circle' = 'qwerty'; + shiftActive = false; @ViewChild('greetInput') inputElement!: ElementRef; ngAfterViewInit() { - // Beim Start fokussieren this.inputElement.nativeElement.focus(); } greet(event: SubmitEvent, name: string): void { event.preventDefault(); - - // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ invoke("greet", { name }).then((text) => { this.greetingMessage = text; }); } - // Keyboard Layout State - currentLayout: 'qwerty' | 'dvorak' = 'qwerty'; - - // QWERTY Layout - qwertyRow1 = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']; - qwertyRow2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']; - qwertyRow3 = ['Z', 'X', 'C', 'V', 'B', 'N', 'M', ",", "."]; - - // DVORAK Layout - dvorakRow1 = [',', '.', 'P', 'Y', 'F', 'G', 'C', 'R', 'L']; - dvorakRow2 = ['A', 'O', 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S']; - dvorakRow3 = ['Q', 'J', 'K', 'X', 'B', 'M', 'W', 'V', 'Z']; - - shiftActive = false; - - // Getters for current layout - get row1() { return this.currentLayout === 'qwerty' ? this.qwertyRow1 : this.dvorakRow1; } - get row2() { return this.currentLayout === 'qwerty' ? this.qwertyRow2 : this.dvorakRow2; } - get row3() { return this.currentLayout === 'qwerty' ? this.qwertyRow3 : this.dvorakRow3; } - toggleShift(): void { this.shiftActive = !this.shiftActive; } switchLayout(): void { - this.currentLayout = this.currentLayout === 'qwerty' ? 'dvorak' : 'qwerty'; + if (this.currentLayout == 'qwerty'){ + this.currentLayout = 'dvorak'; + } else if (this.currentLayout == 'dvorak'){ + this.currentLayout = 'circle'; + } else if (this.currentLayout == 'circle'){ + this.currentLayout = 'qwerty'; + } } - async sendKey(key: string): Promise { + async handleKeyPress(key: string): Promise { this.inputElement.nativeElement.focus(); let finalKey = key; diff --git a/src/app/keyboards/circle-keyboard.component.ts b/src/app/keyboards/circle-keyboard.component.ts new file mode 100644 index 0000000..7494420 --- /dev/null +++ b/src/app/keyboards/circle-keyboard.component.ts @@ -0,0 +1,190 @@ +import { Component, Output, EventEmitter, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +//TODO: Second and fourth ring of keys + +@Component({ + selector: 'app-circle-keyboard', + standalone: true, + imports: [CommonModule], + template: ` +
+ +
+ + + + + + +
+ + + + + +
+ `, + styles: [` + .circle-keyboard-container { + position: relative; + width: 400px; + height: 400px; + margin: 50px auto; + } + + /* Center Button Container */ + .center-button-container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 140px; + height: 140px; + z-index: 1; + } + + /* Center Button Sections */ + .center-section { + position: absolute; + background: white; + font-size: 20px; + font-weight: bold; + cursor: pointer; + transition: background 0.2s; + border: 2px solid #ddd; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + + /* Top-left: Backspace (triangle) */ + .top-left{ + top: 0; + left: 0; + width: 70px; + height: 70px; + border-radius: 70px 0 0 0; + } + + /* Top-right: Enter*/ + .top-right { + top: 0; + right: 0; + width: 70px; + height: 70px; + border-radius: 0 70px 0 0; + } + + /* Bottom: Space */ + .bottom-left { + bottom: 0; + left: 0; + width: 70px; + height: 70px; + border-radius: 0 0 0 70px; + } + + .bottom-left.active { + background: #4CAF50 !important; + color: white; + border-color: #45a049; + } + + .bottom-right { + bottom: 0; + right: 0; + width: 70px; + height: 70px; + border-radius: 0 0 70px 0; + } + + /* 8 Circle Buttons */ + .circle-button { + position: absolute; + top: 50%; + left: 50%; + width: 60px; + height: 60px; + margin: -30px 0 0 -30px; + border-radius: 50%; + border: 2px solid #ddd; + background: white; + font-size: 20px; + font-weight: bold; + cursor: pointer; + transition: background 0.2s, border-color 0.2s; + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + z-index: 1; + } + + .third-ring { + width: 40px; + height: 40px; + margin: -20px 0 0 -20px; + } + + .fourth-ring { + width: 30px; + height: 30px; + margin: -20px 0 0 -20px; + } + + .circle-button:hover, .center-section:hover { + background: #e8e8e8; + border-color: #999; + } + + .circle-button:active, .center-section:active { + background: #d0d0d0; + } + `] +}) +export class CircleKeyboardComponent { + @Input() shiftActive = false; + @Output() keyPressed = new EventEmitter(); + @Output() shiftToggled = new EventEmitter(); + + // 8 keys arranged in circle + circleKeysFirst = ['E', 'T', 'A', 'O', 'N', 'I', 'H', 'S']; + circleKeysSecond = ['R', 'L', 'D', 'U', 'C', 'M', 'W', 'Y']; + circleKeysThird = ['F', 'G', 'P', 'B', 'V', 'K', 'J', 'X']; + circleKeysFourth = ['Q', 'Z', ',', '.']; + + // Calculate position for each button in circle + getCirclePositionFromTop(index: number, radius: number): string { + const angle = (index * 45) - 90; // Start from top (0°), 45° apart + const angleRad = (angle * Math.PI) / 180; + const x = Math.cos(angleRad) * radius; + const y = Math.sin(angleRad) * radius; + return `translate(${x}px, ${y}px)`; + } +} diff --git a/src/app/keyboards/dvorak-keyboard.component.ts b/src/app/keyboards/dvorak-keyboard.component.ts new file mode 100644 index 0000000..0c18a98 --- /dev/null +++ b/src/app/keyboards/dvorak-keyboard.component.ts @@ -0,0 +1,68 @@ +import { Component, Output, EventEmitter, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-dvorak-keyboard', + standalone: true, + imports: [CommonModule], + template: ` +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ + + + + + + +
+
+ `, + styleUrl: '../app.component.css' +}) +export class DvorakKeyboardComponent { + @Input() shiftActive = false; + @Output() keyPressed = new EventEmitter(); + @Output() shiftToggled = new EventEmitter(); + + row1 = [',', '.', 'P', 'Y', 'F', 'G', 'C', 'R', 'L']; + row2 = ['A', 'O', 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S']; + row3 = ['Q', 'J', 'K', 'X', 'B', 'M', 'W', 'V', 'Z']; +} diff --git a/src/app/keyboards/qwerty-keyboard.component.ts b/src/app/keyboards/qwerty-keyboard.component.ts new file mode 100644 index 0000000..a6e616d --- /dev/null +++ b/src/app/keyboards/qwerty-keyboard.component.ts @@ -0,0 +1,68 @@ +import { Component, Output, EventEmitter, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-qwerty-keyboard', + standalone: true, + imports: [CommonModule], + template: ` +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ + + + + + + +
+
+ `, + styleUrl: '../app.component.css' +}) +export class QwertyKeyboardComponent { + @Input() shiftActive = false; + @Output() keyPressed = new EventEmitter(); + @Output() shiftToggled = new EventEmitter(); + + row1 = ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']; + row2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']; + row3 = ['Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.']; +} From 3512bf0fac3be0fd04780a00cadc169728677a8d Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Fri, 5 Dec 2025 01:18:54 +0100 Subject: [PATCH 5/7] finished circle keyboard implementation and update window size --- src-tauri/tauri.conf.json | 6 +- src/app/app.component.css | 9 +- .../keyboards/circle-keyboard.component.css | 147 +++++++++++++++++ .../keyboards/circle-keyboard.component.ts | 152 ++++-------------- 4 files changed, 187 insertions(+), 127 deletions(-) create mode 100644 src/app/keyboards/circle-keyboard.component.css diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index b077b11..051b909 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -14,7 +14,11 @@ { "title": "keeb", "width": 800, - "height": 600 + "height": 700, + "minWidth": 800, + "minHeight": 700, + "resizable": true, + "center": true } ], "security": { diff --git a/src/app/app.component.css b/src/app/app.component.css index d6bf8c6..f9a4cda 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -1,6 +1,4 @@ -.logo.angular:hover { - filter: drop-shadow(0 0 2em #e32727); -} + :root { font-family: Inter, Avenir, Helvetica, Arial, sans-serif; font-size: 16px; @@ -33,10 +31,6 @@ transition: 0.75s; } -.logo.tauri:hover { - filter: drop-shadow(0 0 2em #24c8db); -} - .row { display: flex; justify-content: center; @@ -118,6 +112,7 @@ button { padding: 20px; background: #f5f5f5; border-radius: 10px; + margin: 20px auto; } .keyboard-row { diff --git a/src/app/keyboards/circle-keyboard.component.css b/src/app/keyboards/circle-keyboard.component.css new file mode 100644 index 0000000..d7ed488 --- /dev/null +++ b/src/app/keyboards/circle-keyboard.component.css @@ -0,0 +1,147 @@ +.circle-keyboard-container { + position: relative; + width: 400px; + height: 400px; + margin: 50px auto; + background: #f5f5f5; +} + +/* Center Button Container */ +.center-button-container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 140px; + height: 140px; + z-index: 1; +} + +/* Center Button Sections */ +.center-section { + position: absolute; + background: white; + font-size: 20px; + font-weight: bold; + cursor: pointer; + transition: background 0.2s; + border: 2px solid #ddd; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +/* Top-left: Backspace (triangle) */ +.top-left{ + top: 0; + left: 0; + width: 70px; + height: 70px; + border-radius: 70px 0 0 0; +} + +/* Top-right: Enter*/ +.top-right { + top: 0; + right: 0; + width: 70px; + height: 70px; + border-radius: 0 70px 0 0; +} + +/* Bottom: Space */ +.bottom-left { + bottom: 0; + left: 0; + width: 70px; + height: 70px; + border-radius: 0 0 0 70px; +} + +.bottom-left.active { + background: #4CAF50 !important; + color: white; + border-color: #45a049; +} + +.bottom-right { + bottom: 0; + right: 0; + width: 70px; + height: 70px; + border-radius: 0 0 70px 0; +} + +.middle-left { + top: 50%; + left: 50%; + transform: translate(-100%, -50%); /* Komplett links von der Mitte */ + width: 30px; /* Halbe Breite */ + height: 55px; /* Volle Höhe */ + border-radius: 35px 0 0 35px; /* Linke Hälfte eines Kreises */ + z-index: 15; /* Über anderen Buttons */ +} + +.middle-right { + top: 50%; + left: 50%; + transform: translate(0%, -50%); /* Direkt rechts von der Mitte */ + width: 30px; /* Halbe Breite */ + height: 55px; /* Volle Höhe */ + border-radius: 0 35px 35px 0; /* Rechte Hälfte eines Kreises */ + z-index: 15; /* Über anderen Buttons */ +} + +/* 8 Circle Buttons */ +.circle-button { + position: absolute; + top: 50%; + left: 50%; + width: 70px; + height: 70px; + margin: -35px 0 0 -35px; + border-radius: 50%; + border: 2px solid #ddd; + background: white; + font-size: 24px; + font-weight: bold; + cursor: pointer; + transition: background 0.2s, border-color 0.2s; + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + z-index: 1; +} + +.second-ring { + width: 50px; + height: 50px; + font-size: 20px; + font-weight: normal; + margin: -25px 0 0 -25px; +} + +.third-ring { + width: 40px; + height: 40px; + font-size: 18px; + font-weight: normal; + margin: -20px 0 0 -20px; +} + +.fourth-ring { + width: 30px; + height: 30px; + font-size: 16px; + font-weight: lighter; + margin: -20px 0 0 -20px; +} + +.circle-button:hover, .center-section:hover { + background: #e8e8e8; + border-color: #999; +} + +.circle-button:active, .center-section:active { + background: #d0d0d0; +} diff --git a/src/app/keyboards/circle-keyboard.component.ts b/src/app/keyboards/circle-keyboard.component.ts index 7494420..391281c 100644 --- a/src/app/keyboards/circle-keyboard.component.ts +++ b/src/app/keyboards/circle-keyboard.component.ts @@ -33,6 +33,16 @@ import { CommonModule } from '@angular/common'; class="center-section bottom-left"> ⇧ + + @@ -43,130 +53,34 @@ import { CommonModule } from '@angular/common'; {{ shiftActive ? key : key.toLowerCase() }} + + + + + + `, - styles: [` - .circle-keyboard-container { - position: relative; - width: 400px; - height: 400px; - margin: 50px auto; - } - - /* Center Button Container */ - .center-button-container { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 140px; - height: 140px; - z-index: 1; - } - - /* Center Button Sections */ - .center-section { - position: absolute; - background: white; - font-size: 20px; - font-weight: bold; - cursor: pointer; - transition: background 0.2s; - border: 2px solid #ddd; - display: flex; - align-items: center; - justify-content: center; - z-index: 10; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); - } - - /* Top-left: Backspace (triangle) */ - .top-left{ - top: 0; - left: 0; - width: 70px; - height: 70px; - border-radius: 70px 0 0 0; - } - - /* Top-right: Enter*/ - .top-right { - top: 0; - right: 0; - width: 70px; - height: 70px; - border-radius: 0 70px 0 0; - } - - /* Bottom: Space */ - .bottom-left { - bottom: 0; - left: 0; - width: 70px; - height: 70px; - border-radius: 0 0 0 70px; - } - - .bottom-left.active { - background: #4CAF50 !important; - color: white; - border-color: #45a049; - } - - .bottom-right { - bottom: 0; - right: 0; - width: 70px; - height: 70px; - border-radius: 0 0 70px 0; - } - - /* 8 Circle Buttons */ - .circle-button { - position: absolute; - top: 50%; - left: 50%; - width: 60px; - height: 60px; - margin: -30px 0 0 -30px; - border-radius: 50%; - border: 2px solid #ddd; - background: white; - font-size: 20px; - font-weight: bold; - cursor: pointer; - transition: background 0.2s, border-color 0.2s; - box-shadow: 0 2px 8px rgba(0,0,0,0.15); - z-index: 1; - } - - .third-ring { - width: 40px; - height: 40px; - margin: -20px 0 0 -20px; - } - - .fourth-ring { - width: 30px; - height: 30px; - margin: -20px 0 0 -20px; - } - - .circle-button:hover, .center-section:hover { - background: #e8e8e8; - border-color: #999; - } - - .circle-button:active, .center-section:active { - background: #d0d0d0; - } - `] + styleUrl: './circle-keyboard.component.css' }) export class CircleKeyboardComponent { @Input() shiftActive = false; @@ -177,11 +91,11 @@ export class CircleKeyboardComponent { circleKeysFirst = ['E', 'T', 'A', 'O', 'N', 'I', 'H', 'S']; circleKeysSecond = ['R', 'L', 'D', 'U', 'C', 'M', 'W', 'Y']; circleKeysThird = ['F', 'G', 'P', 'B', 'V', 'K', 'J', 'X']; - circleKeysFourth = ['Q', 'Z', ',', '.']; + circleKeysFourth = ['Q', 'Z']; // Calculate position for each button in circle - getCirclePositionFromTop(index: number, radius: number): string { - const angle = (index * 45) - 90; // Start from top (0°), 45° apart + getCirclePositionFromTop(index: number, radius: number, offset: number = 0): string { + const angle = ((index * 45) - 90) + offset; // Start from top (0°), 45° apart const angleRad = (angle * Math.PI) / 180; const x = Math.cos(angleRad) * radius; const y = Math.sin(angleRad) * radius; From 7744bcf67d2cacf1bd08433b0171fff70484f703 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Fri, 5 Dec 2025 01:22:36 +0100 Subject: [PATCH 6/7] remove german comments --- .../keyboards/circle-keyboard.component.css | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/keyboards/circle-keyboard.component.css b/src/app/keyboards/circle-keyboard.component.css index d7ed488..f1791d8 100644 --- a/src/app/keyboards/circle-keyboard.component.css +++ b/src/app/keyboards/circle-keyboard.component.css @@ -77,21 +77,21 @@ .middle-left { top: 50%; left: 50%; - transform: translate(-100%, -50%); /* Komplett links von der Mitte */ - width: 30px; /* Halbe Breite */ - height: 55px; /* Volle Höhe */ - border-radius: 35px 0 0 35px; /* Linke Hälfte eines Kreises */ - z-index: 15; /* Über anderen Buttons */ + transform: translate(-100%, -50%); + width: 30px; + height: 55px; + border-radius: 35px 0 0 35px; + z-index: 15; } .middle-right { top: 50%; left: 50%; - transform: translate(0%, -50%); /* Direkt rechts von der Mitte */ - width: 30px; /* Halbe Breite */ - height: 55px; /* Volle Höhe */ - border-radius: 0 35px 35px 0; /* Rechte Hälfte eines Kreises */ - z-index: 15; /* Über anderen Buttons */ + transform: translate(0%, -50%); + width: 30px; + height: 55px; + border-radius: 0 35px 35px 0; + z-index: 15; } /* 8 Circle Buttons */ From 04a8a15f237b1811fdb2dcb1a4521e75e53ad7b1 Mon Sep 17 00:00:00 2001 From: lukasadrion Date: Sat, 6 Dec 2025 16:39:33 +0100 Subject: [PATCH 7/7] fix light and darkmode --- src/app/app.component.css | 8 ++++++-- .../keyboards/circle-keyboard.component.css | 20 ++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/app/app.component.css b/src/app/app.component.css index f9a4cda..7f3b095 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -103,6 +103,11 @@ button { button:active { background-color: #0f0f0f69; } + + .key-button { + background: rgb(58, 56, 56); + color: white; + } } .keyboard { @@ -128,13 +133,12 @@ button { font-weight: bold; border: 2px solid #ddd; border-radius: 8px; - background: rgb(58, 56, 56); cursor: pointer; transition: all 0.1s; } .key-button:hover { - background: #979797; + background: #b1b1b1; border-color: #3d3d3d; } diff --git a/src/app/keyboards/circle-keyboard.component.css b/src/app/keyboards/circle-keyboard.component.css index f1791d8..c61d1a4 100644 --- a/src/app/keyboards/circle-keyboard.component.css +++ b/src/app/keyboards/circle-keyboard.component.css @@ -21,6 +21,7 @@ .center-section { position: absolute; background: white; + color: #0f0f0f; font-size: 20px; font-weight: bold; cursor: pointer; @@ -105,11 +106,12 @@ border-radius: 50%; border: 2px solid #ddd; background: white; + color: #0f0f0f; font-size: 24px; font-weight: bold; cursor: pointer; transition: background 0.2s, border-color 0.2s; - box-shadow: 0 2px 8px rgba(0,0,0,0.15); + box-shadow: 0 2px 2px rgba(0,0,0,0.2); z-index: 1; } @@ -138,10 +140,22 @@ } .circle-button:hover, .center-section:hover { - background: #e8e8e8; - border-color: #999; + background: #b1b1b1; + border-color: #3d3d3d; } .circle-button:active, .center-section:active { background: #d0d0d0; } + +@media (prefers-color-scheme: dark) { + .center-section { + background: rgb(58, 56, 56); + color: white; + } + + .circle-button { + background: rgb(58, 56, 56); + color: white; + } +}