Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b493d41
fix(pair): compact bridge cards in a grid; Tuya local-key form collap…
Enard52 Oct 30, 2026
38273f5
feat(catalog): Shelly Gen1 and Home Assistant sensors listed as suppo…
Enard52 Oct 30, 2026
eb8dc9b
Merge branch 'fix/add-device-layout' into feat/catalog-sensors
Enard52 Oct 30, 2026
4f54c2f
feat(discovery): SSDP discovery on desktop feeds the auto scan first
Enard52 Oct 30, 2026
bcdb42a
fix(assistant): in-app prompts get on-topic answers (support/FAQ repl…
Enard52 Oct 30, 2026
1ffc3fb
fix(chat): quick chips are always centered under the greeting (wrap o…
Enard52 Oct 30, 2026
9586046
fix(messages): family shortcut cards get icons and a chevron
Enard52 Oct 30, 2026
4fea3ac
feat(desktop): tray menu gets icons, page shortcuts (Home, Add device…
Enard52 Oct 30, 2026
e996a5d
feat(smart): tap-to-run tab shows ready scenes for the user's paired …
Enard52 Oct 31, 2026
9b755dc
fix(smart): merge quick suggestions into scene choice; picking a scen…
Enard52 Oct 31, 2026
54265aa
fix(pair): WLED finding gets a real icon (lightstrip is not a lucide …
Enard52 Oct 31, 2026
fb1951a
fix(smart): automation page sheets redone (trigger setup + quick sugg…
Enard52 Oct 31, 2026
a42ef94
feat(smart): tap-to-run creation gets its own page (no trigger list);…
Enard52 Oct 31, 2026
317ddf1
feat(ui): real device images next to device names (found devices, rea…
Enard52 Oct 31, 2026
c1c0506
test(quick-scenes): preview carries the device thumb field
Enard52 Oct 31, 2026
504a28f
feat(smart): recommendations ranked by real device kinds, always 5 ca…
Enard52 Oct 31, 2026
11c1f45
feat(assistant): links no longer auto-send messages; real assistant m…
Enard52 Oct 31, 2026
ca22a5d
fix(ui): search bubble becomes an edge tab like the AI button: auto-d…
Enard52 Oct 31, 2026
1c59c07
fix(assistant): local engine no longer acts on questions/recommendati…
Enard52 Oct 31, 2026
dbea2ac
fix(ui): scenario sheet shows accurate descriptions and keeps previe…
Enard52 Oct 31, 2026
6ff992c
fix(smart): ready scene tile says it could not reach devices instead …
Enard52 Oct 31, 2026
1ce0d60
fix(ui): remove inner focus ring from the chat input in light theme too
Enard52 Oct 31, 2026
a0986b8
feat(ui): app-styled select lists instead of the OS grey dropdown
Enard52 Oct 31, 2026
3d991e6
style(tests): prettier formatting so the CI format check passes
Enard52 Oct 31, 2026
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
71 changes: 70 additions & 1 deletion css/nexus-ui.css
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,33 @@ html.dark header[class*="bg-white/"] {
.nx-sheet-head { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; }
.nx-sheet-head .nx-sheet-ico { display: inline-flex; flex: none; width: 20px; height: 20px; color: var(--nx-accent,#4C7DFF); }
html.dark .nx-sheet-head .nx-sheet-ico { color: #8fb0ff; }

/* ---------- 31 Eki yüzeyleri: koyu tema ----------
Projede Tailwind dark: varyantı derlenmez; koyu tema bu katmandan gelir.
Yeni eklenen sheet/sayfalar burada açık hedeflerle koyuya çevrilir. */
html.dark #sheet-plan { background-color: #0f172a; }
html.dark #sheet-plan .text-slate-700,
html.dark #sheet-plan .text-slate-600 { color: #cbd5e1; }
html.dark #plan-summary { background-color: #1e293b; }
html.dark #plan-summary .text-slate-700,
html.dark #plan-summary .text-slate-200 { color: #e2e8f0; }
html.dark #plan-summary .text-slate-400 { color: #94a3b8; }
html.dark #plan-budget,
html.dark #plan-from,
html.dark #plan-to,
html.dark #plan-unit { background-color: #1e293b; border-color: #334155; color: #f1f5f9; }
html.dark #plan-back { background-color: #1e293b; color: #e2e8f0; }
/* Ev Panosu */
html.dark #board-list .bg-white,
html.dark #add-form .bg-white { background-color: #1e293b; }
html.dark #board-list .text-slate-800 { color: #f1f5f9; }
html.dark #board-list .text-slate-500 { color: #94a3b8; }
html.dark #add-input { background-color: #1e293b; border-color: #334155; color: #f1f5f9; }
html.dark #kind-toggle { background-color: #334155; color: #93b4ff; }
/* Üye İzinleri diyaloğu (oda erişimi çipleri dahil) */
html.dark #perm-list .bg-slate-50 { background-color: #1e293b; }
html.dark #perm-list .text-slate-600 { color: #cbd5e1; }
html.dark #perm-list .text-slate-400 { color: #94a3b8; }
.nx-sheet-head .nx-sheet-ico svg { width: 20px; height: 20px; }
.nx-sheet-head h2, .nx-sheet-head h3 { margin: 0; font-size: 18px; font-weight: 800; letter-spacing: -0.01em; }

Expand Down Expand Up @@ -463,6 +490,41 @@ html.dark input:focus-visible, html.dark textarea:focus-visible, html.dark selec
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.35);
border-color: rgba(96, 165, 250, 0.65) !important;
}
/* Sohbet girişi zaten yuvarlak bir çubuğun içinde; kendi odak halkası çubukta kare görünür. */
#chat-input:focus-visible, html.dark #chat-input:focus-visible { box-shadow: none; border-color: transparent !important; }

/* ---------- Özel seçim kutusu (nexus-select.js) ----------
Yerel <select> gizlenir; yerine aynı sınıfları taşıyan düğme ve uygulamaya ait açılır liste gelir.
:where() → sayfadaki Tailwind sınıfları (bg-white, rounded-xl, px-4…) her zaman önceliklidir. */
:where(.nx-sel-btn) { background: #fff; color: #0f172a; border: 1px solid #e2e8f0; border-radius: 12px; padding: 10px 12px; font: inherit; font-weight: 600; }
.nx-sel-btn { display: inline-flex; align-items: center; justify-content: space-between; gap: 10px; text-align: left; cursor: pointer; appearance: none; -webkit-appearance: none; min-width: 0; }
.nx-sel-btn.hidden { display: none; }
.nx-sel-btn:disabled { opacity: .55; cursor: not-allowed; }
.nx-sel-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nx-sel-label.is-placeholder { color: #94a3b8; font-weight: 500; }
.nx-sel-chev { flex: none; color: #64748b; transition: transform .16s ease; }
.nx-sel-btn.is-open .nx-sel-chev { transform: rotate(180deg); }
.nx-sel-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(var(--nx-accent-rgbc,76,125,255),0.30); border-color: rgba(var(--nx-accent-rgbc,76,125,255),0.65); }
html.dark :where(.nx-sel-btn) { background: #0f172a; color: #f1f5f9; border-color: #334155; }
html.dark .nx-sel-chev { color: #94a3b8; }
html.dark .nx-sel-btn:focus-visible { box-shadow: 0 0 0 3px rgba(96,165,250,0.35); border-color: rgba(96,165,250,0.65); }

.nx-sel-panel { position: fixed; z-index: 2147483000; box-sizing: border-box; overflow-y: auto; overscroll-behavior: contain; padding: 6px; border-radius: 16px; background: #fff; border: 1px solid #e2e8f0; box-shadow: 0 18px 40px -12px rgba(15,23,42,.28), 0 4px 12px rgba(15,23,42,.08); font-family: inherit; opacity: 0; transform: translateY(-4px) scale(.98); transform-origin: top center; transition: opacity .12s ease, transform .12s ease; }
.nx-sel-panel.is-up { transform-origin: bottom center; transform: translateY(4px) scale(.98); }
.nx-sel-panel.is-in { opacity: 1; transform: none; }
.nx-sel-opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 12px; border-radius: 11px; font-size: 14px; font-weight: 600; color: #0f172a; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.nx-sel-opt.is-active { background: rgba(var(--nx-accent-rgbc,76,125,255),0.10); }
.nx-sel-opt.is-on { color: var(--nx-accent, #4C7DFF); font-weight: 800; }
.nx-sel-opt.is-placeholder { color: #94a3b8; font-weight: 500; }
.nx-sel-opt.is-disabled { opacity: .45; cursor: not-allowed; }
.nx-sel-check { flex: none; visibility: hidden; }
.nx-sel-opt.is-on .nx-sel-check { visibility: visible; }
.nx-sel-group { padding: 10px 12px 4px; font-size: 11px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: #64748b; }
html.dark .nx-sel-panel { background: #1e293b; border-color: #334155; box-shadow: 0 18px 40px -12px rgba(0,0,0,.6); }
html.dark .nx-sel-opt { color: #f1f5f9; }
html.dark .nx-sel-opt.is-active { background: rgba(96,165,250,0.16); }
html.dark .nx-sel-opt.is-on { color: #7cb0ff; }
html.dark .nx-sel-group { color: #94a3b8; }
a:focus-visible, button:focus-visible, [role="button"]:focus-visible {
outline: 2px solid rgba(var(--nx-accent-rgbc,76,125,255),0.70);
outline-offset: 2px;
Expand Down Expand Up @@ -693,4 +755,11 @@ html .group:active .group-active\:text-\[\#4C7DFF\]{color:rgb(var(--nx-accent-rg
nav[data-purpose="bottom-nav"] { height: calc(2.75rem + env(safe-area-inset-bottom)) !important; padding-top: 0 !important; padding-bottom: max(0rem, env(safe-area-inset-bottom)) !important; }
nav[data-purpose="bottom-nav"] a { flex-direction: row !important; gap: 6px !important; width: auto !important; min-width: 44px; height: 40px !important; padding: 0 12px; }
nav[data-purpose="bottom-nav"] a svg, nav[data-purpose="bottom-nav"] a i { width: 20px !important; height: 20px !important; }
}
}
/* Asistan modları: input üstünde yatay kayan seçim çipleri */
.nx-modes { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 10px; margin: 0 -4px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.nx-modes::-webkit-scrollbar { display: none; }
.nx-mode { flex: none; padding: 8px 14px; border-radius: 999px; border: 1.5px solid rgba(100, 116, 139, .25); background: rgba(255, 255, 255, .75); color: #475569; font-size: 13px; font-weight: 700; white-space: nowrap; cursor: pointer; transition: background .12s ease, color .12s ease; }
.nx-mode.is-on { border-color: var(--nx-accent, #4C7DFF); background: var(--nx-accent, #4C7DFF); color: #fff; }
html.dark .nx-mode { background: rgba(30, 41, 59, .8); color: #cbd5e1; border-color: #334155; }
html.dark .nx-mode.is-on { background: var(--nx-accent, #4C7DFF); color: #fff; border-color: var(--nx-accent, #4C7DFF); }
110 changes: 110 additions & 0 deletions css/quick-scenes.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* Hazır senaryo kartları ve senaryo oluşturma ekranı (nexus-smart.html + nexus-skills.html).
Derlenmiş Tailwind'de olmayan sınıflara bağımlı olmamak için kendi sınıfları vardır. */
.qs-wrap { --qs-card: #ffffff; --qs-line: #e8ebf4; --qs-text: #0f172a; --qs-muted: #64748b; --qs-soft: #f4f6fc; --qs-accent: var(--nx-accent, #4C7DFF); }
html.dark .qs-wrap { --qs-card: #1e293b; --qs-line: #334155; --qs-text: #f1f5f9; --qs-muted: #94a3b8; --qs-soft: #0f172a; }

.qs-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
.qs-head h3 { margin: 0; font-size: 18px; font-weight: 800; color: var(--qs-text); letter-spacing: -.01em; }
.qs-sub { margin: -6px 0 12px; font-size: 12.5px; line-height: 1.5; color: var(--qs-muted); }

.qs-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
@media (min-width: 720px) { .qs-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Hazır senaryo kutusu: dokununca çalışır */
.qs-tile { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; width: 100%; min-height: 132px; padding: 14px; border-radius: 22px; border: 1px solid var(--qs-line); background: var(--qs-card); color: var(--qs-text); text-align: left; cursor: pointer; transition: transform .12s ease, box-shadow .12s ease; box-shadow: 0 4px 18px rgba(15, 23, 42, .05); }
.qs-tile:active { transform: scale(.97); }
.qs-tile[disabled] { opacity: .75; cursor: default; }
.qs-ico { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 40px; height: 40px; border-radius: 14px; }
.qs-ico svg { width: 20px; height: 20px; }
.qs-title { font-size: 15px; font-weight: 800; line-height: 1.2; }
.qs-meta { font-size: 11.5px; line-height: 1.4; color: var(--qs-muted); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.qs-run { margin-top: auto; display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 800; }
.qs-run svg { width: 14px; height: 14px; }
.qs-tile.is-done .qs-run { color: #10b981; }
.qs-tile.is-warn .qs-run { color: #f59e0b; }

/* Kullanıcının kaydettikleri */
.qs-mine { display: flex; align-items: center; gap: 12px; width: 100%; padding: 12px; border-radius: 20px; border: 1px solid var(--qs-line); background: var(--qs-card); color: var(--qs-text); text-align: left; cursor: pointer; }
.qs-mine + .qs-mine { margin-top: 10px; }
.qs-mine .qs-body { min-width: 0; flex: 1; }
.qs-mine .qs-title { display: block; font-size: 14.5px; }
.qs-mine .qs-meta { display: block; margin-top: 2px; -webkit-line-clamp: 1; }
.qs-icon-btn { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 36px; height: 36px; border-radius: 12px; border: 0; background: var(--qs-soft); color: var(--qs-muted); cursor: pointer; }
.qs-icon-btn svg { width: 16px; height: 16px; }
.qs-icon-btn.danger { color: #ef4444; }

/* Boş durum / not */
.qs-note { padding: 14px; border-radius: 16px; background: var(--qs-soft); border: 1px solid var(--qs-line); font-size: 12.5px; line-height: 1.55; color: var(--qs-muted); }
.qs-note a { color: var(--qs-accent); font-weight: 800; }

.qs-link-btn { display: inline-flex; align-items: center; gap: 6px; padding: 9px 14px; border-radius: 999px; border: 0; background: var(--qs-accent); color: #fff; font-size: 13px; font-weight: 800; text-decoration: none; cursor: pointer; }
.qs-link-btn svg { width: 15px; height: 15px; }
.qs-link-btn.ghost { background: color-mix(in srgb, var(--qs-accent) 12%, transparent); color: var(--qs-accent); }

/* ---- Oluşturma ekranı ---- */
.qs-section { margin: 0 0 22px; }
.qs-section > .qs-label { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 13px; font-weight: 800; color: var(--qs-text); }
.qs-step { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 999px; background: var(--qs-accent); color: #fff; font-size: 12px; font-weight: 800; }

.qs-choice { display: flex; align-items: center; gap: 12px; width: 100%; padding: 12px; border-radius: 18px; border: 1.5px solid var(--qs-line); background: var(--qs-card); color: var(--qs-text); text-align: left; cursor: pointer; transition: border-color .12s ease, background .12s ease; }
.qs-choice + .qs-choice { margin-top: 10px; }
.qs-choice.is-on { border-color: var(--qs-accent); background: color-mix(in srgb, var(--qs-accent) 8%, var(--qs-card)); }
.qs-choice[disabled] { opacity: .55; cursor: not-allowed; }
.qs-choice .qs-body { min-width: 0; flex: 1; }
.qs-choice .qs-title { display: block; font-size: 14.5px; }
.qs-choice .qs-meta { display: block; margin-top: 2px; }
.qs-radio { flex: none; width: 20px; height: 20px; border-radius: 999px; border: 2px solid var(--qs-line); display: inline-flex; align-items: center; justify-content: center; }
.qs-choice.is-on .qs-radio { border-color: var(--qs-accent); background: var(--qs-accent); }
.qs-choice.is-on .qs-radio::after { content: ""; width: 7px; height: 7px; border-radius: 999px; background: #fff; }

.qs-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.qs-chip { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 999px; border: 1.5px solid var(--qs-line); background: var(--qs-card); color: var(--qs-text); font-size: 13px; font-weight: 700; cursor: pointer; }
.qs-chip.is-on { border-color: var(--qs-accent); background: var(--qs-accent); color: #fff; }
.qs-chip img, .qs-chip .nx-thumb { width: 20px; height: 20px; object-fit: contain; }

.qs-input { width: 100%; min-height: 46px; padding: 0 14px; border-radius: 14px; border: 1.5px solid var(--qs-line); background: var(--qs-card); color: var(--qs-text); font-size: 15px; font-weight: 600; }
.qs-input:focus { outline: none; border-color: var(--qs-accent); }

.qs-preview { margin-top: 10px; padding: 12px 14px; border-radius: 16px; background: var(--qs-soft); border: 1px solid var(--qs-line); }
.qs-preview h5 { margin: 0 0 6px; font-size: 12px; font-weight: 800; color: var(--qs-muted); text-transform: uppercase; letter-spacing: .04em; }
.qs-preview li { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; font-size: 13px; color: var(--qs-text); }
.qs-preview li span:last-child { color: var(--qs-muted); text-align: right; }
.qs-preview ul { margin: 0; padding: 0; list-style: none; }

.qs-savebar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; padding: 12px 20px calc(12px + env(safe-area-inset-bottom)); background: linear-gradient(to top, var(--qs-bar, #fff) 70%, transparent); }
html.dark .qs-savebar { --qs-bar: #0f172a; }
.qs-save { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; max-width: 560px; margin: 0 auto; min-height: 52px; border: 0; border-radius: 18px; background: var(--qs-accent); color: #fff; font-size: 16px; font-weight: 800; cursor: pointer; }
.qs-save[disabled] { background: #cbd5e1; color: #fff; cursor: not-allowed; }
html.dark .qs-save[disabled] { background: #334155; color: #94a3b8; }
.qs-hint { margin: 8px auto 0; max-width: 560px; text-align: center; font-size: 12px; color: var(--qs-muted); }

/* Hızlı öneri satırı: tek dokunuşla ekle */
.qs-sugg { display: flex; align-items: center; gap: 12px; padding: 12px; border-radius: 18px; border: 1px solid var(--qs-line); background: var(--qs-card); }
.qs-sugg + .qs-sugg { margin-top: 10px; }
.qs-sugg .qs-body { min-width: 0; flex: 1; }
.qs-sugg .qs-title { display: block; font-size: 14px; }
.qs-sugg .qs-meta { display: block; margin-top: 2px; -webkit-line-clamp: 1; }

/* Alttan açılan sayfalar (tetikleyici ayarı, Hızlı Öneriler) */
.qs-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, .4); opacity: 0; pointer-events: none; transition: opacity .3s ease; }
.qs-backdrop.is-open { opacity: 1; pointer-events: auto; }
.qs-sheet { --qs-sheet: #ffffff; position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; display: flex; flex-direction: column; max-height: 88vh; padding: 10px 20px calc(16px + env(safe-area-inset-bottom)); background: var(--qs-sheet); border-radius: 28px 28px 0 0; box-shadow: 0 -10px 40px rgba(0, 0, 0, .12); transform: translateY(105%); visibility: hidden; transition: transform .3s ease, visibility 0s linear .3s; }
html.dark .qs-sheet { --qs-sheet: #111827; }
.qs-sheet.is-open { transform: none; visibility: visible; transition: transform .3s ease; }
@media (min-width: 720px) { .qs-sheet { left: 50%; right: auto; width: 560px; margin-left: -280px; } }
.qs-grab { width: 48px; height: 5px; margin: 0 auto 14px; border-radius: 999px; background: var(--qs-line); flex: none; }
.qs-sheet-title { margin: 0 0 4px; text-align: center; font-size: 22px; font-weight: 800; color: var(--qs-text); }
.qs-sheet-desc { margin: 4px 0 14px; text-align: center; font-size: 13px; line-height: 1.5; color: var(--qs-muted); }
.qs-sheet-body { flex: 1; min-height: 0; overflow-y: auto; padding: 2px 0 8px; }
.qs-sheet-foot { flex: none; padding-top: 10px; }
.qs-sheet-foot .qs-save { max-width: none; }
.qs-row2 { margin-top: 10px; }
.qs-done { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; font-weight: 800; color: #10b981; }
.qs-done svg { width: 15px; height: 15px; }
.qs-sugg .qs-ico + .qs-body { margin-left: 0; }
.qs-sugg .qs-meta { display: block; margin-top: 2px; -webkit-line-clamp: 2; }
/* Cihaz adının yanında gerçek ürün görseli */
.qs-thumb { width: 22px; height: 22px; object-fit: contain; flex: none; }
.qs-thumbs { display: flex; align-items: center; gap: 4px; min-height: 26px; }
.qs-thumbs .qs-thumb { width: 26px; height: 26px; }
.qs-devname { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
Loading
Loading