@scalar/api-client 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.
Files changed (59) hide show
  1. package/dist/components/SimpleTable/SimpleCell.vue.d.ts.map +1 -1
  2. package/dist/components/SimpleTable/SimpleHeader.vue.d.ts.map +1 -1
  3. package/dist/components/SimpleTable/SimpleRow.vue.d.ts.map +1 -1
  4. package/dist/components/SimpleTable/SimpleTable.vue.d.ts.map +1 -1
  5. package/dist/fixtures/index.d.ts +1 -1
  6. package/dist/fixtures/index.d.ts.map +1 -1
  7. package/dist/index.js +37 -26
  8. package/package.json +6 -6
  9. package/src/components/ApiClient/AddressBar.vue +462 -0
  10. package/src/components/ApiClient/ApiClient.vue +266 -0
  11. package/src/components/ApiClient/Request/Request.vue +271 -0
  12. package/src/components/ApiClient/Request/RequestAuth.vue +221 -0
  13. package/src/components/ApiClient/Request/RequestBody.vue +39 -0
  14. package/src/components/ApiClient/Request/RequestHeaders.vue +24 -0
  15. package/src/components/ApiClient/Request/RequestQuery.vue +25 -0
  16. package/src/components/ApiClient/Request/RequestVariables.vue +25 -0
  17. package/src/components/ApiClient/Request/index.ts +1 -0
  18. package/src/components/ApiClient/RequestHistory.vue +114 -0
  19. package/src/components/ApiClient/RequestHistoryItem.vue +59 -0
  20. package/src/components/ApiClient/Response/Copilot.vue.bak +385 -0
  21. package/src/components/ApiClient/Response/Response.vue +120 -0
  22. package/src/components/ApiClient/Response/ResponseBody.vue +23 -0
  23. package/src/components/ApiClient/Response/ResponseHeaders.vue +52 -0
  24. package/src/components/ApiClient/Response/ResponseMetaInformation.vue +58 -0
  25. package/src/components/ApiClient/Response/index.ts +1 -0
  26. package/src/components/ApiClient/index.ts +1 -0
  27. package/src/components/CodeMirror/CodeMirror.vue +232 -0
  28. package/src/components/CodeMirror/extensions/variables.ts +41 -0
  29. package/src/components/CodeMirror/index.ts +1 -0
  30. package/src/components/CollapsibleSection/CollapsibleSection.vue +149 -0
  31. package/src/components/CollapsibleSection/index.ts +1 -0
  32. package/src/components/FlowModal.vue +133 -0
  33. package/src/components/Grid/Grid.vue +511 -0
  34. package/src/components/Grid/SimpleGrid.vue +33 -0
  35. package/src/components/Grid/index.ts +2 -0
  36. package/src/components/HelpfulLink.vue +19 -0
  37. package/src/components/SimpleTable/SimpleCell.vue +47 -0
  38. package/src/components/SimpleTable/SimpleHeader.vue +17 -0
  39. package/src/components/SimpleTable/SimpleRow.vue +14 -0
  40. package/src/components/SimpleTable/SimpleTable.vue +13 -0
  41. package/src/components/SimpleTable/index.ts +4 -0
  42. package/src/fixtures/httpHeaders.ts +530 -0
  43. package/src/fixtures/httpStatusCodes.ts +259 -0
  44. package/src/fixtures/index.ts +6 -0
  45. package/src/helpers/createPlaceholderRequest.ts +16 -0
  46. package/src/helpers/generateParameters.ts +19 -0
  47. package/src/helpers/generateRequest.ts +26 -0
  48. package/src/helpers/index.ts +5 -0
  49. package/src/helpers/mapFromArray.ts +16 -0
  50. package/src/helpers/sendRequest.ts +94 -0
  51. package/src/hooks/index.ts +2 -0
  52. package/src/hooks/useCopilot.ts +64 -0
  53. package/src/hooks/useOperation.test.ts +7 -0
  54. package/src/hooks/useOperation.ts +43 -0
  55. package/src/index.ts +9 -0
  56. package/src/stores/apiClientRequestStore.ts +103 -0
  57. package/src/stores/apiClientStore.ts +57 -0
  58. package/src/stores/index.ts +5 -0
  59. package/src/types.ts +181 -0
@@ -0,0 +1,52 @@
1
+ <script lang="ts" setup>
2
+ import { httpHeaders } from '../../../fixtures'
3
+ import { CollapsibleSection } from '../../CollapsibleSection'
4
+ import {
5
+ SimpleCell,
6
+ SimpleHeader,
7
+ SimpleRow,
8
+ SimpleTable,
9
+ } from '../../SimpleTable'
10
+
11
+ defineProps<{ headers: Record<string, string>[] }>()
12
+
13
+ const getDocumentationUrlForHttpHeader = (headerName: string) => {
14
+ return httpHeaders.find((header) => {
15
+ return header.name.toLowerCase() === headerName.toLowerCase()
16
+ })?.url
17
+ }
18
+
19
+ // Make the first letter and all letters after a - uppercase
20
+ const formatHeaderName = (headerName: string) => {
21
+ return headerName
22
+ .split('-')
23
+ .map((word) => {
24
+ return word.charAt(0).toUpperCase() + word.slice(1)
25
+ })
26
+ .join('-')
27
+ }
28
+ </script>
29
+ <template>
30
+ <CollapsibleSection title="Headers">
31
+ <SimpleTable v-if="headers.length > 0">
32
+ <SimpleRow>
33
+ <SimpleHeader>Key</SimpleHeader>
34
+ <SimpleHeader>Value</SimpleHeader>
35
+ </SimpleRow>
36
+ <SimpleRow
37
+ v-for="header in headers"
38
+ :key="header.name">
39
+ <SimpleCell
40
+ :href="getDocumentationUrlForHttpHeader(header.name)"
41
+ :strong="true"
42
+ :wrap="false">
43
+ {{ formatHeaderName(header.name) }}
44
+ </SimpleCell>
45
+ <SimpleCell>{{ header.value }}</SimpleCell>
46
+ </SimpleRow>
47
+ </SimpleTable>
48
+ <template v-else>
49
+ <div class="scalar-api-client__empty-state">No Headers</div>
50
+ </template>
51
+ </CollapsibleSection>
52
+ </template>
@@ -0,0 +1,58 @@
1
+ <script lang="ts" setup>
2
+ import prettyBytes from 'pretty-bytes'
3
+ import prettyMilliseconds from 'pretty-ms'
4
+ import { computed } from 'vue'
5
+
6
+ import { type HttpStatusCode, httpStatusCodes } from '../../../fixtures'
7
+ import { type ClientResponse } from '../../../types'
8
+ import HelpfulLink from '../../HelpfulLink.vue'
9
+
10
+ const props = defineProps<{ response: any }>()
11
+
12
+ /** Size of the response */
13
+ const getContentLength = (response: ClientResponse) => {
14
+ if (response?.headers?.['X-API-Client-Content-Length']) {
15
+ return prettyBytes(
16
+ parseFloat(response.headers['X-API-Client-Content-Length']),
17
+ )
18
+ }
19
+ return prettyBytes(0)
20
+ }
21
+
22
+ /** Status text for the response */
23
+ const statusCodeInformation = computed((): HttpStatusCode | undefined => {
24
+ const responseStatusCode = props.response.statusCode
25
+
26
+ if (!responseStatusCode) {
27
+ return undefined
28
+ }
29
+
30
+ return httpStatusCodes[responseStatusCode] ?? undefined
31
+ })
32
+ </script>
33
+ <template>
34
+ <div class="meta-item">
35
+ <!-- <span>182 ms</span> -->
36
+ <span>{{ prettyMilliseconds(response.duration) }}</span>
37
+ </div>
38
+ <div class="meta-item">
39
+ <!-- <span>20 Bytes</span> -->
40
+ <span>{{ getContentLength(response) }}</span>
41
+ </div>
42
+ <div class="meta-item">
43
+ <!-- <span>200</span> -->
44
+ <span
45
+ :class="`scalar-api-client__status scalar-api-client__status--${String(
46
+ response.statusCode,
47
+ ).charAt(0)}xx`">
48
+ <template v-if="statusCodeInformation?.url">
49
+ <HelpfulLink :href="statusCodeInformation.url">
50
+ {{ response.statusCode }} {{ statusCodeInformation.name }}
51
+ </HelpfulLink>
52
+ </template>
53
+ <template v-else>
54
+ {{ response.statusCode }} {{ statusCodeInformation?.name }}
55
+ </template>
56
+ </span>
57
+ </div>
58
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Response } from './Response.vue'
@@ -0,0 +1 @@
1
+ export { default as ApiClient } from './ApiClient.vue'
@@ -0,0 +1,232 @@
1
+ <script lang="ts" setup>
2
+ import { java } from '@codemirror/lang-java'
3
+ import { javascript } from '@codemirror/lang-javascript'
4
+ import { json } from '@codemirror/lang-json'
5
+ import { python } from '@codemirror/lang-python'
6
+ import { type LanguageSupport, StreamLanguage } from '@codemirror/language'
7
+ import {
8
+ c,
9
+ csharp,
10
+ kotlin,
11
+ objectiveC,
12
+ } from '@codemirror/legacy-modes/mode/clike'
13
+ import { clojure } from '@codemirror/legacy-modes/mode/clojure'
14
+ import { go } from '@codemirror/legacy-modes/mode/go'
15
+ import { http } from '@codemirror/legacy-modes/mode/http'
16
+ import { oCaml } from '@codemirror/legacy-modes/mode/mllike'
17
+ import { powerShell } from '@codemirror/legacy-modes/mode/powershell'
18
+ import { r } from '@codemirror/legacy-modes/mode/r'
19
+ import { ruby } from '@codemirror/legacy-modes/mode/ruby'
20
+ import { shell } from '@codemirror/legacy-modes/mode/shell'
21
+ import { swift } from '@codemirror/legacy-modes/mode/swift'
22
+ import { type Extension } from '@codemirror/state'
23
+ import {
24
+ EditorView,
25
+ type ViewUpdate,
26
+ keymap,
27
+ lineNumbers as lineNumbersExtension,
28
+ } from '@codemirror/view'
29
+ import { useCodeMirror } from '@scalar/use-codemirror'
30
+ import { watch } from 'vue'
31
+
32
+ import { variables } from './extensions/variables'
33
+
34
+ const props = withDefaults(
35
+ defineProps<{
36
+ content?: string
37
+ readOnly?: boolean
38
+ languages?: Language[]
39
+ withVariables?: boolean
40
+ lineNumbers?: boolean
41
+ withoutTheme?: boolean
42
+ disableEnter?: boolean
43
+ }>(),
44
+ {
45
+ disableEnter: false,
46
+ },
47
+ )
48
+
49
+ const emit = defineEmits<{
50
+ (e: 'change', value: string): void
51
+ }>()
52
+
53
+ // TODO: Add 'php' and 'laravel'
54
+ const syntaxHighlighting: Partial<
55
+ Record<Language, LanguageSupport | StreamLanguage<any>>
56
+ > = {
57
+ axios: javascript(),
58
+ c: StreamLanguage.define(c),
59
+ clojure: StreamLanguage.define(clojure),
60
+ csharp: StreamLanguage.define(csharp),
61
+ go: StreamLanguage.define(go),
62
+ http: StreamLanguage.define(http),
63
+ java: java(),
64
+ javascript: javascript(),
65
+ json: json(),
66
+ kotlin: StreamLanguage.define(kotlin),
67
+ node: javascript(),
68
+ objc: StreamLanguage.define(objectiveC),
69
+ ocaml: StreamLanguage.define(oCaml),
70
+ powershell: StreamLanguage.define(powerShell),
71
+ python: python(),
72
+ r: StreamLanguage.define(r),
73
+ ruby: StreamLanguage.define(ruby),
74
+ shell: StreamLanguage.define(shell),
75
+ swift: StreamLanguage.define(swift),
76
+ }
77
+
78
+ type Language =
79
+ | 'axios'
80
+ | 'c'
81
+ | 'clojure'
82
+ | 'csharp'
83
+ | 'go'
84
+ | 'http'
85
+ | 'java'
86
+ | 'javascript'
87
+ | 'json'
88
+ | 'kotlin'
89
+ | 'node'
90
+ | 'objc'
91
+ | 'ocaml'
92
+ | 'powershell'
93
+ | 'python'
94
+ | 'r'
95
+ | 'ruby'
96
+ | 'shell'
97
+ | 'swift'
98
+ | 'php'
99
+
100
+ // CSS Class
101
+ const classes = ['scalar-api-client__codemirror']
102
+
103
+ if (props.readOnly) {
104
+ classes.push('scalar-api-client__codemirror--read-only')
105
+ }
106
+
107
+ const getCodeMirrorExtensions = () => {
108
+ const extensions: Extension[] = []
109
+
110
+ extensions.push(EditorView.editorAttributes.of({ class: classes.join(' ') }))
111
+
112
+ // Read only
113
+ if (props.readOnly) {
114
+ extensions.push(EditorView.editable.of(false))
115
+ }
116
+
117
+ // Syntax highlighting
118
+ if (props.languages) {
119
+ props.languages
120
+ .filter((language) => typeof syntaxHighlighting[language] !== 'undefined')
121
+ .forEach((language) => {
122
+ extensions.push(syntaxHighlighting[language] as Extension)
123
+ })
124
+ }
125
+
126
+ // Line numbers
127
+ if (props.lineNumbers) {
128
+ extensions.push(lineNumbersExtension())
129
+ }
130
+
131
+ // Highlight variables
132
+ if (props.withVariables) {
133
+ extensions.push(variables())
134
+ }
135
+
136
+ if (props.disableEnter) {
137
+ extensions.push(
138
+ keymap.of([
139
+ {
140
+ key: 'Enter',
141
+ run: () => {
142
+ return true
143
+ },
144
+ },
145
+ {
146
+ key: 'Ctrl-Enter',
147
+ mac: 'Cmd-Enter',
148
+ run: () => {
149
+ return true
150
+ },
151
+ },
152
+ {
153
+ key: 'Shift-Enter',
154
+ run: () => {
155
+ return true
156
+ },
157
+ },
158
+ ]),
159
+ )
160
+ }
161
+
162
+ // Listen to updates
163
+ extensions.push(
164
+ EditorView.updateListener.of((v: ViewUpdate) => {
165
+ if (!v.docChanged) {
166
+ return
167
+ }
168
+
169
+ emit('change', v.state.doc.toString())
170
+ }),
171
+ )
172
+
173
+ return extensions
174
+ }
175
+
176
+ const { codeMirrorRef, setCodeMirrorContent, reconfigureCodeMirror } =
177
+ useCodeMirror({
178
+ content: props.content ?? '',
179
+ extensions: getCodeMirrorExtensions(),
180
+ withoutTheme: props.withoutTheme,
181
+ })
182
+
183
+ watch(props, () => {
184
+ setCodeMirrorContent(props.content ?? '')
185
+ reconfigureCodeMirror(getCodeMirrorExtensions())
186
+ })
187
+ </script>
188
+
189
+ <template>
190
+ <div
191
+ ref="codeMirrorRef"
192
+ class="scalar-api-client__codemirror__wrapper" />
193
+ </template>
194
+
195
+ <style>
196
+ /** Basics */
197
+ .scalar-api-client__codemirror__wrapper {
198
+ width: 100%;
199
+ display: flex;
200
+ align-items: stretch;
201
+ }
202
+
203
+ .scalar-api-client__codemirror {
204
+ flex-grow: 1;
205
+ max-width: 100%;
206
+ }
207
+
208
+ .scalar-api-client__codemirror.ͼw {
209
+ background-color: var(--theme-background-1);
210
+ }
211
+
212
+ .scalar-api-client__codemirror--read-only.ͼw {
213
+ background-color: var(--theme-background-2);
214
+ }
215
+
216
+ /** URL input */
217
+ .scalar-api-client__url-input {
218
+ font-weight: var(--theme-semibold);
219
+ }
220
+
221
+ .scalar-api-client__url-input .cm-scroller {
222
+ padding-left: 6px;
223
+ }
224
+
225
+ .scalar-api-client__url-input .ͼ1 .cm-scroller {
226
+ align-items: center !important;
227
+ }
228
+
229
+ .scalar-api-client__variable {
230
+ color: var(--scalar-api-client-color);
231
+ }
232
+ </style>
@@ -0,0 +1,41 @@
1
+ import {
2
+ Decoration,
3
+ type DecorationSet,
4
+ EditorView,
5
+ MatchDecorator,
6
+ ViewPlugin,
7
+ type ViewUpdate,
8
+ } from '@codemirror/view'
9
+
10
+ const variableHighlighterDecoration = new MatchDecorator({
11
+ regexp: /(\{[^}]+\})/g,
12
+ decoration: () =>
13
+ Decoration.mark({
14
+ attributes: {
15
+ class: 'scalar-api-client__variable',
16
+ },
17
+ }),
18
+ })
19
+
20
+ export const variables = () =>
21
+ ViewPlugin.fromClass(
22
+ class {
23
+ variables: DecorationSet
24
+ constructor(view: EditorView) {
25
+ this.variables = variableHighlighterDecoration.createDeco(view)
26
+ }
27
+ update(update: ViewUpdate) {
28
+ this.variables = variableHighlighterDecoration.updateDeco(
29
+ update,
30
+ this.variables,
31
+ )
32
+ }
33
+ },
34
+ {
35
+ decorations: (instance) => instance.variables,
36
+ provide: (plugin) =>
37
+ EditorView.atomicRanges.of(
38
+ (view) => view.plugin(plugin)?.variables || Decoration.none,
39
+ ),
40
+ },
41
+ )
@@ -0,0 +1 @@
1
+ export { default as CodeMirror } from './CodeMirror.vue'
@@ -0,0 +1,149 @@
1
+ <script lang="ts" setup>
2
+ import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
3
+
4
+ defineProps<{
5
+ title?: string
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <Disclosure
11
+ v-slot="{ open }"
12
+ :defaultOpen="true">
13
+ <div
14
+ class="scalar-api-client__item"
15
+ :class="{ 'scalar-api-client__item--open': open }">
16
+ <DisclosureButton class="scalar-api-client__toggle">
17
+ <svg
18
+ class="scalar-api-client__toggle__icon"
19
+ height="10"
20
+ viewBox="0 0 5 10"
21
+ width="5"
22
+ xmlns="http://www.w3.org/2000/svg">
23
+ <path
24
+ d="M0 10l5-5-5-5z"
25
+ fill="currentColor"
26
+ fill-rule="nonzero" />
27
+ </svg>
28
+ <span class="scalar-api-client__item__title">
29
+ {{ title }}
30
+ </span>
31
+ <div
32
+ v-if="$slots.options && open"
33
+ class="scalar-api-client__item__options">
34
+ <slot name="options" />
35
+ </div>
36
+ </DisclosureButton>
37
+ <DisclosurePanel>
38
+ <div class="scalar-api-client__item__content">
39
+ <slot />
40
+ </div>
41
+ </DisclosurePanel>
42
+ </div>
43
+ </Disclosure>
44
+ </template>
45
+
46
+ <style>
47
+ .scalar-api-client__item {
48
+ border-radius: var(--theme-radius-lg);
49
+ margin-bottom: 6px;
50
+ background: var(--theme-background-2);
51
+ box-shadow: var(--shadow1);
52
+ position: relative;
53
+ }
54
+
55
+ .scalar-api-client__item button {
56
+ background-color: transparent;
57
+ text-align: left;
58
+ }
59
+
60
+ .scalar-api-client__item:hover {
61
+ cursor: pointer;
62
+ }
63
+
64
+ .scalar-api-client__item--open {
65
+ background: var(--theme-background-2);
66
+ }
67
+
68
+ .scalar-api-client__item--open:focus-within {
69
+ box-shadow: var(--shadow1);
70
+ }
71
+
72
+ .scalar-api-client__item--open .scalar-api-client__item__content {
73
+ display: flex;
74
+ }
75
+
76
+ .scalar-api-client__item--open:hover {
77
+ cursor: default;
78
+ }
79
+
80
+ .scalar-api-client__item--open .scalar-api-client__toggle__icon {
81
+ transform: rotate(90deg);
82
+ }
83
+ .scalar-api-client__toggle {
84
+ padding: 6px 12px;
85
+ min-height: 37px;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: space-between;
89
+ position: relative;
90
+ width: 100%;
91
+ }
92
+
93
+ .scalar-api-client__item .scalar-api-client__item__title {
94
+ color: var(--theme-color-1);
95
+ font-size: var(--theme-small);
96
+ font-weight: var(--theme-bold);
97
+ user-select: none;
98
+ flex: 1;
99
+ }
100
+
101
+ .scalar-api-client__item .scalar-api-client__item__title:after {
102
+ content: '';
103
+ position: absolute;
104
+ top: 0;
105
+ left: 0;
106
+ width: 100%;
107
+ height: 100%;
108
+ display: block;
109
+ }
110
+
111
+ .scalar-api-client__item .scalar-api-client__toggle__icon {
112
+ width: 10px;
113
+ margin-right: 6px;
114
+ color: var(--theme-color-1);
115
+ }
116
+
117
+ .scalar-api-client__item__options {
118
+ position: relative;
119
+ }
120
+
121
+ .scalar-api-client__item__options span {
122
+ background: var(--theme-background-3);
123
+ padding: 2px 6px;
124
+ border-radius: 3px;
125
+ font-size: 12px;
126
+ pointer-events: none;
127
+ color: var(--theme-color-2);
128
+ border: 1px solid var(--theme-border-color);
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ }
133
+
134
+ .scalar-api-client__item__options span svg {
135
+ width: 9px;
136
+ height: 9px;
137
+ margin-left: 3px;
138
+ }
139
+
140
+ .scalar-api-client__item__options select {
141
+ position: absolute;
142
+ top: 0;
143
+ left: 0;
144
+ width: 100%;
145
+ height: 100%;
146
+ opacity: 0;
147
+ cursor: pointer;
148
+ }
149
+ </style>
@@ -0,0 +1 @@
1
+ export { default as CollapsibleSection } from './CollapsibleSection.vue'
@@ -0,0 +1,133 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ Dialog,
4
+ DialogDescription,
5
+ DialogPanel,
6
+ DialogTitle,
7
+ } from '@headlessui/vue'
8
+ import { reactive } from 'vue'
9
+
10
+ withDefaults(
11
+ defineProps<{
12
+ state: ModalState
13
+ title?: string
14
+ bodyClass?: string
15
+ maxWidth?: string
16
+ variant?: 'small' | 'normal' | 'large'
17
+ }>(),
18
+ {
19
+ variant: 'normal',
20
+ },
21
+ )
22
+ </script>
23
+ <script lang="ts">
24
+ export type ModalState = ReturnType<typeof useModalState>
25
+
26
+ export const useModalState = () =>
27
+ reactive({
28
+ open: false,
29
+ show() {
30
+ this.open = true
31
+ },
32
+ hide() {
33
+ this.open = false
34
+ },
35
+ })
36
+ </script>
37
+ <template>
38
+ <Dialog
39
+ :open="state.open"
40
+ @close="state.hide()">
41
+ <div class="modal-layout">
42
+ <DialogPanel
43
+ class="modal"
44
+ :class="{
45
+ 'modal-content-large': variant === 'large',
46
+ 'modal-content-normal': variant === 'normal',
47
+ 'modal-content-small': variant === 'small',
48
+ }"
49
+ :style="{ maxWidth }">
50
+ <DialogTitle
51
+ v-if="title"
52
+ class="modal-header">
53
+ {{ title }}
54
+ </DialogTitle>
55
+ <DialogDescription
56
+ class="modal-body custom-scroll"
57
+ :class="[bodyClass]">
58
+ <slot />
59
+ </DialogDescription>
60
+ </DialogPanel>
61
+ </div>
62
+ </Dialog>
63
+ </template>
64
+ <style scoped>
65
+ .modal-layout {
66
+ position: fixed;
67
+ width: 100vw;
68
+ height: 100vh;
69
+ top: 0;
70
+ left: 0;
71
+ z-index: 1001;
72
+ background: rgba(0, 0, 0, 0.44);
73
+ padding: 20px;
74
+ opacity: 0;
75
+ animation: modal-fade 0.2s forwards;
76
+ }
77
+ .modal-body {
78
+ padding: 24px 12px 18px 24px;
79
+ max-height: calc(100vh - 240px);
80
+ background: var(--theme-background-1);
81
+ border-radius: var(--theme-radius-lg);
82
+ font-family: var(--theme-font);
83
+ }
84
+ .modal {
85
+ margin: 80px auto 0;
86
+ position: relative;
87
+ background: var(--theme-background-2);
88
+ border-radius: var(--theme-radius-lg);
89
+ color: var(--theme-color-1);
90
+ width: 100%;
91
+ text-align: left;
92
+ line-height: 1.4;
93
+ opacity: 0;
94
+ transform: scale(0.98);
95
+ animation: modal-pop 0.15s 0.15s forwards;
96
+ display: flex;
97
+ flex-direction: column;
98
+ }
99
+ .modal-content-large {
100
+ max-width: 800px;
101
+ }
102
+ .modal-content-normal {
103
+ max-width: 640px;
104
+ }
105
+ .modal-content-small {
106
+ max-width: 480px;
107
+ }
108
+ @keyframes modal-fade {
109
+ from {
110
+ opacity: 0;
111
+ }
112
+ to {
113
+ opacity: 1;
114
+ }
115
+ }
116
+ @keyframes modal-pop {
117
+ 0% {
118
+ opacity: 0;
119
+ }
120
+ 100% {
121
+ opacity: 1;
122
+ transform: scale(1);
123
+ }
124
+ }
125
+ .modal-header {
126
+ padding: 12px 24px;
127
+ color: var(--theme-color-1);
128
+ font-size: var(--theme-font-size-4);
129
+ text-align: left;
130
+ font-weight: 600;
131
+ border-radius: var(--theme-radius-lg) var(--theme-radius-lg) 0 0;
132
+ }
133
+ </style>