@stisocial/ui 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/components/TimeSlotPicker/TimeSlotPicker.d.ts +1 -11
- package/dist/components/TimeSlotPicker/TimeSlotPicker.js +2 -24
- package/dist/components/TimeSlotPicker/index.d.ts +3 -2
- package/dist/components/TimeSlotPicker/timeSlots.d.ts +12 -0
- package/dist/components/TimeSlotPicker/timeSlots.js +25 -0
- package/dist/id/AccountMenu/AccountMenu.css +128 -44
- package/dist/id/AccountMenu/AccountMenu.d.ts +37 -9
- package/dist/id/AccountMenu/AccountMenu.js +138 -65
- package/dist/id/AccountMenu/AccountMenu.module.js +16 -9
- package/dist/id/AccountMenu/index.d.ts +2 -2
- package/dist/id/AppSwitcher/AppSwitcher.css +153 -31
- package/dist/id/AppSwitcher/AppSwitcher.d.ts +31 -6
- package/dist/id/AppSwitcher/AppSwitcher.js +90 -37
- package/dist/id/AppSwitcher/AppSwitcher.module.js +12 -6
- package/dist/id/AppSwitcher/index.d.ts +2 -2
- package/dist/id/OrgSwitcher/OrgSwitcher.css +129 -17
- package/dist/id/OrgSwitcher/OrgSwitcher.d.ts +30 -5
- package/dist/id/OrgSwitcher/OrgSwitcher.js +110 -74
- package/dist/id/OrgSwitcher/OrgSwitcher.module.js +11 -7
- package/dist/id/OrgSwitcher/index.d.ts +2 -2
- package/dist/id/PermissionGate/PermissionGate.css +25 -14
- package/dist/id/PermissionGate/PermissionGate.d.ts +3 -1
- package/dist/id/PermissionGate/PermissionGate.js +15 -8
- package/dist/id/PermissionGate/PermissionGate.module.js +6 -5
- package/dist/id/SignInButton/SignInButton.css +179 -0
- package/dist/id/SignInButton/SignInButton.d.ts +12 -3
- package/dist/id/SignInButton/SignInButton.js +37 -18
- package/dist/id/SignInButton/SignInButton.module.js +10 -0
- package/dist/id/_internal/StiMark/StiMark.css +28 -0
- package/dist/id/_internal/StiMark/StiMark.js +37 -0
- package/dist/id/_internal/StiMark/StiMark.module.js +8 -0
- package/dist/id/index.d.ts +4 -4
- package/dist/id/index.js +4 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/messages/messages.d.ts +7 -0
- package/dist/messages/messages.js +14 -0
- package/dist/styles.css +644 -106
- package/dist/text/text.d.ts +5 -1
- package/dist/text/text.js +8 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
Sürüm numaraları anlamlıdır: kırıcı değişiklik yalnız büyük sürümde, önceden kullanımdan kaldırma
|
|
4
4
|
uyarısıyla gelir. `1.0`'a kadar (dalga 2 sonu) küçük sürümler de kırıcı olabilir; burada yazılır.
|
|
5
5
|
|
|
6
|
+
## 0.2.1 — 2026-11-13
|
|
7
|
+
|
|
8
|
+
- **STI ID parçaları yeniden tasarlandı** (`/id`; mevcut API korunur, eklemeler):
|
|
9
|
+
- **AccountMenu:** tetikleyici esnek üst çubukta artık dikeyde uzamıyor. Panel dışa açık `AccountMenuPanel` oldu: ortalanmış kimlik ve "Merhaba, Elif" selamlaması, hesap yönetimi, gruplu bağlantılar, diğer hesaplar (`otherAccounts`, `onSwitchAccount`), hesap ekleme (`addAccountHref` / `onAddAccount`), oturumu kapatma, yasal bağlantılar (`privacyHref`, `termsHref`).
|
|
10
|
+
- **AppSwitcher:** dışa açık `AppSwitcherPanel`; başlık, alt zeminli ızgara, uygulamaya göre kalıcı renkli karolar (`color`), anlamlı kısaltma (`appMonogram`: "STI ID" → "ID", "STI Office" → "O"), "Tüm uygulamalar" bağlantısı (`moreHref`), sağdan sola ok gezinmesi.
|
|
11
|
+
- **OrgSwitcher:** dışa açık `OrgSwitcherPanel`; kuruluşlar türün ikonuyla kalıcı renkli karoda (harf yazılmaz, WCAG 2.5.3), liste satırı ölçüsünde "Yeni kuruluş oluşturun" (`createHref` eklendi).
|
|
12
|
+
- **SignInButton:** kendi marka düğmesi: başta STI monogramı (kalkan ikonu yerine), tam genişlikte ortalanmış metin, beklerken monogramın yerinde dönen gösterge ve görünür "Oturum açılıyor" metni.
|
|
13
|
+
- **PermissionGate:** yetki kutusuna eylem (`deniedAction`, "Yetki isteyin"); kesik kenar yerine ince kenar ve amber kilit karosu.
|
|
14
|
+
- Katalog örnekleri gerçek kullanımı gösterir: üst çubukta tetikleyiciler ve açık paneller.
|
|
15
|
+
- **Baş harfler:** rakamla başlayan sözcük baş harf vermez ("Müşteri 04" → "M"; önce "M0").
|
|
16
|
+
- **Katalog koruması:** örnek dosyası istemci modülünden yalnız bileşen alabilir; veri ya da yardımcı işlev alınırsa birim testi kırılır (önceki denetimdeki bozuk düzenli ifade düzeltildi).
|
|
17
|
+
- **TimeSlotPicker:** `timeSlots()` yardımcısı istemci yönergesi olmayan ayrı modüle taşındı; artık sunucu bileşeninde de çağrılabilir (0.2.0'da sunucuda çağrıldığında hata veriyordu). İçe aktarma yolu değişmedi.
|
|
18
|
+
- **Katalog:** işleyici gerektiren 12 bileşenin örnekleri (Alert, BackLink, Chip, ConfirmButton, DownloadButton, ActionBar ve yapay zekâ bileşenleri) sunucuda işlev geçirdiği için katalog sayfası açılmıyordu; örnekler istemci sarmalayıcısına alındı. Örnek dosyalarının sunucuda çalışabilirliği artık birim testiyle denetlenir.
|
|
19
|
+
|
|
6
20
|
## 0.2.0 — 2026-11-13
|
|
7
21
|
|
|
8
22
|
93 yeni bileşen; hazır sayısı 339/485. Yeni alt yollar ana girişe girmez, yalnız kendi yolundan içe aktarılır: `/charts`, `/id`, `/ai`, `/media`, `/editor`, `/agency`, `/site`, `/commerce`, `/maps`, `/email`, `/document`.
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
+
import { TimeSlot } from "./timeSlots.js";
|
|
1
2
|
import { ReactNode } from "react";
|
|
2
|
-
export interface TimeSlot {
|
|
3
|
-
/** Başlangıç saati ("09:30"). */
|
|
4
|
-
time: string;
|
|
5
|
-
/** Dolu ya da kapalı saat (seçilemez, görünür kalır). */
|
|
6
|
-
isUnavailable?: boolean;
|
|
7
|
-
}
|
|
8
3
|
export interface TimeSlotPickerProps {
|
|
9
4
|
label: ReactNode;
|
|
10
5
|
description?: ReactNode;
|
|
@@ -28,11 +23,6 @@ export interface TimeSlotPickerProps {
|
|
|
28
23
|
className?: string;
|
|
29
24
|
id?: string;
|
|
30
25
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Aralıktan saatler: `timeSlots("09:00", "17:00", 30)` → 09:00, 09:30 … 16:30 (bitiş dahil
|
|
33
|
-
* değildir: son randevu bitişte biter). `unavailable` dolu saatleri işaretler.
|
|
34
|
-
*/
|
|
35
|
-
export declare function timeSlots(start: string, end: string, stepMinutes: number, unavailable?: readonly string[]): TimeSlot[];
|
|
36
26
|
/**
|
|
37
27
|
* Randevu saati seçimi: saatler hap biçiminde ızgarada (React Aria ListBox, `layout="grid"`);
|
|
38
28
|
* dolu saatler üstü çizili ve seçilemez, sabah, öğleden sonra ve akşam başlıklarıyla gruplu. Oklar
|
|
@@ -4,33 +4,11 @@ import { template } from "../../text/text.js";
|
|
|
4
4
|
import { AlertCircleIcon } from "../../icons/generated/AlertCircleIcon.js";
|
|
5
5
|
import { fieldStyles } from "../Field/Field.js";
|
|
6
6
|
import TimeSlotPicker_module_default from "./TimeSlotPicker.module.js";
|
|
7
|
+
import { toMinutes, toTime } from "./timeSlots.js";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
9
10
|
import { Header, ListBox, ListBoxItem, ListBoxSection } from "react-aria-components";
|
|
10
11
|
// src/components/TimeSlotPicker/TimeSlotPicker.tsx
|
|
11
|
-
const toMinutes = (t) => {
|
|
12
|
-
const m = /^(\d{1,2}):(\d{2})$/.exec(t);
|
|
13
|
-
return m ? Number(m[1]) * 60 + Number(m[2]) : NaN;
|
|
14
|
-
};
|
|
15
|
-
const toTime = (min) => `${String(Math.floor(min / 60) % 24).padStart(2, "0")}:${String(min % 60).padStart(2, "0")}`;
|
|
16
|
-
/**
|
|
17
|
-
* Aralıktan saatler: `timeSlots("09:00", "17:00", 30)` → 09:00, 09:30 … 16:30 (bitiş dahil
|
|
18
|
-
* değildir: son randevu bitişte biter). `unavailable` dolu saatleri işaretler.
|
|
19
|
-
*/
|
|
20
|
-
function timeSlots(start, end, stepMinutes, unavailable = []) {
|
|
21
|
-
const from = toMinutes(start);
|
|
22
|
-
const to = toMinutes(end);
|
|
23
|
-
if (!Number.isFinite(from) || !Number.isFinite(to) || stepMinutes <= 0) return [];
|
|
24
|
-
const out = [];
|
|
25
|
-
for (let m = from; m + stepMinutes <= to; m += stepMinutes) {
|
|
26
|
-
const time = toTime(m);
|
|
27
|
-
out.push({
|
|
28
|
-
time,
|
|
29
|
-
isUnavailable: unavailable.includes(time)
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
return out;
|
|
33
|
-
}
|
|
34
12
|
const partOf = (t) => {
|
|
35
13
|
const m = toMinutes(t);
|
|
36
14
|
return m < 720 ? "morning" : m < 1020 ? "afternoon" : "evening";
|
|
@@ -159,4 +137,4 @@ function TimeSlotPicker({ label, description, errorMessage, slots, value, defaul
|
|
|
159
137
|
]
|
|
160
138
|
});
|
|
161
139
|
}
|
|
162
|
-
export { TimeSlotPicker
|
|
140
|
+
export { TimeSlotPicker };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { TimeSlot,
|
|
2
|
-
|
|
1
|
+
import { TimeSlot, timeSlots } from "./timeSlots.js";
|
|
2
|
+
import { TimeSlotPicker, TimeSlotPickerProps } from "./TimeSlotPicker.js";
|
|
3
|
+
export { type TimeSlot, TimeSlotPicker, TimeSlotPickerProps, timeSlots };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Saat aralığı yardımcıları: istemci yönergesi yoktur, sunucu bileşeninden de çağrılır. */
|
|
2
|
+
export interface TimeSlot {
|
|
3
|
+
/** Başlangıç saati ("09:30"). */
|
|
4
|
+
time: string;
|
|
5
|
+
/** Dolu ya da kapalı saat (seçilemez, görünür kalır). */
|
|
6
|
+
isUnavailable?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Aralıktan saatler: `timeSlots("09:00", "17:00", 30)` → 09:00, 09:30 … 16:30 (bitiş dahil
|
|
10
|
+
* değildir: son randevu bitişte biter). `unavailable` dolu saatleri işaretler.
|
|
11
|
+
*/
|
|
12
|
+
export declare function timeSlots(start: string, end: string, stepMinutes: number, unavailable?: readonly string[]): TimeSlot[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/components/TimeSlotPicker/timeSlots.ts
|
|
2
|
+
const toMinutes = (t) => {
|
|
3
|
+
const m = /^(\d{1,2}):(\d{2})$/.exec(t);
|
|
4
|
+
return m ? Number(m[1]) * 60 + Number(m[2]) : NaN;
|
|
5
|
+
};
|
|
6
|
+
const toTime = (min) => `${String(Math.floor(min / 60) % 24).padStart(2, "0")}:${String(min % 60).padStart(2, "0")}`;
|
|
7
|
+
/**
|
|
8
|
+
* Aralıktan saatler: `timeSlots("09:00", "17:00", 30)` → 09:00, 09:30 … 16:30 (bitiş dahil
|
|
9
|
+
* değildir: son randevu bitişte biter). `unavailable` dolu saatleri işaretler.
|
|
10
|
+
*/
|
|
11
|
+
function timeSlots(start, end, stepMinutes, unavailable = []) {
|
|
12
|
+
const from = toMinutes(start);
|
|
13
|
+
const to = toMinutes(end);
|
|
14
|
+
if (!Number.isFinite(from) || !Number.isFinite(to) || stepMinutes <= 0) return [];
|
|
15
|
+
const out = [];
|
|
16
|
+
for (let m = from; m + stepMinutes <= to; m += stepMinutes) {
|
|
17
|
+
const time = toTime(m);
|
|
18
|
+
out.push({
|
|
19
|
+
time,
|
|
20
|
+
isUnavailable: unavailable.includes(time)
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
export { timeSlots, toMinutes, toTime };
|
|
@@ -1,94 +1,93 @@
|
|
|
1
1
|
@layer sti.reset, sti.tokens, sti.base, sti.components, sti.variants, sti.utilities;
|
|
2
2
|
@layer sti.components {
|
|
3
|
-
.sti-AccountMenu-trigger-
|
|
3
|
+
.sti-AccountMenu-trigger-b7836 {
|
|
4
4
|
--sti-account-menu-ring: var(--sti-border-subtle);
|
|
5
5
|
box-sizing: border-box;
|
|
6
|
+
block-size: max-content;
|
|
7
|
+
inline-size: max-content;
|
|
6
8
|
padding: var(--sti-space-0-5);
|
|
7
9
|
border: var(--sti-border-width) solid var(--sti-account-menu-ring);
|
|
8
10
|
border-radius: var(--sti-radius-pill);
|
|
9
11
|
cursor: pointer;
|
|
10
12
|
-webkit-tap-highlight-color: transparent;
|
|
11
13
|
transition: border-color var(--sti-duration-fast) var(--sti-ease-snap),
|
|
12
|
-
background-color var(--sti-duration-fast) var(--sti-ease-snap)
|
|
14
|
+
background-color var(--sti-duration-fast) var(--sti-ease-snap),
|
|
15
|
+
box-shadow var(--sti-duration-fast) var(--sti-ease-snap);
|
|
13
16
|
background: none;
|
|
14
17
|
flex: none;
|
|
15
18
|
justify-content: center;
|
|
19
|
+
align-self: center;
|
|
16
20
|
align-items: center;
|
|
21
|
+
margin: 0;
|
|
17
22
|
display: inline-flex;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
@media (hover: hover) {
|
|
21
|
-
.sti-AccountMenu-trigger-
|
|
26
|
+
.sti-AccountMenu-trigger-b7836[data-hovered] {
|
|
22
27
|
--sti-account-menu-ring: var(--sti-border-accent);
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
.sti-AccountMenu-trigger-
|
|
31
|
+
.sti-AccountMenu-trigger-b7836[data-pressed] {
|
|
27
32
|
background: var(--sti-bg-surface-active);
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
.sti-AccountMenu-trigger-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
.sti-AccountMenu-trigger-b7836[data-expanded] {
|
|
36
|
+
--sti-account-menu-ring: var(--sti-border-selected);
|
|
37
|
+
box-shadow: 0 0 0 var(--sti-border-width) var(--sti-border-selected);
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
.sti-AccountMenu-trigger-
|
|
36
|
-
--sti-
|
|
40
|
+
.sti-AccountMenu-trigger-b7836[data-focus-visible] {
|
|
41
|
+
outline: var(--sti-focus-ring-width) solid var(--sti-focus-ring);
|
|
42
|
+
outline-offset: var(--sti-focus-ring-offset);
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
@media (pointer: coarse) {
|
|
40
|
-
.sti-AccountMenu-trigger-
|
|
46
|
+
.sti-AccountMenu-trigger-b7836 {
|
|
41
47
|
min-block-size: 2.75rem;
|
|
42
48
|
min-inline-size: 2.75rem;
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
outline-color: highlight;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
@media (prefers-reduced-motion: reduce) {
|
|
53
|
-
.sti-AccountMenu-trigger-cc23b {
|
|
54
|
-
transition: none;
|
|
55
|
-
}
|
|
52
|
+
.sti-AccountMenu-card-5ba55 {
|
|
53
|
+
--sti-floating-w: 22.5rem;
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
.sti-AccountMenu-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.sti-AccountMenu-body-cd3ae {
|
|
63
|
-
gap: var(--sti-space-4);
|
|
56
|
+
.sti-AccountMenu-panel-697e1 {
|
|
57
|
+
gap: var(--sti-space-3);
|
|
64
58
|
min-inline-size: 0;
|
|
59
|
+
color: var(--sti-fg);
|
|
65
60
|
font-family: var(--sti-font-text);
|
|
66
61
|
display: grid;
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
.sti-AccountMenu-identity-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
display:
|
|
64
|
+
.sti-AccountMenu-identity-42ef2 {
|
|
65
|
+
padding-block: var(--sti-space-2) var(--sti-space-1);
|
|
66
|
+
text-align: center;
|
|
67
|
+
justify-items: center;
|
|
68
|
+
display: grid;
|
|
74
69
|
}
|
|
75
70
|
|
|
76
|
-
.sti-AccountMenu-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
.sti-AccountMenu-greeting-ced99 {
|
|
72
|
+
margin: var(--sti-space-3) 0 0;
|
|
73
|
+
font-family: var(--sti-font-display);
|
|
74
|
+
font-size: var(--sti-font-size-xl);
|
|
75
|
+
font-weight: var(--sti-font-weight-semibold);
|
|
76
|
+
line-height: var(--sti-line-height-xl);
|
|
77
|
+
letter-spacing: var(--sti-tracking-xl);
|
|
78
|
+
overflow-wrap: anywhere;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
.sti-AccountMenu-
|
|
81
|
+
.sti-AccountMenu-fullName-7a91b {
|
|
82
|
+
margin: var(--sti-space-1) 0 0;
|
|
83
83
|
color: var(--sti-fg);
|
|
84
|
-
font-size: var(--sti-font-size-
|
|
85
|
-
font-weight: var(--sti-font-weight-
|
|
86
|
-
line-height: var(--sti-line-height-
|
|
84
|
+
font-size: var(--sti-font-size-sm);
|
|
85
|
+
font-weight: var(--sti-font-weight-medium);
|
|
86
|
+
line-height: var(--sti-line-height-sm);
|
|
87
87
|
overflow-wrap: anywhere;
|
|
88
|
-
margin: 0;
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
.sti-AccountMenu-email-
|
|
90
|
+
.sti-AccountMenu-email-c7b78 {
|
|
92
91
|
color: var(--sti-fg-muted);
|
|
93
92
|
font-size: var(--sti-font-size-sm);
|
|
94
93
|
line-height: var(--sti-line-height-sm);
|
|
@@ -96,7 +95,22 @@
|
|
|
96
95
|
margin: 0;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
.sti-AccountMenu-
|
|
98
|
+
.sti-AccountMenu-manage-2a04e {
|
|
99
|
+
max-inline-size: 100%;
|
|
100
|
+
margin-block-start: var(--sti-space-4);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.sti-AccountMenu-group-8f65f {
|
|
104
|
+
gap: var(--sti-space-0-5);
|
|
105
|
+
padding: var(--sti-space-1);
|
|
106
|
+
border-radius: var(--sti-radius-lg);
|
|
107
|
+
background: var(--sti-bg-subtle);
|
|
108
|
+
margin: 0;
|
|
109
|
+
list-style: none;
|
|
110
|
+
display: grid;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sti-AccountMenu-list-0d7e5 {
|
|
100
114
|
gap: var(--sti-space-0-5);
|
|
101
115
|
margin: 0;
|
|
102
116
|
padding: 0;
|
|
@@ -104,7 +118,77 @@
|
|
|
104
118
|
display: grid;
|
|
105
119
|
}
|
|
106
120
|
|
|
107
|
-
.sti-AccountMenu-
|
|
108
|
-
|
|
121
|
+
.sti-AccountMenu-groupTitle-3bc6e {
|
|
122
|
+
padding: var(--sti-space-2) var(--sti-space-3) var(--sti-space-1);
|
|
123
|
+
color: var(--sti-fg-muted);
|
|
124
|
+
font-size: var(--sti-font-size-xs);
|
|
125
|
+
font-weight: var(--sti-font-weight-semibold);
|
|
126
|
+
line-height: var(--sti-line-height-xs);
|
|
127
|
+
margin: 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.sti-AccountMenu-accountRow-2470c > span:first-child {
|
|
131
|
+
background: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.sti-AccountMenu-legal-3b18a {
|
|
135
|
+
justify-content: center;
|
|
136
|
+
gap: var(--sti-space-1);
|
|
137
|
+
padding-block: var(--sti-space-1) 0;
|
|
138
|
+
color: var(--sti-fg-muted);
|
|
139
|
+
font-size: var(--sti-font-size-xs);
|
|
140
|
+
line-height: var(--sti-line-height-xs);
|
|
141
|
+
flex-wrap: wrap;
|
|
142
|
+
margin: 0;
|
|
143
|
+
display: flex;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.sti-AccountMenu-legalItem-5deef {
|
|
147
|
+
gap: var(--sti-space-1);
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.sti-AccountMenu-dot-af8da {
|
|
152
|
+
color: var(--sti-fg-muted);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.sti-AccountMenu-legalLink-e2e81 {
|
|
156
|
+
border-radius: var(--sti-radius-xs);
|
|
157
|
+
color: var(--sti-fg-muted);
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
text-decoration: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@media (hover: hover) {
|
|
163
|
+
.sti-AccountMenu-legalLink-e2e81[data-hovered] {
|
|
164
|
+
color: var(--sti-fg);
|
|
165
|
+
text-underline-offset: .2em;
|
|
166
|
+
text-decoration: underline;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.sti-AccountMenu-legalLink-e2e81[data-focus-visible] {
|
|
171
|
+
outline: var(--sti-focus-ring-width) solid var(--sti-focus-ring);
|
|
172
|
+
outline-offset: var(--sti-focus-ring-offset);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@media (forced-colors: active) {
|
|
176
|
+
.sti-AccountMenu-trigger-b7836[data-expanded] {
|
|
177
|
+
border-color: highlight;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.sti-AccountMenu-trigger-b7836[data-focus-visible], .sti-AccountMenu-legalLink-e2e81[data-focus-visible] {
|
|
181
|
+
outline-color: highlight;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.sti-AccountMenu-group-8f65f {
|
|
185
|
+
border: var(--sti-border-width) solid CanvasText;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (prefers-reduced-motion: reduce) {
|
|
190
|
+
.sti-AccountMenu-trigger-b7836 {
|
|
191
|
+
transition: none;
|
|
192
|
+
}
|
|
109
193
|
}
|
|
110
194
|
}
|
|
@@ -9,6 +9,13 @@ export interface AccountMenuAccount {
|
|
|
9
9
|
/** Profil fotoğrafı; yoksa baş harfler çizilir. */
|
|
10
10
|
avatarSrc?: string;
|
|
11
11
|
}
|
|
12
|
+
/** Aynı tarayıcıda oturumu açık başka bir hesap. */
|
|
13
|
+
export interface AccountMenuOtherAccount extends AccountMenuAccount {
|
|
14
|
+
/** Kalıcı anahtar. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Verilirse hesaba geçiş bağlantıdır; verilmezse `onSwitchAccount` çağrılır. */
|
|
17
|
+
href?: string;
|
|
18
|
+
}
|
|
12
19
|
export interface AccountMenuItem {
|
|
13
20
|
/** Kalıcı anahtar. */
|
|
14
21
|
id: string;
|
|
@@ -19,27 +26,48 @@ export interface AccountMenuItem {
|
|
|
19
26
|
href?: string;
|
|
20
27
|
onPress?: () => void;
|
|
21
28
|
}
|
|
22
|
-
export interface
|
|
29
|
+
export interface AccountMenuPanelProps {
|
|
23
30
|
account: AccountMenuAccount;
|
|
24
|
-
/** Hesap
|
|
31
|
+
/** Hesap yönetiminin altındaki bağlantı ve eylemler ("Güvenlik", "Faturalama"). */
|
|
25
32
|
items?: readonly AccountMenuItem[];
|
|
26
33
|
/** "STI ID hesabınızı yönetin" düğmesinin adresi; verilmezse düğme çizilmez. */
|
|
27
34
|
manageHref?: string;
|
|
28
|
-
/** Oturumu
|
|
29
|
-
|
|
35
|
+
/** Oturumu açık diğer hesaplar; verilirse "Diğer hesaplar" bölümü çizilir. */
|
|
36
|
+
otherAccounts?: readonly AccountMenuOtherAccount[];
|
|
37
|
+
onSwitchAccount?: (id: string) => void;
|
|
38
|
+
/** "Başka bir hesap ekleyin" satırı: adres ya da işlev. */
|
|
39
|
+
addAccountHref?: string;
|
|
40
|
+
onAddAccount?: () => void;
|
|
41
|
+
/** Oturumu kapatma eylemi: adres (`signOutHref`) ya da işlev. */
|
|
30
42
|
signOutHref?: string;
|
|
43
|
+
onSignOut?: () => void;
|
|
44
|
+
/** Panelin dibindeki yasal bağlantılar. */
|
|
45
|
+
privacyHref?: string;
|
|
46
|
+
termsHref?: string;
|
|
47
|
+
/** Bir eylem seçildiğinde çağrılır; açılır kutuda paneli kapatır. */
|
|
48
|
+
onAction?: () => void;
|
|
49
|
+
className?: string;
|
|
50
|
+
id?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface AccountMenuProps extends Omit<AccountMenuPanelProps, "onAction" | "id"> {
|
|
31
53
|
/** Tetikleyicinin avatar boyu. */
|
|
32
54
|
size?: "sm" | "md" | "lg";
|
|
33
55
|
placement?: Placement;
|
|
34
56
|
isOpen?: boolean;
|
|
35
57
|
defaultOpen?: boolean;
|
|
36
58
|
onOpenChange?: (open: boolean) => void;
|
|
37
|
-
|
|
59
|
+
/** Tetikleyici düğmenin kimliği. */
|
|
38
60
|
id?: string;
|
|
39
61
|
}
|
|
40
62
|
/**
|
|
41
|
-
* Hesap
|
|
42
|
-
*
|
|
43
|
-
*
|
|
63
|
+
* Hesap panelinin içeriği: kimlik (büyük avatar, selamlama, e-posta), hesap yönetimi, bağlantılar,
|
|
64
|
+
* diğer hesaplar, hesap ekleme, oturumu kapatma ve yasal bağlantılar. `AccountMenu` bunu açılır
|
|
65
|
+
* kutuda çizer; uygulama dar ekran çekmecesinde ya da hesap sayfasında doğrudan kullanabilir.
|
|
66
|
+
*/
|
|
67
|
+
export declare function AccountMenuPanel({ account, items, manageHref, otherAccounts, onSwitchAccount, addAccountHref, onAddAccount, signOutHref, onSignOut, privacyHref, termsHref, onAction, className, id }: AccountMenuPanelProps): import("react").JSX.Element;
|
|
68
|
+
/**
|
|
69
|
+
* Hesap menüsü: avatar düğmesi ve açılır hesap paneli (`AccountMenuPanel`). APG Dialog kalıbı
|
|
70
|
+
* (kipsiz açılır kutu): Enter ya da Boşluk açar, Tab içeride dolaşır, Escape kapatır ve odak
|
|
71
|
+
* düğmeye döner.
|
|
44
72
|
*/
|
|
45
|
-
export declare function AccountMenu({
|
|
73
|
+
export declare function AccountMenu({ size, placement, isOpen, defaultOpen, onOpenChange, className, id, ...panel }: AccountMenuProps): import("react").JSX.Element;
|
|
@@ -6,17 +6,142 @@ import { Button as Button$1 } from "../../components/Button/Button.js";
|
|
|
6
6
|
import { Avatar } from "../../components/Avatar/Avatar.js";
|
|
7
7
|
import { Popover as Popover$1 } from "../../components/Popover/Popover.js";
|
|
8
8
|
import { LogOutIcon } from "../../icons/generated/LogOutIcon.js";
|
|
9
|
+
import { UserPlusIcon } from "../../icons/generated/UserPlusIcon.js";
|
|
9
10
|
import { ActionItem } from "../_internal/ActionItem/ActionItem.js";
|
|
10
11
|
import AccountMenu_module_default from "./AccountMenu.module.js";
|
|
11
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
import { Button } from "react-aria-components";
|
|
12
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { Button, Link } from "react-aria-components";
|
|
13
14
|
// src/id/AccountMenu/AccountMenu.tsx
|
|
14
15
|
/**
|
|
15
|
-
* Hesap
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Hesap panelinin içeriği: kimlik (büyük avatar, selamlama, e-posta), hesap yönetimi, bağlantılar,
|
|
17
|
+
* diğer hesaplar, hesap ekleme, oturumu kapatma ve yasal bağlantılar. `AccountMenu` bunu açılır
|
|
18
|
+
* kutuda çizer; uygulama dar ekran çekmecesinde ya da hesap sayfasında doğrudan kullanabilir.
|
|
18
19
|
*/
|
|
19
|
-
function
|
|
20
|
+
function AccountMenuPanel({ account, items = [], manageHref, otherAccounts = [], onSwitchAccount, addAccountHref, onAddAccount, signOutHref, onSignOut, privacyHref, termsHref, onAction, className, id }) {
|
|
21
|
+
const t = useMessages();
|
|
22
|
+
const run = (fn) => () => {
|
|
23
|
+
onAction?.();
|
|
24
|
+
fn?.();
|
|
25
|
+
};
|
|
26
|
+
const canAdd = addAccountHref !== void 0 || onAddAccount !== void 0;
|
|
27
|
+
const canSignOut = signOutHref !== void 0 || onSignOut !== void 0;
|
|
28
|
+
const legal = [privacyHref ? {
|
|
29
|
+
href: privacyHref,
|
|
30
|
+
label: t.idAccountPrivacy
|
|
31
|
+
} : null, termsHref ? {
|
|
32
|
+
href: termsHref,
|
|
33
|
+
label: t.idAccountTerms
|
|
34
|
+
} : null].filter((l) => l !== null);
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
36
|
+
id,
|
|
37
|
+
className: [AccountMenu_module_default.panel, className].filter(Boolean).join(" "),
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsxs("div", {
|
|
40
|
+
className: AccountMenu_module_default.identity,
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Avatar, {
|
|
43
|
+
name: account.name,
|
|
44
|
+
src: account.avatarSrc,
|
|
45
|
+
size: "xl",
|
|
46
|
+
isDecorative: true
|
|
47
|
+
}),
|
|
48
|
+
/* @__PURE__ */ jsx("p", {
|
|
49
|
+
className: AccountMenu_module_default.greeting,
|
|
50
|
+
children: template(t.idAccountGreeting, { name: firstName(account.name) })
|
|
51
|
+
}),
|
|
52
|
+
/* @__PURE__ */ jsx("p", {
|
|
53
|
+
className: AccountMenu_module_default.fullName,
|
|
54
|
+
children: account.name
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ jsx("p", {
|
|
57
|
+
className: AccountMenu_module_default.email,
|
|
58
|
+
children: account.email
|
|
59
|
+
}),
|
|
60
|
+
manageHref ? /* @__PURE__ */ jsx(Button$1, {
|
|
61
|
+
variant: "secondary",
|
|
62
|
+
size: "sm",
|
|
63
|
+
href: manageHref,
|
|
64
|
+
className: AccountMenu_module_default.manage,
|
|
65
|
+
children: t.idAccountManage
|
|
66
|
+
}) : null
|
|
67
|
+
]
|
|
68
|
+
}),
|
|
69
|
+
items.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
70
|
+
className: AccountMenu_module_default.group,
|
|
71
|
+
children: items.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(ActionItem, {
|
|
72
|
+
label: item.label,
|
|
73
|
+
icon: item.icon,
|
|
74
|
+
href: item.href,
|
|
75
|
+
onPress: run(item.onPress)
|
|
76
|
+
}) }, item.id))
|
|
77
|
+
}) : null,
|
|
78
|
+
otherAccounts.length > 0 || canAdd ? /* @__PURE__ */ jsxs("section", {
|
|
79
|
+
className: AccountMenu_module_default.group,
|
|
80
|
+
"aria-label": t.idAccountOthers,
|
|
81
|
+
children: [otherAccounts.length > 0 ? /* @__PURE__ */ jsx("p", {
|
|
82
|
+
className: AccountMenu_module_default.groupTitle,
|
|
83
|
+
"aria-hidden": "true",
|
|
84
|
+
children: t.idAccountOthers
|
|
85
|
+
}) : null, /* @__PURE__ */ jsxs("ul", {
|
|
86
|
+
className: AccountMenu_module_default.list,
|
|
87
|
+
children: [otherAccounts.map((other) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(ActionItem, {
|
|
88
|
+
label: /* @__PURE__ */ jsxs(Fragment, { children: [other.name, /* @__PURE__ */ jsxs(VisuallyHidden, { children: [", ", t.idAccountSwitch] })] }),
|
|
89
|
+
description: other.email,
|
|
90
|
+
icon: /* @__PURE__ */ jsx(Avatar, {
|
|
91
|
+
name: other.name,
|
|
92
|
+
src: other.avatarSrc,
|
|
93
|
+
size: "sm",
|
|
94
|
+
isDecorative: true
|
|
95
|
+
}),
|
|
96
|
+
className: AccountMenu_module_default.accountRow,
|
|
97
|
+
href: other.href,
|
|
98
|
+
onPress: run(() => onSwitchAccount?.(other.id))
|
|
99
|
+
}) }, other.id)), canAdd ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(ActionItem, {
|
|
100
|
+
label: t.idAccountAdd,
|
|
101
|
+
icon: /* @__PURE__ */ jsx(UserPlusIcon, {}),
|
|
102
|
+
href: addAccountHref,
|
|
103
|
+
onPress: run(onAddAccount)
|
|
104
|
+
}) }) : null]
|
|
105
|
+
})]
|
|
106
|
+
}) : null,
|
|
107
|
+
canSignOut ? /* @__PURE__ */ jsx("div", {
|
|
108
|
+
className: AccountMenu_module_default.group,
|
|
109
|
+
children: /* @__PURE__ */ jsx(ActionItem, {
|
|
110
|
+
label: t.idAccountSignOut,
|
|
111
|
+
icon: /* @__PURE__ */ jsx(LogOutIcon, {}),
|
|
112
|
+
href: signOutHref,
|
|
113
|
+
onPress: run(onSignOut)
|
|
114
|
+
})
|
|
115
|
+
}) : null,
|
|
116
|
+
legal.length > 0 ? /* @__PURE__ */ jsx("p", {
|
|
117
|
+
className: AccountMenu_module_default.legal,
|
|
118
|
+
children: legal.map((link, i) => /* @__PURE__ */ jsxs("span", {
|
|
119
|
+
className: AccountMenu_module_default.legalItem,
|
|
120
|
+
children: [i > 0 ? /* @__PURE__ */ jsx("span", {
|
|
121
|
+
className: AccountMenu_module_default.dot,
|
|
122
|
+
"aria-hidden": "true",
|
|
123
|
+
children: "·"
|
|
124
|
+
}) : null, /* @__PURE__ */ jsx(Link, {
|
|
125
|
+
href: link.href,
|
|
126
|
+
className: AccountMenu_module_default.legalLink,
|
|
127
|
+
onPress: onAction,
|
|
128
|
+
children: link.label
|
|
129
|
+
})]
|
|
130
|
+
}, link.href))
|
|
131
|
+
}) : null
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/** Selamlamadaki ad: ilk sözcük ("Elif Yıldırım" → "Elif"). */
|
|
136
|
+
function firstName(name) {
|
|
137
|
+
return name.trim().split(/\s+/)[0] ?? name;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Hesap menüsü: avatar düğmesi ve açılır hesap paneli (`AccountMenuPanel`). APG Dialog kalıbı
|
|
141
|
+
* (kipsiz açılır kutu): Enter ya da Boşluk açar, Tab içeride dolaşır, Escape kapatır ve odak
|
|
142
|
+
* düğmeye döner.
|
|
143
|
+
*/
|
|
144
|
+
function AccountMenu({ size = "md", placement = "bottom end", isOpen, defaultOpen, onOpenChange, className, id, ...panel }) {
|
|
20
145
|
const t = useMessages();
|
|
21
146
|
return /* @__PURE__ */ jsx(Popover$1, {
|
|
22
147
|
isOpen,
|
|
@@ -31,68 +156,16 @@ function AccountMenu({ account, items = [], manageHref, onSignOut, signOutHref,
|
|
|
31
156
|
className: [AccountMenu_module_default.trigger, className].filter(Boolean).join(" "),
|
|
32
157
|
"data-size": size,
|
|
33
158
|
children: [/* @__PURE__ */ jsx(Avatar, {
|
|
34
|
-
name: account.name,
|
|
35
|
-
src: account.avatarSrc,
|
|
159
|
+
name: panel.account.name,
|
|
160
|
+
src: panel.account.avatarSrc,
|
|
36
161
|
size,
|
|
37
162
|
isDecorative: true
|
|
38
|
-
}), /* @__PURE__ */ jsx(VisuallyHidden, { children: template(t.idAccountMenuFor, { name: account.name }) })]
|
|
163
|
+
}), /* @__PURE__ */ jsx(VisuallyHidden, { children: template(t.idAccountMenuFor, { name: panel.account.name }) })]
|
|
39
164
|
}),
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fullWidth: true,
|
|
44
|
-
iconStart: /* @__PURE__ */ jsx(LogOutIcon, {}),
|
|
45
|
-
...signOutHref ? { href: signOutHref } : { onPress: () => {
|
|
46
|
-
close();
|
|
47
|
-
onSignOut?.();
|
|
48
|
-
} },
|
|
49
|
-
children: t.idAccountSignOut
|
|
50
|
-
}) : null,
|
|
51
|
-
children: (close) => /* @__PURE__ */ jsxs("div", {
|
|
52
|
-
className: AccountMenu_module_default.body,
|
|
53
|
-
children: [
|
|
54
|
-
/* @__PURE__ */ jsxs("div", {
|
|
55
|
-
className: AccountMenu_module_default.identity,
|
|
56
|
-
children: [/* @__PURE__ */ jsx(Avatar, {
|
|
57
|
-
name: account.name,
|
|
58
|
-
src: account.avatarSrc,
|
|
59
|
-
size: "lg",
|
|
60
|
-
isDecorative: true
|
|
61
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
62
|
-
className: AccountMenu_module_default.names,
|
|
63
|
-
children: [/* @__PURE__ */ jsx("p", {
|
|
64
|
-
className: AccountMenu_module_default.name,
|
|
65
|
-
children: account.name
|
|
66
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
67
|
-
className: AccountMenu_module_default.email,
|
|
68
|
-
children: account.email
|
|
69
|
-
})]
|
|
70
|
-
})]
|
|
71
|
-
}),
|
|
72
|
-
manageHref ? /* @__PURE__ */ jsx(Button$1, {
|
|
73
|
-
variant: "secondary",
|
|
74
|
-
size: "sm",
|
|
75
|
-
fullWidth: true,
|
|
76
|
-
href: manageHref,
|
|
77
|
-
children: t.idAccountManage
|
|
78
|
-
}) : null,
|
|
79
|
-
items.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
80
|
-
className: AccountMenu_module_default.items,
|
|
81
|
-
children: items.map((item) => /* @__PURE__ */ jsx("li", {
|
|
82
|
-
className: AccountMenu_module_default.item,
|
|
83
|
-
children: /* @__PURE__ */ jsx(ActionItem, {
|
|
84
|
-
label: item.label,
|
|
85
|
-
icon: item.icon,
|
|
86
|
-
href: item.href,
|
|
87
|
-
onPress: () => {
|
|
88
|
-
close();
|
|
89
|
-
item.onPress?.();
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}, item.id))
|
|
93
|
-
}) : null
|
|
94
|
-
]
|
|
165
|
+
children: (close) => /* @__PURE__ */ jsx(AccountMenuPanel, {
|
|
166
|
+
...panel,
|
|
167
|
+
onAction: close
|
|
95
168
|
})
|
|
96
169
|
});
|
|
97
170
|
}
|
|
98
|
-
export { AccountMenu };
|
|
171
|
+
export { AccountMenu, AccountMenuPanel };
|