@uniai-fe/uds-templates 0.5.9 → 0.5.11

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.
Files changed (30) hide show
  1. package/README.md +7 -0
  2. package/dist/styles.css +139 -79
  3. package/package.json +1 -1
  4. package/src/cctv/components/pagination/list/Item.tsx +9 -0
  5. package/src/weather/apis/korea/client.ts +50 -15
  6. package/src/weather/apis/korea/server.ts +2 -2
  7. package/src/weather/apis/open-weather-map/client.ts +45 -15
  8. package/src/weather/apis/open-weather-map/server.ts +8 -2
  9. package/src/weather/components/icon/Address.tsx +7 -6
  10. package/src/weather/components/icon/Weather.tsx +4 -5
  11. package/src/weather/components/page-header/Address.tsx +36 -2
  12. package/src/weather/components/page-header/Alert.tsx +43 -16
  13. package/src/weather/components/page-header/Container.tsx +33 -5
  14. package/src/weather/components/page-header/Forecast.tsx +48 -7
  15. package/src/weather/components/page-header/NextDays.tsx +25 -22
  16. package/src/weather/components/page-header/Today.tsx +134 -91
  17. package/src/weather/hooks/useOpenWeatherMap.ts +22 -3
  18. package/src/weather/hooks/useWeatherKorea.ts +16 -4
  19. package/src/weather/hooks/useWeatherKoreaAlert.ts +13 -4
  20. package/src/weather/img/marker.svg +4 -0
  21. package/src/weather/index.scss +1 -0
  22. package/src/weather/styles/variables.scss +30 -0
  23. package/src/weather/styles/weather.scss +116 -109
  24. package/src/weather/types/base.ts +20 -0
  25. package/src/weather/types/index.ts +2 -0
  26. package/src/weather/types/page-header.ts +277 -0
  27. package/src/weather/types/provider.ts +34 -0
  28. package/src/weather/utils/index.ts +1 -0
  29. package/src/weather/utils/locale.ts +110 -0
  30. package/src/weather/utils/weather.ts +112 -0
@@ -5,13 +5,22 @@ import { useAtomValue } from "jotai";
5
5
  import { useQueryWeatherKoreaAlert } from "../apis/korea/client"; // server 번들을 피하기 위해 client 모듈에서 직접 import한다.
6
6
  import { weatherFarmIdx } from "../jotai/farm-idx";
7
7
 
8
- export default function useWeatherKoreaAlert() {
8
+ type UseWeatherKoreaAlertOptions = {
9
+ enabled?: boolean;
10
+ };
11
+
12
+ export default function useWeatherKoreaAlert({
13
+ enabled = true,
14
+ }: UseWeatherKoreaAlertOptions = {}) {
9
15
  const farm_idx = useAtomValue(weatherFarmIdx);
10
16
 
11
17
  // 특보 조회 식별자는 템플릿이 보정하지 않고, 서비스가 주입한 값만 그대로 사용한다.
12
- const { data, isFetching } = useQueryWeatherKoreaAlert({
13
- farm_idx,
14
- });
18
+ const { data, isFetching } = useQueryWeatherKoreaAlert(
19
+ {
20
+ farm_idx,
21
+ },
22
+ { enabled },
23
+ );
15
24
 
16
25
  const alert = useMemo(() => data?.alerts || [], [data]);
17
26
 
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M7.99996 1.4668C10.6941 1.4668 12.8665 3.47682 12.8665 6.58854C12.8664 8.54149 11.6838 10.5163 10.5898 11.9421C10.0325 12.6683 9.47625 13.28 9.05986 13.7096C8.8515 13.9246 8.67753 14.095 8.55465 14.2122C8.49317 14.2709 8.44389 14.3165 8.41012 14.3477C8.39335 14.3631 8.38018 14.3752 8.37105 14.3835C8.36655 14.3876 8.36318 14.3909 8.36064 14.3932C8.35938 14.3944 8.35814 14.3952 8.35738 14.3958L8.35608 14.3965C8.17889 14.5552 7.92171 14.576 7.72457 14.457L7.64384 14.3971L7.64254 14.3958C7.64178 14.3952 7.64053 14.3944 7.63928 14.3932C7.63674 14.3909 7.63337 14.3876 7.62887 14.3835C7.61974 14.3752 7.60657 14.3631 7.5898 14.3477C7.55603 14.3165 7.50675 14.2709 7.44527 14.2122C7.32239 14.095 7.14842 13.9246 6.94006 13.7096C6.52367 13.28 5.96741 12.6683 5.41012 11.9421C4.3161 10.5163 3.13354 8.54149 3.13342 6.58854C3.13342 3.47682 5.30586 1.4668 7.99996 1.4668Z" fill="#313235"/>
3
+ <path d="M9.33329 6.66671C9.33329 7.40309 8.73634 8.00004 7.99996 8.00004C7.26358 8.00004 6.66663 7.40309 6.66663 6.66671C6.66663 5.93033 7.26358 5.33337 7.99996 5.33337C8.73634 5.33337 9.33329 5.93033 9.33329 6.66671Z" fill="white"/>
4
+ </svg>
@@ -1 +1,2 @@
1
+ @use "./styles/variables.scss";
1
2
  @use "./styles/weather.scss";
@@ -0,0 +1,30 @@
1
+ :root {
2
+ --weather-page-header-height: 2.4rem;
3
+ --weather-page-header-gap: var(--spacing-gap-6);
4
+ --weather-page-header-background: var(--color-surface-static-white);
5
+
6
+ --weather-icon-width: 2.5rem;
7
+ --weather-icon-height: 2.4rem;
8
+ --weather-address-icon-size: 1.6rem;
9
+
10
+ --weather-item-gap: var(--spacing-gap-4);
11
+ --weather-address-gap: var(--spacing-gap-2);
12
+
13
+ --weather-body-font-size: var(--font-body-xxsmall-size);
14
+ --weather-body-line-height: var(--font-body-xxsmall-line-height);
15
+ --weather-body-letter-spacing: var(--font-body-xxsmall-letter-spacing);
16
+ --weather-label-font-weight: 500;
17
+ --weather-label-value-gap: var(--spacing-gap-2);
18
+ --weather-value-font-weight: 600;
19
+ --weather-unit-font-size: 0.8385rem;
20
+
21
+ --weather-text-color: var(--color-label-standard);
22
+ --weather-label-color: var(--color-label-neutral);
23
+ --weather-alert-text-color: var(--color-primary-standard);
24
+ --weather-alert-background: var(--color-surface-static-blue);
25
+ --weather-alert-height: 2rem;
26
+ --weather-alert-padding-horizontal: var(--spacing-padding-3);
27
+ --weather-alert-radius: 0.6rem;
28
+ --weather-alert-font-size: var(--font-caption-medium-size);
29
+ --weather-alert-font-weight: 400;
30
+ }
@@ -1,151 +1,158 @@
1
- .weather-base-container {
2
- width: fit-content;
1
+ .weather-page-header {
3
2
  display: flex;
4
3
  align-items: center;
5
-
6
- span {
7
- font-size: 1.4rem;
8
- }
4
+ gap: var(--weather-page-header-gap);
5
+ width: fit-content;
6
+ height: var(--weather-page-header-height);
7
+ background: var(--weather-page-header-background);
8
+ white-space: nowrap;
9
9
  }
10
10
 
11
11
  .weather-base-icon {
12
- width: 2.5rem;
13
- height: 2.4rem;
14
12
  position: relative;
13
+ width: var(--weather-icon-width);
14
+ height: var(--weather-icon-height);
15
+ flex: 0 0 auto;
15
16
  }
16
17
 
17
- .weather-base-text-info {
18
+ .weather-address {
18
19
  display: flex;
19
20
  align-items: center;
21
+ gap: var(--weather-address-gap);
22
+ width: fit-content;
23
+ }
20
24
 
21
- dt {
22
- margin-right: 0.8rem;
23
- font-size: 0;
24
-
25
- span {
26
- color: var(--color-cool-gray-35);
27
- }
28
- }
25
+ .weather-address-icon {
26
+ position: relative;
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ width: var(--weather-address-icon-size);
31
+ height: var(--weather-address-icon-size);
32
+ flex: 0 0 auto;
33
+ }
29
34
 
30
- dd {
31
- font-size: 0;
32
- display: flex;
33
- align-items: flex-start;
35
+ .weather-address-text {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: var(--weather-address-gap);
39
+ margin: 0;
40
+ color: var(--weather-text-color);
41
+ font-size: var(--weather-body-font-size);
42
+ font-weight: var(--weather-label-font-weight);
43
+ line-height: var(--weather-body-line-height);
44
+ letter-spacing: var(--weather-body-letter-spacing);
45
+ }
34
46
 
35
- span {
36
- color: var(--color-cool-gray-10);
37
- font-weight: 600;
38
- }
39
- }
47
+ .weather-address-date {
48
+ color: var(--weather-label-color);
40
49
  }
41
50
 
42
- .weather-base-divider {
43
- width: 1px;
44
- height: 1.3rem;
45
- margin: 0 0.8rem;
46
- background: var(--color-cool-gray-85);
51
+ .weather-today-container {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: var(--weather-item-gap);
55
+ width: fit-content;
47
56
  }
48
57
 
49
- .weather-address {
58
+ .weather-today-text {
50
59
  display: flex;
51
60
  align-items: center;
61
+ gap: var(--weather-item-gap);
52
62
  width: fit-content;
63
+ }
53
64
 
54
- &-icon {
55
- width: 1.6rem;
56
- height: 1.6rem;
57
- margin-right: 0.4rem;
58
- position: relative;
59
- }
60
-
61
- &-text {
62
- width: fit-content;
63
- margin-right: 1rem;
64
- display: flex;
65
- align-items: center;
66
-
67
- span {
68
- font-size: 1.6rem;
69
- color: var(--color-cool-gray-10);
70
- font-weight: 600;
71
- white-space: nowrap;
72
- transform: translateY(0.1rem);
73
- }
74
- }
65
+ .weather-next-days-container {
66
+ display: flex;
67
+ align-items: center;
68
+ gap: var(--weather-item-gap);
69
+ width: fit-content;
75
70
  }
76
71
 
77
- .weather-today-container {
78
- @extend .weather-base-container;
72
+ .weather-temperature-text {
73
+ margin: 0;
74
+ color: var(--weather-text-color);
75
+ font-size: 0;
76
+ font-weight: var(--weather-label-font-weight);
77
+ line-height: var(--weather-body-line-height);
78
+ letter-spacing: var(--weather-body-letter-spacing);
79
+ }
79
80
 
80
- span {
81
- white-space: nowrap;
82
- }
81
+ .weather-humidity-text {
82
+ margin: 0;
83
+ color: var(--weather-text-color);
84
+ font-size: 0;
85
+ font-weight: var(--weather-label-font-weight);
86
+ line-height: var(--weather-body-line-height);
87
+ letter-spacing: var(--weather-body-letter-spacing);
88
+ }
83
89
 
84
- .empty-text {
85
- font-size: 1.4rem;
86
- padding-right: 4rem;
87
- }
90
+ .weather-forecast-text {
91
+ margin: 0;
92
+ color: var(--weather-text-color);
93
+ font-size: 0;
94
+ font-weight: var(--weather-label-font-weight);
95
+ line-height: var(--weather-body-line-height);
96
+ letter-spacing: var(--weather-body-letter-spacing);
88
97
  }
89
98
 
90
- .weather-today-temperature {
91
- margin-left: 1rem;
92
- display: flex;
93
- align-items: flex-start;
99
+ .weather-label {
100
+ color: var(--weather-label-color);
101
+ font-size: var(--weather-body-font-size);
102
+ font-weight: var(--weather-label-font-weight);
103
+ margin-right: var(--weather-label-value-gap);
104
+ }
94
105
 
95
- span {
96
- font-size: 2rem;
97
- font-weight: 700;
98
- color: var(--color-blue-55);
99
- }
106
+ .weather-value {
107
+ color: var(--weather-text-color);
108
+ font-size: var(--weather-body-font-size);
109
+ font-weight: var(--weather-value-font-weight);
110
+ }
100
111
 
101
- .unit {
102
- font-size: 1.2rem;
103
- }
112
+ .weather-unit {
113
+ color: var(--weather-text-color);
114
+ font-size: var(--weather-unit-font-size);
115
+ font-weight: var(--weather-value-font-weight);
104
116
  }
105
117
 
106
- .weather-today-humidity {
107
- margin-left: 1.4rem;
118
+ .weather-range {
119
+ color: var(--weather-text-color);
120
+ font-size: var(--weather-body-font-size);
121
+ font-weight: var(--weather-value-font-weight);
108
122
  }
109
123
 
110
124
  .weather-alert {
111
- width: fit-content;
112
- height: 2.6rem;
113
- padding: 0 1rem;
114
- margin-left: 1rem;
115
- border-radius: 0.8rem;
116
- background-color: var(--color-cool-gray-95, #f4f6f8);
117
125
  display: flex;
118
126
  align-items: center;
119
-
120
- &-text {
121
- height: fit-content;
122
- font-size: 0;
123
-
124
- span {
125
- font-size: 1.2rem;
126
- color: var(--color-blue-55, #007cdb);
127
- font-weight: 600;
128
- line-height: 1.6;
129
- }
130
- }
127
+ justify-content: center;
128
+ width: fit-content;
129
+ height: var(--weather-alert-height);
130
+ padding: 0 var(--weather-alert-padding-horizontal);
131
+ border-radius: var(--weather-alert-radius);
132
+ background-color: var(--weather-alert-background);
133
+ box-sizing: border-box;
131
134
  }
132
135
 
133
- .weather-next-days-container {
134
- @extend .weather-base-container;
136
+ .weather-alert-loading {
137
+ display: flex;
138
+ align-items: center;
139
+ width: fit-content;
140
+ height: var(--weather-page-header-height);
135
141
  }
136
142
 
137
- .weather-next-days-text {
138
- @extend .weather-base-text-info;
139
-
140
- dt {
141
- margin-right: 0.8rem;
142
- }
143
-
144
- dd:nth-of-type(n + 2) {
145
- margin-left: 0.8rem;
143
+ .weather-alert-text {
144
+ display: flex;
145
+ align-items: center;
146
+ color: var(--weather-alert-text-color);
147
+ font-size: var(--weather-alert-font-size);
148
+ font-weight: var(--weather-alert-font-weight);
149
+ line-height: var(--weather-body-line-height);
150
+ letter-spacing: var(--weather-body-letter-spacing);
151
+ }
146
152
 
147
- .unit {
148
- font-size: 1rem;
149
- }
150
- }
153
+ .weather-alert-text span {
154
+ color: inherit;
155
+ font-size: inherit;
156
+ font-weight: inherit;
157
+ line-height: inherit;
151
158
  }
@@ -22,6 +22,26 @@ export type WeatherGeoCoordinate = {
22
22
  lng: number | null;
23
23
  };
24
24
 
25
+ /**
26
+ * 날씨 API locale 요청 옵션.
27
+ * @property {string} [locale] 요청 언어 코드. 기본 지원값은 ko, en, ja이며 타입은 확장 가능한 string으로 유지한다.
28
+ */
29
+ export interface WeatherApiLocaleOptions {
30
+ /**
31
+ * 요청 언어 코드. 기본 지원값은 ko, en, ja이며 타입은 확장 가능한 string으로 유지한다.
32
+ */
33
+ locale?: string;
34
+ }
35
+
36
+ /**
37
+ * OpenWeatherMap 요청 파라미터.
38
+ * @property {number | null} lat 위도
39
+ * @property {number | null} lng 경도
40
+ * @property {string} [locale] 요청 언어 코드
41
+ */
42
+ export type WeatherOpenWeatherMapParams = WeatherGeoCoordinate &
43
+ WeatherApiLocaleOptions;
44
+
25
45
  /**
26
46
  * 좌표와 주소 정보를 함께 담는 구조.
27
47
  * @property {string | null} address 좌표 주소
@@ -2,3 +2,5 @@ export type * from "./base";
2
2
  export type * from "./api";
3
3
  export type * from "./korea";
4
4
  export type * from "./open-weather-map";
5
+ export type * from "./page-header";
6
+ export type * from "./provider";
@@ -0,0 +1,277 @@
1
+ import type {
2
+ API_Res_WeatherKoreaForecast,
3
+ API_Res_WeatherKoreaNextDays,
4
+ API_Res_WeatherKoreaNow,
5
+ } from "./api";
6
+ import type {
7
+ OWM_Res_Weather_Forecast,
8
+ OWM_Res_Weather_Now,
9
+ } from "./open-weather-map";
10
+
11
+ /**
12
+ * Weather Page Header; locale 옵션
13
+ * @property {string} [locale] 표시 언어 코드. 기본 지원값은 ko, en, ja이며 타입은 확장 가능한 string으로 유지한다.
14
+ */
15
+ export interface WeatherLocaleOptions {
16
+ /**
17
+ * 표시 언어 코드. 기본 지원값은 ko, en, ja이며 타입은 확장 가능한 string으로 유지한다.
18
+ */
19
+ locale?: string;
20
+ }
21
+
22
+ /**
23
+ * Weather Page Header; 텍스트 옵션
24
+ * @property {string} currentWeatherLoading 현재 날씨 로딩 문구
25
+ * @property {string} forecastWeatherLoading 예보 날씨 로딩 문구
26
+ * @property {string} alertLoading 특보 로딩 문구
27
+ * @property {string} currentLabel 현재 기온 라벨
28
+ * @property {string} maxTemperatureLabel 최고 기온 라벨
29
+ * @property {string} minTemperatureLabel 최저 기온 라벨
30
+ * @property {string} humidityLabel 습도 라벨
31
+ * @property {string} tomorrowLabel 내일 라벨
32
+ * @property {string} dayAfterTomorrowLabel 모레 라벨
33
+ * @property {string} weatherIconAlt 날씨 아이콘 기본 대체 텍스트
34
+ * @property {string} addressIconAlt 위치 아이콘 대체 텍스트
35
+ * @property {string} conditionFallbackLabel 날씨 상태 fallback 텍스트
36
+ * @property {string} alertPreliminaryLevelLabel 예비 특보 수준 라벨
37
+ * @property {string} alertWatchLevelLabel 주의보 수준 라벨
38
+ * @property {string} alertCancelCommandLabel 특보 해제 명령 라벨
39
+ * @property {string} alertIssueCommandLabel 특보 발령 명령 라벨
40
+ */
41
+ export interface WeatherPageHeaderTexts {
42
+ /**
43
+ * 현재 날씨 로딩 문구
44
+ */
45
+ currentWeatherLoading: string;
46
+ /**
47
+ * 예보 날씨 로딩 문구
48
+ */
49
+ forecastWeatherLoading: string;
50
+ /**
51
+ * 특보 로딩 문구
52
+ */
53
+ alertLoading: string;
54
+ /**
55
+ * 현재 기온 라벨
56
+ */
57
+ currentLabel: string;
58
+ /**
59
+ * 최고 기온 라벨
60
+ */
61
+ maxTemperatureLabel: string;
62
+ /**
63
+ * 최저 기온 라벨
64
+ */
65
+ minTemperatureLabel: string;
66
+ /**
67
+ * 습도 라벨
68
+ */
69
+ humidityLabel: string;
70
+ /**
71
+ * 내일 라벨
72
+ */
73
+ tomorrowLabel: string;
74
+ /**
75
+ * 모레 라벨
76
+ */
77
+ dayAfterTomorrowLabel: string;
78
+ /**
79
+ * 날씨 아이콘 기본 대체 텍스트
80
+ */
81
+ weatherIconAlt: string;
82
+ /**
83
+ * 위치 아이콘 대체 텍스트
84
+ */
85
+ addressIconAlt: string;
86
+ /**
87
+ * 날씨 상태 fallback 텍스트
88
+ */
89
+ conditionFallbackLabel: string;
90
+ /**
91
+ * 예비 특보 수준 라벨
92
+ */
93
+ alertPreliminaryLevelLabel: string;
94
+ /**
95
+ * 주의보 수준 라벨
96
+ */
97
+ alertWatchLevelLabel: string;
98
+ /**
99
+ * 특보 해제 명령 라벨
100
+ */
101
+ alertCancelCommandLabel: string;
102
+ /**
103
+ * 특보 발령 명령 라벨
104
+ */
105
+ alertIssueCommandLabel: string;
106
+ }
107
+
108
+ /**
109
+ * Weather Page Header; locale과 텍스트 override 조합 옵션
110
+ * @property {string} [locale] 표시 언어 코드
111
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
112
+ */
113
+ export interface WeatherPageHeaderLocaleOptions extends WeatherLocaleOptions {
114
+ /**
115
+ * 서비스에서 주입한 표시 문구
116
+ */
117
+ texts?: Partial<WeatherPageHeaderTexts>;
118
+ }
119
+
120
+ /**
121
+ * Weather Page Header; KMA weather query 결과
122
+ * @property {API_Res_WeatherKoreaNow} [now] 현재 날씨 응답
123
+ * @property {API_Res_WeatherKoreaForecast} [forecast] 예보 날씨 응답
124
+ * @property {boolean} isFetchingNow 현재 날씨 조회 상태
125
+ * @property {boolean} isFetchingForecast 예보 날씨 조회 상태
126
+ */
127
+ export interface WeatherPageHeaderKoreaWeather {
128
+ /**
129
+ * 현재 날씨 응답
130
+ */
131
+ now?: API_Res_WeatherKoreaNow;
132
+ /**
133
+ * 예보 날씨 응답
134
+ */
135
+ forecast?: API_Res_WeatherKoreaForecast;
136
+ /**
137
+ * 현재 날씨 조회 상태
138
+ */
139
+ isFetchingNow: boolean;
140
+ /**
141
+ * 예보 날씨 조회 상태
142
+ */
143
+ isFetchingForecast: boolean;
144
+ }
145
+
146
+ /**
147
+ * Weather Page Header; OpenWeatherMap query 결과
148
+ * @property {OWM_Res_Weather_Now} [now] 현재 날씨 응답
149
+ * @property {OWM_Res_Weather_Forecast} [forecast] 예보 날씨 응답
150
+ * @property {boolean} isFetchingNow 현재 날씨 조회 상태
151
+ * @property {boolean} isFetchingForecast 예보 날씨 조회 상태
152
+ */
153
+ export interface WeatherPageHeaderOpenWeatherMapWeather {
154
+ /**
155
+ * 현재 날씨 응답
156
+ */
157
+ now?: OWM_Res_Weather_Now;
158
+ /**
159
+ * 예보 날씨 응답
160
+ */
161
+ forecast?: OWM_Res_Weather_Forecast;
162
+ /**
163
+ * 현재 날씨 조회 상태
164
+ */
165
+ isFetchingNow: boolean;
166
+ /**
167
+ * 예보 날씨 조회 상태
168
+ */
169
+ isFetchingForecast: boolean;
170
+ }
171
+
172
+ /**
173
+ * Weather Page Header; 상위 container에서 준비한 weather query 결과
174
+ * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
175
+ * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
176
+ */
177
+ export interface WeatherPageHeaderDataOptions {
178
+ /**
179
+ * KMA weather query 결과
180
+ */
181
+ koreaWeather?: WeatherPageHeaderKoreaWeather;
182
+ /**
183
+ * OpenWeatherMap query 결과
184
+ */
185
+ openWeatherMapWeather?: WeatherPageHeaderOpenWeatherMapWeather;
186
+ }
187
+
188
+ /**
189
+ * Weather Page Header; container props
190
+ * @property {string} [locale] 표시 언어 코드
191
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
192
+ */
193
+ export type WeatherPageHeaderContainerProps = WeatherPageHeaderLocaleOptions;
194
+
195
+ /**
196
+ * Weather Page Header; address props
197
+ * @property {string} [locale] 표시 언어 코드
198
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
199
+ */
200
+ export type WeatherPageHeaderAddressProps = WeatherPageHeaderLocaleOptions;
201
+
202
+ /**
203
+ * Weather Page Header; today props
204
+ * @property {string} [locale] 표시 언어 코드
205
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
206
+ * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
207
+ * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
208
+ */
209
+ export type WeatherPageHeaderTodayProps = WeatherPageHeaderLocaleOptions &
210
+ WeatherPageHeaderDataOptions;
211
+
212
+ /**
213
+ * Weather Page Header; forecast props
214
+ * @property {string} [locale] 표시 언어 코드
215
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
216
+ * @property {WeatherPageHeaderKoreaWeather} [koreaWeather] KMA weather query 결과
217
+ * @property {WeatherPageHeaderOpenWeatherMapWeather} [openWeatherMapWeather] OpenWeatherMap query 결과
218
+ */
219
+ export type WeatherPageHeaderForecastProps = WeatherPageHeaderLocaleOptions &
220
+ WeatherPageHeaderDataOptions;
221
+
222
+ /**
223
+ * Weather Page Header; alert props
224
+ * @property {string} [locale] 표시 언어 코드
225
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
226
+ */
227
+ export type WeatherPageHeaderAlertProps = WeatherPageHeaderLocaleOptions;
228
+
229
+ /**
230
+ * Weather Page Header; next days props
231
+ * @property {string} title 날짜 라벨
232
+ * @property {API_Res_WeatherKoreaNextDays} [data] 예보 데이터
233
+ * @property {string} [locale] 표시 언어 코드
234
+ * @property {Partial<WeatherPageHeaderTexts>} [texts] 서비스에서 주입한 표시 문구
235
+ */
236
+ export interface WeatherPageHeaderNextDaysProps extends WeatherPageHeaderLocaleOptions {
237
+ /**
238
+ * 날짜 라벨
239
+ */
240
+ title: string;
241
+ /**
242
+ * 예보 데이터
243
+ */
244
+ data?: API_Res_WeatherKoreaNextDays;
245
+ }
246
+
247
+ /**
248
+ * Weather Icon; 날씨 아이콘 props
249
+ * @property {string | null} [code] 날씨 아이콘 코드
250
+ * @property {string | null} [name] 날씨 상태 이름
251
+ * @property {string} [alt] 아이콘 대체 텍스트 fallback
252
+ */
253
+ export interface WeatherIconProps {
254
+ /**
255
+ * 날씨 아이콘 코드
256
+ */
257
+ code?: string | null;
258
+ /**
259
+ * 날씨 상태 이름
260
+ */
261
+ name?: string | null;
262
+ /**
263
+ * 아이콘 대체 텍스트 fallback
264
+ */
265
+ alt?: string;
266
+ }
267
+
268
+ /**
269
+ * Weather Address Icon; 위치 아이콘 props
270
+ * @property {string} [alt] 아이콘 대체 텍스트
271
+ */
272
+ export interface WeatherAddressIconProps {
273
+ /**
274
+ * 아이콘 대체 텍스트
275
+ */
276
+ alt?: string;
277
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Weather Provider; provider 식별자
3
+ * @desc 현재 확정된 provider만 나열하고, 국가별 상세 API 체계는 후속 결정에서 확장한다.
4
+ */
5
+ export type WeatherProviderKey = "kma" | "openWeatherMap";
6
+
7
+ /**
8
+ * Weather Provider; provider별 지원 기능
9
+ * @property {boolean} now 현재 날씨 지원 여부
10
+ * @property {boolean} forecast 예보 날씨 지원 여부
11
+ * @property {boolean} alert 특보 지원 여부
12
+ */
13
+ export interface WeatherProviderCapability {
14
+ /**
15
+ * 현재 날씨 지원 여부
16
+ */
17
+ now: boolean;
18
+ /**
19
+ * 예보 날씨 지원 여부
20
+ */
21
+ forecast: boolean;
22
+ /**
23
+ * 특보 지원 여부
24
+ */
25
+ alert: boolean;
26
+ }
27
+
28
+ /**
29
+ * Weather Provider; provider capability registry
30
+ */
31
+ export type WeatherProviderCapabilityRegistry = Record<
32
+ WeatherProviderKey,
33
+ WeatherProviderCapability
34
+ >;
@@ -2,3 +2,4 @@ export * from "./location";
2
2
  export * from "./date-time";
3
3
  export * from "./weather";
4
4
  export * from "./alert";
5
+ export * from "./locale";