ar-design 0.4.26 → 0.4.28
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/dist/assets/css/components/data-display/calendar/styles.css +15 -0
- package/dist/assets/css/components/data-display/calendar/styles.week-view.css +128 -0
- package/dist/components/data-display/calendar/Body.d.ts +21 -0
- package/dist/components/data-display/calendar/Body.js +14 -0
- package/dist/components/data-display/calendar/Header.d.ts +20 -0
- package/dist/components/data-display/calendar/Header.js +26 -0
- package/dist/components/data-display/calendar/IProps.d.ts +12 -0
- package/dist/components/data-display/calendar/IProps.js +1 -0
- package/dist/components/data-display/calendar/index.d.ts +5 -0
- package/dist/components/data-display/calendar/index.js +27 -0
- package/dist/components/data-display/calendar/views/Day.d.ts +3 -0
- package/dist/components/data-display/calendar/views/Day.js +5 -0
- package/dist/components/data-display/calendar/views/Month.d.ts +3 -0
- package/dist/components/data-display/calendar/views/Month.js +5 -0
- package/dist/components/data-display/calendar/views/Week.d.ts +17 -0
- package/dist/components/data-display/calendar/views/Week.js +104 -0
- package/dist/components/data-display/table/IProps.d.ts +1 -1
- package/dist/components/form/date-picker/Props.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/libs/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
.ar-calendar {
|
|
2
|
+
> .ar-calendar-week-view {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: flex-end;
|
|
6
|
+
background-color: var(--white);
|
|
7
|
+
padding: 0.75rem 0.75rem 0.75rem 2rem;
|
|
8
|
+
border-radius: var(--border-radius-sm);
|
|
9
|
+
|
|
10
|
+
> .head {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
width: 100%;
|
|
14
|
+
padding-left: 50px;
|
|
15
|
+
|
|
16
|
+
> .item {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: 1rem;
|
|
21
|
+
width: calc(100% / 7);
|
|
22
|
+
padding: 0.5rem 0;
|
|
23
|
+
|
|
24
|
+
> .day-name {
|
|
25
|
+
color: var(--gray-400);
|
|
26
|
+
font-size: 0.75rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
> .date {
|
|
30
|
+
font-size: 1.5rem;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
> .body {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: row;
|
|
38
|
+
width: 100%;
|
|
39
|
+
|
|
40
|
+
> .clocks {
|
|
41
|
+
> div {
|
|
42
|
+
height: 60px;
|
|
43
|
+
|
|
44
|
+
> span {
|
|
45
|
+
color: var(--gray-700);
|
|
46
|
+
font-size: 0.75rem;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
> .grid {
|
|
52
|
+
position: relative;
|
|
53
|
+
width: 100%;
|
|
54
|
+
height: calc(24 * 60px);
|
|
55
|
+
border: solid 1px transparent;
|
|
56
|
+
border-top-color: var(--gray-200);
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
|
|
59
|
+
> .events-layer {
|
|
60
|
+
position: absolute;
|
|
61
|
+
top: 0;
|
|
62
|
+
left: 0;
|
|
63
|
+
width: 100%;
|
|
64
|
+
height: 100%;
|
|
65
|
+
pointer-events: none;
|
|
66
|
+
z-index: 1;
|
|
67
|
+
|
|
68
|
+
> .event-box {
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: calc(100% / 7);
|
|
71
|
+
padding: 0.5rem;
|
|
72
|
+
color: var(--white);
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
> .row {
|
|
78
|
+
position: relative;
|
|
79
|
+
height: 60px;
|
|
80
|
+
margin: auto;
|
|
81
|
+
|
|
82
|
+
&:nth-child(2) {
|
|
83
|
+
> .cell {
|
|
84
|
+
&::before {
|
|
85
|
+
content: "";
|
|
86
|
+
position: absolute;
|
|
87
|
+
left: -1px;
|
|
88
|
+
background-color: var(--gray-200);
|
|
89
|
+
width: 1px;
|
|
90
|
+
height: 25px;
|
|
91
|
+
transform: translateY(-25px);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&:last-child {
|
|
97
|
+
> .cell {
|
|
98
|
+
border-bottom-color: transparent;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
> .cell {
|
|
103
|
+
position: relative;
|
|
104
|
+
width: calc(100% / 7);
|
|
105
|
+
height: 60px;
|
|
106
|
+
padding: 0;
|
|
107
|
+
border: solid 1px transparent;
|
|
108
|
+
border-left-color: var(--gray-200);
|
|
109
|
+
border-bottom-color: var(--gray-200);
|
|
110
|
+
|
|
111
|
+
&:first-child {
|
|
112
|
+
&::after {
|
|
113
|
+
content: "";
|
|
114
|
+
position: absolute;
|
|
115
|
+
top: -2px;
|
|
116
|
+
left: 0;
|
|
117
|
+
background-color: var(--gray-200);
|
|
118
|
+
width: 15px;
|
|
119
|
+
height: 1px;
|
|
120
|
+
transform: translateX(-15px);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "../../../libs/types";
|
|
3
|
+
import { CalendarEvent } from "./IProps";
|
|
4
|
+
interface IProps {
|
|
5
|
+
data: CalendarEvent[];
|
|
6
|
+
states: {
|
|
7
|
+
currentDate: {
|
|
8
|
+
get: Date;
|
|
9
|
+
set: React.Dispatch<React.SetStateAction<Date>>;
|
|
10
|
+
};
|
|
11
|
+
view: {
|
|
12
|
+
get: View;
|
|
13
|
+
set: React.Dispatch<React.SetStateAction<View>>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
config?: {
|
|
17
|
+
locale?: Intl.LocalesArgument;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
declare const Body: ({ data, states, config }: IProps) => React.JSX.Element;
|
|
21
|
+
export default Body;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Day from "./views/Day";
|
|
3
|
+
import Week from "./views/Week";
|
|
4
|
+
import Month from "./views/Month";
|
|
5
|
+
const Body = ({ data, states, config }) => {
|
|
6
|
+
if (states.view.get === "Day")
|
|
7
|
+
return React.createElement(Day, null);
|
|
8
|
+
else if (states.view.get === "Week")
|
|
9
|
+
return React.createElement(Week, { data: data, states: { currentDate: states.currentDate }, config: config });
|
|
10
|
+
else if (states.view.get === "Month")
|
|
11
|
+
return React.createElement(Month, null);
|
|
12
|
+
return React.createElement(React.Fragment, null, "...");
|
|
13
|
+
};
|
|
14
|
+
export default Body;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "../../../libs/types";
|
|
3
|
+
interface IProps {
|
|
4
|
+
states: {
|
|
5
|
+
currentDate: {
|
|
6
|
+
get: Date;
|
|
7
|
+
set: React.Dispatch<React.SetStateAction<Date>>;
|
|
8
|
+
};
|
|
9
|
+
view: {
|
|
10
|
+
get: View;
|
|
11
|
+
set: React.Dispatch<React.SetStateAction<View>>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
config?: {
|
|
15
|
+
locale?: Intl.LocalesArgument;
|
|
16
|
+
weekStartsOn?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
declare const Header: ({ states, config }: IProps) => React.JSX.Element;
|
|
20
|
+
export default Header;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Button from "../../form/button";
|
|
3
|
+
import { ARIcon } from "../../icons";
|
|
4
|
+
import Box from "../grid-system/box/Box";
|
|
5
|
+
const Header = ({ states, config }) => {
|
|
6
|
+
// methods
|
|
7
|
+
const changeWeek = (direction) => {
|
|
8
|
+
states.currentDate.set((prev) => {
|
|
9
|
+
if (direction === "today")
|
|
10
|
+
return new Date();
|
|
11
|
+
const newDate = new Date(prev);
|
|
12
|
+
newDate.setDate(prev.getDate() + (direction === "next" ? 7 : -7));
|
|
13
|
+
return newDate;
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
return (React.createElement("div", { className: "header" },
|
|
17
|
+
React.createElement(Box, null,
|
|
18
|
+
React.createElement(Button, { variant: "outlined", color: "green", border: { radius: "xxl" }, onClick: () => changeWeek("today") }, "Bug\u00FCn"),
|
|
19
|
+
React.createElement(Button, { variant: "borderless", color: "light", border: { radius: "pill" }, icon: { element: React.createElement(ARIcon, { icon: "ArrowLeft", stroke: "currentColor" }) }, onClick: () => changeWeek("prev") }),
|
|
20
|
+
React.createElement(Button, { variant: "borderless", color: "light", border: { radius: "pill" }, icon: { element: React.createElement(ARIcon, { icon: "ArrowRight", stroke: "currentColor" }) }, onClick: () => changeWeek("next") }),
|
|
21
|
+
React.createElement("span", { className: "week-time" },
|
|
22
|
+
states.currentDate.get.toLocaleString(config?.locale ?? "tr-TR", { month: "long" }),
|
|
23
|
+
" ",
|
|
24
|
+
states.currentDate.get.getFullYear()))));
|
|
25
|
+
};
|
|
26
|
+
export default Header;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import Body from "./Body";
|
|
4
|
+
import Header from "./Header";
|
|
5
|
+
import "../../../assets/css/components/data-display/calendar/styles.css";
|
|
6
|
+
const Calendar = ({ data, config }) => {
|
|
7
|
+
// states
|
|
8
|
+
const [currentDate, setCurrentDate] = useState(new Date());
|
|
9
|
+
const [view, setView] = useState("Week");
|
|
10
|
+
return (React.createElement("div", { className: "ar-calendar" },
|
|
11
|
+
React.createElement(Header, { states: {
|
|
12
|
+
currentDate: { get: currentDate, set: setCurrentDate },
|
|
13
|
+
view: {
|
|
14
|
+
get: view,
|
|
15
|
+
set: setView,
|
|
16
|
+
},
|
|
17
|
+
}, config: config }),
|
|
18
|
+
React.createElement(Body, { data: data, states: {
|
|
19
|
+
currentDate: { get: currentDate, set: setCurrentDate },
|
|
20
|
+
view: {
|
|
21
|
+
get: view,
|
|
22
|
+
set: setView,
|
|
23
|
+
},
|
|
24
|
+
}, config: config })));
|
|
25
|
+
};
|
|
26
|
+
Calendar.displayName = "DatePicker";
|
|
27
|
+
export default Calendar;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CalendarEvent } from "../IProps";
|
|
3
|
+
interface IProps {
|
|
4
|
+
data: CalendarEvent[];
|
|
5
|
+
states: {
|
|
6
|
+
currentDate: {
|
|
7
|
+
get: Date;
|
|
8
|
+
set: React.Dispatch<React.SetStateAction<Date>>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
config?: {
|
|
12
|
+
locale?: Intl.LocalesArgument;
|
|
13
|
+
weekStartsOn?: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
declare const Week: ({ data, states, config }: IProps) => React.JSX.Element;
|
|
17
|
+
export default Week;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
2
|
+
const Week = ({ data, states, config }) => {
|
|
3
|
+
const startHour = 0;
|
|
4
|
+
const endHour = 24;
|
|
5
|
+
const hours = endHour - startHour;
|
|
6
|
+
const cellHeight = 60;
|
|
7
|
+
const [events, setEvents] = useState([]);
|
|
8
|
+
const weekDays = useMemo(() => getWeekDays(states.currentDate.get, config?.weekStartsOn ?? 1), [states.currentDate.get, config?.weekStartsOn]);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
setEvents(data);
|
|
11
|
+
}, [data]);
|
|
12
|
+
return (React.createElement("div", { className: "ar-calendar-week-view" },
|
|
13
|
+
React.createElement("div", { className: "head" }, weekDays.map((day) => (React.createElement("div", { key: day.toISOString(), className: "item", style: { flex: 1, textAlign: "center" } },
|
|
14
|
+
React.createElement("span", { className: "day-name" }, day.toLocaleString(config?.locale ?? "tr", { weekday: "short" }).toUpperCase()),
|
|
15
|
+
React.createElement("span", { className: "date" }, day.getDate()))))),
|
|
16
|
+
React.createElement("div", { className: "body" },
|
|
17
|
+
React.createElement("div", { className: "clocks", style: { width: "50px" } }, Array.from({ length: hours }, (_, index) => (React.createElement("div", { key: index },
|
|
18
|
+
React.createElement("span", null,
|
|
19
|
+
String(startHour + index).padStart(2, "0"),
|
|
20
|
+
":00"))))),
|
|
21
|
+
React.createElement("div", { role: "grid", className: "grid" },
|
|
22
|
+
Array.from({ length: hours }).map((_, rowIndex) => (React.createElement("div", { key: rowIndex, className: "row" }, weekDays.map((_, colIndex) => (React.createElement("div", { key: colIndex, className: "cell" })))))),
|
|
23
|
+
React.createElement("div", { className: "events-layer" }, events.flatMap((event, eventIdx) => {
|
|
24
|
+
const eventColor = getColor(eventIdx);
|
|
25
|
+
// Her etkinlik için haftanın günlerini gezip, o güne düşen parçayı hesaplıyoruz
|
|
26
|
+
return weekDays.map((day, dayIndex) => {
|
|
27
|
+
const dayStart = new Date(day);
|
|
28
|
+
dayStart.setHours(0, 0, 0, 0);
|
|
29
|
+
const dayEnd = new Date(day);
|
|
30
|
+
dayEnd.setHours(23, 59, 59, 999);
|
|
31
|
+
// Etkinlik bu günle kesişiyor mu?
|
|
32
|
+
const overlapStart = new Date(Math.max(event.start.getTime(), dayStart.getTime()));
|
|
33
|
+
const overlapEnd = new Date(Math.min(event.end.getTime(), dayEnd.getTime()));
|
|
34
|
+
if (overlapStart < overlapEnd) {
|
|
35
|
+
// Bu güne düşen kısmın yükseklik ve top değerleri
|
|
36
|
+
const startMinutes = overlapStart.getHours() * 60 + overlapStart.getMinutes();
|
|
37
|
+
const durationMinutes = (overlapEnd.getTime() - overlapStart.getTime()) / 60000;
|
|
38
|
+
const top = (startMinutes / 60) * cellHeight;
|
|
39
|
+
const height = (durationMinutes / 60) * cellHeight;
|
|
40
|
+
// Durum Kontrolleri
|
|
41
|
+
const isContinuedFromYesterday = event.start < dayStart;
|
|
42
|
+
const isContinuingTomorrow = event.end > dayEnd;
|
|
43
|
+
return (React.createElement("div", { key: `${eventIdx}-${dayIndex}`, className: "event-box", style: {
|
|
44
|
+
backgroundColor: eventColor.bg,
|
|
45
|
+
top: `${top}px`,
|
|
46
|
+
height: `${height}px`,
|
|
47
|
+
left: `${(100 / 7) * dayIndex}%`,
|
|
48
|
+
width: `${100 / 7}%`,
|
|
49
|
+
borderTop: isContinuedFromYesterday ? "none" : `1px solid ${eventColor.border}`,
|
|
50
|
+
borderBottom: isContinuingTomorrow ? "none" : `1px solid ${eventColor.border}`,
|
|
51
|
+
borderRadius: isContinuedFromYesterday
|
|
52
|
+
? "0 0 var(--border-radius-sm) var(--border-radius-sm)"
|
|
53
|
+
: isContinuingTomorrow
|
|
54
|
+
? "var(--border-radius-sm) var(--border-radius-sm) 0 0"
|
|
55
|
+
: "var(--border-radius-sm)",
|
|
56
|
+
} }, !isContinuedFromYesterday && (React.createElement(React.Fragment, null,
|
|
57
|
+
React.createElement("div", { className: "event-content" },
|
|
58
|
+
event.start.toLocaleTimeString(config?.locale ?? "tr-TR", {
|
|
59
|
+
hour: "2-digit",
|
|
60
|
+
minute: "2-digit",
|
|
61
|
+
}),
|
|
62
|
+
" - ",
|
|
63
|
+
event.end.toLocaleTimeString(config?.locale ?? "tr-TR", {
|
|
64
|
+
hour: "2-digit",
|
|
65
|
+
minute: "2-digit",
|
|
66
|
+
}))))));
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
});
|
|
70
|
+
}))))));
|
|
71
|
+
};
|
|
72
|
+
// Yardımcı Fonksiyonlar aynı kalıyor
|
|
73
|
+
const getWeekRange = (date, weekStartsOn = 1) => {
|
|
74
|
+
const current = new Date(date);
|
|
75
|
+
const currentDay = current.getDay();
|
|
76
|
+
const diff = (currentDay - weekStartsOn + 7) % 7;
|
|
77
|
+
const start = new Date(current);
|
|
78
|
+
start.setDate(current.getDate() - diff);
|
|
79
|
+
start.setHours(0, 0, 0, 0);
|
|
80
|
+
const end = new Date(start);
|
|
81
|
+
end.setDate(start.getDate() + 6);
|
|
82
|
+
return { start, end };
|
|
83
|
+
};
|
|
84
|
+
const getWeekDays = (date, weekStartsOn = 1) => {
|
|
85
|
+
const { start } = getWeekRange(date, weekStartsOn);
|
|
86
|
+
return Array.from({ length: 7 }, (_, i) => {
|
|
87
|
+
const d = new Date(start);
|
|
88
|
+
d.setDate(start.getDate() + i);
|
|
89
|
+
return d;
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
const getColor = (id) => {
|
|
93
|
+
const colors = [
|
|
94
|
+
{ bg: "#3174ad", border: "#2a6293" }, // Mavi
|
|
95
|
+
{ bg: "#4caf50", border: "#388e3c" }, // Yeşil
|
|
96
|
+
{ bg: "#ff9800", border: "#f57c00" }, // Turuncu
|
|
97
|
+
{ bg: "#9c27b0", border: "#7b1fa2" }, // Mor
|
|
98
|
+
{ bg: "#e91e63", border: "#c2185b" }, // Pembe
|
|
99
|
+
{ bg: "#00bcd4", border: "#0097a7" }, // Turkuaz
|
|
100
|
+
];
|
|
101
|
+
const index = typeof id === "number" ? id : id.length;
|
|
102
|
+
return colors[index % colors.length];
|
|
103
|
+
};
|
|
104
|
+
export default Week;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import Select from "./components/form/select";
|
|
|
10
10
|
import Switch from "./components/form/switch";
|
|
11
11
|
import TextEditor from "./components/form/text-editor";
|
|
12
12
|
import Upload from "./components/form/upload";
|
|
13
|
+
import Calendar from "./components/data-display/calendar";
|
|
13
14
|
import Card from "./components/data-display/card";
|
|
14
15
|
import Chip from "./components/data-display/chip";
|
|
15
16
|
import Diagram from "./components/data-display/diagram/index";
|
|
@@ -33,4 +34,4 @@ import Pagination from "./components/navigation/pagination";
|
|
|
33
34
|
import Steps from "./components/navigation/steps";
|
|
34
35
|
import Grid from "./components/data-display/grid-system";
|
|
35
36
|
import Layout from "./components/layout";
|
|
36
|
-
export { Button, ButtonAction, ButtonGroup, Checkbox, DatePicker, Input, Radio, Select, Switch, TextEditor, Upload, Card, Chip, Diagram, Divider, DnD, KanbanBoard, Paper, SyntaxHighlighter, Table, Tabs, Typography, Alert, Drawer, Modal, Popover, Progress, Tooltip, Breadcrumb, Menu, Pagination, Steps, Grid, Layout, };
|
|
37
|
+
export { Button, ButtonAction, ButtonGroup, Checkbox, DatePicker, Input, Radio, Select, Switch, TextEditor, Upload, Calendar, Card, Chip, Diagram, Divider, DnD, KanbanBoard, Paper, SyntaxHighlighter, Table, Tabs, Typography, Alert, Drawer, Modal, Popover, Progress, Tooltip, Breadcrumb, Menu, Pagination, Steps, Grid, Layout, };
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import Switch from "./components/form/switch";
|
|
|
12
12
|
import TextEditor from "./components/form/text-editor";
|
|
13
13
|
import Upload from "./components/form/upload";
|
|
14
14
|
// Data Display
|
|
15
|
+
import Calendar from "./components/data-display/calendar";
|
|
15
16
|
import Card from "./components/data-display/card";
|
|
16
17
|
import Chip from "./components/data-display/chip";
|
|
17
18
|
import Diagram from "./components/data-display/diagram/index";
|
|
@@ -42,7 +43,7 @@ export {
|
|
|
42
43
|
// Form Elements
|
|
43
44
|
Button, ButtonAction, ButtonGroup, Checkbox, DatePicker, Input, Radio, Select, Switch, TextEditor, Upload,
|
|
44
45
|
// Data Display
|
|
45
|
-
Card, Chip, Diagram, Divider, DnD, KanbanBoard, Paper, SyntaxHighlighter, Table, Tabs, Typography,
|
|
46
|
+
Calendar, Card, Chip, Diagram, Divider, DnD, KanbanBoard, Paper, SyntaxHighlighter, Table, Tabs, Typography,
|
|
46
47
|
// Feedback
|
|
47
48
|
Alert, Drawer, Modal, Popover, Progress, Tooltip,
|
|
48
49
|
// Navigation
|