blob: d000a3ff36a7af2179332ae86a1de63e53bfed87 [file] [log] [blame]
Philip Zeyligere08c7ff2025-06-06 13:22:12 -07001import { css, html, LitElement } from "lit";
2import { customElement, property } from "lit/decorators.js";
3import { ConnectionStatus } from "../data";
4
5@customElement("mobile-title")
6export class MobileTitle extends LitElement {
7 @property({ type: String })
8 connectionStatus: ConnectionStatus = "disconnected";
9
10 @property({ type: Boolean })
11 isThinking = false;
12
Philip Zeyliger0113be52025-06-07 23:53:41 +000013 @property({ type: String })
14 skabandAddr?: string;
15
Philip Zeyligere08c7ff2025-06-06 13:22:12 -070016 static styles = css`
17 :host {
18 display: block;
19 background-color: #f8f9fa;
20 border-bottom: 1px solid #e9ecef;
21 padding: 12px 16px;
22 }
23
24 .title-container {
25 display: flex;
26 align-items: center;
27 justify-content: space-between;
28 }
29
30 .title {
31 font-size: 18px;
32 font-weight: 600;
33 color: #212529;
34 margin: 0;
35 }
36
Philip Zeyliger0113be52025-06-07 23:53:41 +000037 .title a {
38 color: inherit;
39 text-decoration: none;
40 transition: opacity 0.2s ease;
41 display: flex;
42 align-items: center;
43 gap: 8px;
44 }
45
46 .title a:hover {
47 opacity: 0.8;
48 text-decoration: underline;
49 }
50
51 .title img {
52 width: 18px;
53 height: 18px;
54 border-radius: 3px;
55 }
56
Philip Zeyligere08c7ff2025-06-06 13:22:12 -070057 .status-indicator {
58 display: flex;
59 align-items: center;
60 gap: 8px;
61 font-size: 14px;
62 }
63
64 .status-dot {
65 width: 8px;
66 height: 8px;
67 border-radius: 50%;
68 flex-shrink: 0;
69 }
70
71 .status-dot.connected {
72 background-color: #28a745;
73 }
74
75 .status-dot.connecting {
76 background-color: #ffc107;
77 animation: pulse 1.5s ease-in-out infinite;
78 }
79
80 .status-dot.disconnected {
81 background-color: #dc3545;
82 }
83
84 .thinking-indicator {
85 display: flex;
86 align-items: center;
87 gap: 6px;
88 color: #6c757d;
89 font-size: 13px;
90 }
91
92 .thinking-dots {
93 display: flex;
94 gap: 2px;
95 }
96
97 .thinking-dot {
98 width: 4px;
99 height: 4px;
100 border-radius: 50%;
101 background-color: #6c757d;
102 animation: thinking 1.4s ease-in-out infinite both;
103 }
104
105 .thinking-dot:nth-child(1) {
106 animation-delay: -0.32s;
107 }
108 .thinking-dot:nth-child(2) {
109 animation-delay: -0.16s;
110 }
111 .thinking-dot:nth-child(3) {
112 animation-delay: 0;
113 }
114
115 @keyframes pulse {
116 0%,
117 100% {
118 opacity: 1;
119 }
120 50% {
121 opacity: 0.5;
122 }
123 }
124
125 @keyframes thinking {
126 0%,
127 80%,
128 100% {
129 transform: scale(0);
130 }
131 40% {
132 transform: scale(1);
133 }
134 }
135 `;
136
137 private getStatusText() {
138 switch (this.connectionStatus) {
139 case "connected":
140 return "Connected";
141 case "connecting":
142 return "Connecting...";
143 case "disconnected":
144 return "Disconnected";
145 default:
146 return "Unknown";
147 }
148 }
149
150 render() {
151 return html`
152 <div class="title-container">
Philip Zeyliger0113be52025-06-07 23:53:41 +0000153 <h1 class="title">
154 ${this.skabandAddr
155 ? html`<a
156 href="${this.skabandAddr}"
157 target="_blank"
158 rel="noopener noreferrer"
159 >
160 <img src="${this.skabandAddr}/sketch.dev.png" alt="sketch" />
161 Sketch
162 </a>`
163 : html`Sketch`}
164 </h1>
Philip Zeyligere08c7ff2025-06-06 13:22:12 -0700165
166 <div class="status-indicator">
167 ${this.isThinking
168 ? html`
169 <div class="thinking-indicator">
170 <span>thinking</span>
171 <div class="thinking-dots">
172 <div class="thinking-dot"></div>
173 <div class="thinking-dot"></div>
174 <div class="thinking-dot"></div>
175 </div>
176 </div>
177 `
178 : html`
179 <span class="status-dot ${this.connectionStatus}"></span>
180 <span>${this.getStatusText()}</span>
181 `}
182 </div>
183 </div>
184 `;
185 }
186}