@asgard-js/react 0.0.43-canary.24 → 0.0.43-canary.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asgard-js/react",
3
- "version": "0.0.43-canary.24",
3
+ "version": "0.0.43-canary.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
Binary file
@@ -1,61 +1,33 @@
1
- .api_key_input {
2
- width: 360px;
3
- max-width: calc(100vw - 32px);
1
+ .container {
2
+ width: 220px;
4
3
  background-color: var(--asg-color-bg);
5
4
  border-radius: 12px;
6
- padding: 24px;
5
+ padding: 20px;
7
6
  border: 0.5px solid var(--asg-color-border);
8
-
9
- @media (max-width: 480px) {
10
- width: 100%;
11
- max-width: none;
12
- padding: 20px;
13
- margin: 0 16px;
14
- }
15
- }
16
-
17
- .api_key_input__header {
18
- display: flex;
19
- flex-direction: column;
20
- gap: 8px;
21
- align-items: center;
22
- margin-bottom: 20px;
23
7
  }
24
8
 
25
- .api_key_input__icon {
26
- width: 40px;
27
- height: 40px;
28
- }
29
-
30
- .api_key_input__title {
31
- margin: 0;
32
- font-size: 20px;
33
- font-weight: 500;
34
- color: white;
35
- }
36
-
37
- .api_key_input__form {
9
+ .form {
38
10
  width: 100%;
39
11
  display: flex;
40
12
  flex-direction: column;
41
13
  gap: 20px;
42
14
  }
43
15
 
44
- .api_key_input__label {
16
+ .label {
45
17
  display: block;
46
18
  font-size: 14px;
47
19
  color: rgba(255, 255, 255, 0.7);
48
20
  margin-bottom: 8px;
49
21
  }
50
22
 
51
- .api_key_input__input_wrapper {
23
+ .inputWrapper {
52
24
  position: relative;
53
25
  width: 100%;
54
26
  }
55
27
 
56
- .api_key_input__input {
28
+ .input {
57
29
  width: 100%;
58
- height: 48px;
30
+ height: 42px;
59
31
  padding: 0 40px 0 12px;
60
32
  font-size: 14px;
61
33
  font-weight: 400;
@@ -67,11 +39,6 @@
67
39
  transition: all 0.2s ease;
68
40
  box-sizing: border-box;
69
41
 
70
- @media (max-width: 480px) {
71
- height: 44px;
72
- font-size: 16px;
73
- }
74
-
75
42
  &::placeholder {
76
43
  color: rgba(255, 255, 255, 0.4);
77
44
  }
@@ -81,18 +48,18 @@
81
48
  background: rgba(255, 255, 255, 0.08);
82
49
  }
83
50
 
84
- &--error {
85
- border-color: #FF4D4F;
86
- background: rgba(255, 77, 79, 0.05);
51
+ &.error {
52
+ border-color: rgba(255, 69, 58, 0.6);
53
+ background: rgba(255, 69, 58, 0.05);
87
54
  }
88
55
 
89
- &--disabled {
56
+ &.disabled {
90
57
  opacity: 0.5;
91
58
  cursor: not-allowed;
92
59
  }
93
60
  }
94
61
 
95
- .api_key_input__toggle_button {
62
+ .toggleButton {
96
63
  position: absolute;
97
64
  right: 8px;
98
65
  top: 50%;
@@ -119,23 +86,23 @@
119
86
  }
120
87
  }
121
88
 
122
- .api_key_input__toggle_icon {
89
+ .toggleIcon {
123
90
  width: 16px;
124
91
  height: 16px;
125
92
  }
126
93
 
127
- .api_key_input__error_message {
94
+ .errorMessage {
128
95
  margin-top: 6px;
129
96
  font-size: 12px;
130
- color: #FF4D4F;
97
+ color: rgba(255, 69, 58, 0.8);
131
98
  }
132
99
 
133
- .api_key_input__submit_button {
100
+ .submitButton {
134
101
  width: 100%;
135
- height: 48px;
102
+ height: 42px;
103
+ background: #5856d6;
136
104
  border: none;
137
105
  border-radius: 6px;
138
- background-color: #5856d6;
139
106
  color: white;
140
107
  font-size: 14px;
141
108
  font-weight: 500;
@@ -143,9 +110,13 @@
143
110
  transition: all 0.2s ease;
144
111
  outline: none;
145
112
 
146
- @media (max-width: 480px) {
147
- height: 44px;
148
- font-size: 16px;
113
+ &:hover:not(:disabled) {
114
+ background: #4845c7;
115
+ transform: translateY(-1px);
116
+ }
117
+
118
+ &:active:not(:disabled) {
119
+ transform: translateY(0);
149
120
  }
150
121
 
151
122
  &:disabled {
@@ -153,4 +124,41 @@
153
124
  cursor: not-allowed;
154
125
  transform: none;
155
126
  }
127
+
128
+ &.loading {
129
+ position: relative;
130
+ color: transparent;
131
+
132
+ &::after {
133
+ content: '';
134
+ position: absolute;
135
+ top: 50%;
136
+ left: 50%;
137
+ width: 16px;
138
+ height: 16px;
139
+ margin-left: -8px;
140
+ margin-top: -8px;
141
+ border: 2px solid transparent;
142
+ border-top: 2px solid white;
143
+ border-radius: 50%;
144
+ animation: spin 1s linear infinite;
145
+ }
146
+ }
147
+ }
148
+
149
+ @keyframes spin {
150
+ 0% {
151
+ transform: rotate(0deg);
152
+ }
153
+ 100% {
154
+ transform: rotate(360deg);
155
+ }
156
+ }
157
+
158
+ // 響應式設計
159
+ @media (max-width: 280px) {
160
+ .container {
161
+ width: 100%;
162
+ min-width: 200px;
163
+ }
156
164
  }
@@ -1,10 +1,6 @@
1
1
  import { useState, FormEvent, ChangeEvent } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { useAsgardThemeContext } from '../../../context/asgard-theme-context';
4
- import { useAsgardContext } from '../../../context/asgard-service-context';
5
- import { ProfileIcon } from '../profile-icon';
6
- import EyeSvg from '../../../icons/eye.svg?react';
7
- import EyeOffSvg from '../../../icons/eye-off.svg?react';
8
4
  import styles from './api-key-input.module.scss';
9
5
 
10
6
  export interface ApiKeyInputProps {
@@ -12,7 +8,6 @@ export interface ApiKeyInputProps {
12
8
  loading?: boolean;
13
9
  error?: string;
14
10
  placeholder?: string;
15
- title?: string;
16
11
  showToggle?: boolean;
17
12
  className?: string;
18
13
  }
@@ -22,14 +17,12 @@ export function ApiKeyInput({
22
17
  loading = false,
23
18
  error,
24
19
  placeholder = 'Enter your key',
25
- title = 'Preview',
26
20
  showToggle = true,
27
21
  className,
28
22
  }: ApiKeyInputProps): JSX.Element {
29
23
  const [apiKey, setApiKey] = useState('');
30
24
  const [showPassword, setShowPassword] = useState(false);
31
25
  const { chatbot } = useAsgardThemeContext();
32
- const { avatar } = useAsgardContext();
33
26
 
34
27
  const handleSubmit = (e: FormEvent): void => {
35
28
  e.preventDefault();
@@ -48,29 +41,24 @@ export function ApiKeyInput({
48
41
 
49
42
  return (
50
43
  <div
51
- className={clsx(styles.api_key_input, className)}
44
+ className={clsx(styles.container, className)}
52
45
  style={{
53
46
  backgroundColor: chatbot.backgroundColor,
54
47
  borderColor: chatbot.borderColor,
55
48
  }}
56
49
  >
57
- <div className={styles.api_key_input__header}>
58
- <ProfileIcon avatar={avatar} />
59
- <h2 className={styles.api_key_input__title} style={chatbot?.header?.title?.style}>{title}</h2>
60
- </div>
61
-
62
- <form onSubmit={handleSubmit} className={styles.api_key_input__form}>
63
- <div>
64
- <label className={styles.api_key_input__label}>Key</label>
65
- <div className={styles.api_key_input__input_wrapper}>
50
+ <form onSubmit={handleSubmit} className={styles.form}>
51
+ <div className={styles.inputGroup}>
52
+ <label className={styles.label}>Key</label>
53
+ <div className={styles.inputWrapper}>
66
54
  <input
67
55
  type={showPassword ? 'text' : 'password'}
68
56
  value={apiKey}
69
57
  onChange={handleInputChange}
70
58
  placeholder={placeholder}
71
- className={clsx(styles.api_key_input__input, {
72
- [styles['api_key_input__input--error']]: error,
73
- [styles['api_key_input__input--disabled']]: loading,
59
+ className={clsx(styles.input, {
60
+ [styles.error]: error,
61
+ [styles.disabled]: loading,
74
62
  })}
75
63
  disabled={loading}
76
64
  autoComplete="off"
@@ -79,29 +67,45 @@ export function ApiKeyInput({
79
67
  <button
80
68
  type="button"
81
69
  onClick={togglePasswordVisibility}
82
- className={styles.api_key_input__toggle_button}
70
+ className={styles.toggleButton}
83
71
  disabled={loading}
84
72
  aria-label={showPassword ? 'Hide password' : 'Show password'}
85
73
  >
86
- {showPassword ? (
87
- <EyeOffSvg className={styles.api_key_input__toggle_icon} />
88
- ) : (
89
- <EyeSvg className={styles.api_key_input__toggle_icon} />
90
- )}
74
+ <svg
75
+ className={styles.toggleIcon}
76
+ width="16"
77
+ height="16"
78
+ viewBox="0 0 24 24"
79
+ fill="none"
80
+ stroke="currentColor"
81
+ strokeWidth="2"
82
+ strokeLinecap="round"
83
+ strokeLinejoin="round"
84
+ >
85
+ {showPassword ? (
86
+ <>
87
+ <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
88
+ <line x1="1" y1="1" x2="23" y2="23" />
89
+ </>
90
+ ) : (
91
+ <>
92
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
93
+ <circle cx="12" cy="12" r="3" />
94
+ </>
95
+ )}
96
+ </svg>
91
97
  </button>
92
98
  )}
93
99
  </div>
94
- {error && <div className={styles.api_key_input__error_message}>{error}</div>}
100
+ {error && <div className={styles.errorMessage}>{error}</div>}
95
101
  </div>
96
102
 
97
103
  <button
98
104
  type="submit"
99
105
  disabled={!apiKey.trim() || loading}
100
- className={styles.api_key_input__submit_button}
101
- style={{
102
- backgroundColor: chatbot?.mainColor,
103
- color: chatbot?.secondaryColor,
104
- }}
106
+ className={clsx(styles.submitButton, {
107
+ [styles.loading]: loading,
108
+ })}
105
109
  >
106
110
  {loading ? 'Loading...' : 'Continue'}
107
111
  </button>
@@ -17,13 +17,14 @@ import {
17
17
  AsgardAppInitializationContextProvider,
18
18
  AsgardServiceContextProviderProps,
19
19
  } from '../../context';
20
- import { AuthState } from '@asgard-js/core';
21
20
  import { ApiKeyInput } from './api-key-input';
22
21
  import { ChatbotHeader } from './chatbot-header';
23
22
  import { ChatbotBody } from './chatbot-body';
24
23
  import { ChatbotFooter } from './chatbot-footer';
25
24
  import { ChatbotContainer } from './chatbot-container/chatbot-container';
26
25
 
26
+ type AuthState = 'loading' | 'needApiKey' | 'authenticated' | 'error';
27
+
27
28
  interface ChatbotProps extends AsgardTemplateContextValue {
28
29
  className?: string;
29
30
  style?: CSSProperties;
@@ -122,24 +123,6 @@ export const Chatbot = forwardRef(function Chatbot(
122
123
  </div>
123
124
  );
124
125
 
125
- case 'invalidApiKey':
126
- return (
127
- <div style={{
128
- display: 'flex',
129
- alignItems: 'center',
130
- justifyContent: 'center',
131
- flex: 1,
132
- padding: '20px'
133
- }}>
134
- <ApiKeyInput
135
- title={title}
136
- onSubmit={onApiKeySubmit || (() => {})}
137
- placeholder="Enter your key"
138
- error="Please check if the key is correct."
139
- />
140
- </div>
141
- );
142
-
143
126
  case 'error':
144
127
  return (
145
128
  <div style={{
@@ -176,7 +159,7 @@ export const Chatbot = forwardRef(function Chatbot(
176
159
  };
177
160
 
178
161
  // Don't initialize SSE connection when explicitly needing API key or in error state
179
- if (authState !== 'needApiKey' && authState !== 'error' && authState !== 'invalidApiKey') {
162
+ if (authState !== 'needApiKey' && authState !== 'error') {
180
163
  return (
181
164
  <AsgardAppInitializationContextProvider
182
165
  enabled={enableLoadConfigFromService}
@@ -31,8 +31,6 @@ export interface AsgardThemeContextValue {
31
31
  backgroundColor?: CSSProperties['backgroundColor'];
32
32
  borderColor?: CSSProperties['borderColor'];
33
33
  inactiveColor?: CSSProperties['color'];
34
- mainColor?: CSSProperties['color'];
35
- secondaryColor?: CSSProperties['color'];
36
34
  primaryComponent?: {
37
35
  mainColor?: CSSProperties['color'];
38
36
  secondaryColor?: CSSProperties['color'];
@@ -269,9 +267,6 @@ export function AsgardThemeContextProvider(
269
267
  chatbot: {
270
268
  backgroundColor: themeFromAnnotations.chatbot?.backgroundColor,
271
269
  borderColor: themeFromAnnotations.chatbot?.borderColor,
272
- mainColor: themeFromAnnotations.chatbot?.primaryComponent?.mainColor,
273
- secondaryColor: themeFromAnnotations.chatbot?.primaryComponent?.secondaryColor,
274
-
275
270
  header: {
276
271
  style: {
277
272
  borderBottomColor: themeFromAnnotations.chatbot?.borderColor,
@@ -412,8 +407,6 @@ export function AsgardThemeContextProvider(
412
407
  chatbot: {
413
408
  backgroundColor: propsTheme.chatbot?.backgroundColor,
414
409
  borderColor: propsTheme.chatbot?.borderColor,
415
- mainColor: propsTheme.chatbot?.primaryComponent?.mainColor,
416
- secondaryColor: propsTheme.chatbot?.primaryComponent?.secondaryColor,
417
410
  header: {
418
411
  style: {
419
412
  borderBottomColor: propsTheme.chatbot?.borderColor,
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import 'highlight.js/styles/atom-one-dark.css';
2
2
  export * from './components';
3
3
  export * from './context';
4
- export * from './hooks';
4
+ export * from './hooks';
@@ -1,4 +0,0 @@
1
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
3
- <line x1="1" y1="1" x2="23" y2="23"/>
4
- </svg>
package/src/icons/eye.svg DELETED
@@ -1,4 +0,0 @@
1
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
3
- <circle cx="12" cy="12" r="3"/>
4
- </svg>