You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
3.9 KiB

3 years ago
  1. <script lang="ts">
  2. import { createEventDispatcher, onMount } from 'svelte';
  3. import Icon from './Icon.svelte';
  4. export let title: string = "";
  5. export let wide: boolean = false;
  6. export let error: string | null = null;
  7. export let closable: boolean = false;
  8. export let show: boolean = false;
  9. onMount(() => {
  10. const listener = (ev: KeyboardEvent) => {
  11. if ((ev.ctrlKey || ev.altKey) && (ev.key === "Escape" || ev.key.toLowerCase() === "q")) {
  12. dispatch("close");
  13. }
  14. }
  15. document.addEventListener("keyup", listener);
  16. return () => {
  17. document.removeEventListener("keyup", listener);
  18. }
  19. })
  20. const dispatch = createEventDispatcher();
  21. </script>
  22. {#if show}
  23. <div class="modal-background">
  24. <div class="modal" class:wide>
  25. <div class="header">
  26. <div class="title" class:noclose={!closable}>{title}</div>
  27. {#if (closable)}
  28. <div class="x">
  29. <div class="button" on:click={() => dispatch("close")}>
  30. <Icon name="times" />
  31. </div>
  32. </div>
  33. {/if}
  34. </div>
  35. <hr />
  36. {#if (error != null)}
  37. <div class="error">{error}</div>
  38. {/if}
  39. <div class="body">
  40. <slot></slot>
  41. </div>
  42. </div>
  43. </div>
  44. {/if}
  45. <style>
  46. div.modal-background {
  47. position: fixed;
  48. top: 0;
  49. left: 0;
  50. width: 100%;
  51. height: 100%;
  52. background: rgba(0,0,0,0.3);
  53. }
  54. div.modal {
  55. position: absolute;
  56. left: 50%;
  57. top: 50%;
  58. width: calc(100vw - 4em);
  59. max-width: 40ch;
  60. max-height: calc(100vh - 4em);
  61. overflow: auto;
  62. transform: translate(-50%,-50%);
  63. padding: 1em;
  64. border-radius: 0.2em;
  65. background: #333;
  66. }
  67. div.modal.wide {
  68. max-width: 60ch;
  69. }
  70. div.modal :global(hr) {
  71. border: 0.5px solid gray;
  72. margin: 0;
  73. }
  74. div.error {
  75. margin: 0.5em;
  76. padding: 0.5em;
  77. border: 1px solid rgb(204, 65, 65);
  78. border-radius: 0.2em;
  79. background-color: rgb(133, 39, 39);
  80. color: rgb(211, 141, 141);
  81. animation: fadein 0.5s;
  82. }
  83. div.body {
  84. margin: 1em 0.25ch;
  85. }
  86. div.title {
  87. color: #CCC;
  88. line-height: 1em;
  89. }
  90. div.title.noclose {
  91. margin-bottom: 1.2em;
  92. }
  93. div.x {
  94. position: relative;
  95. line-height: 1em;
  96. top: -1em;
  97. text-align: right;
  98. }
  99. div.x div.button {
  100. color: #CCC;
  101. display: inline-block;
  102. padding: 0em 0.5ch 0.1em 0.5ch;
  103. line-height: 1em;
  104. user-select: none;
  105. cursor: pointer;
  106. }
  107. div.x div.button:hover {
  108. color: #FFF;
  109. }
  110. div.modal :global(button) {
  111. display: inline-block;
  112. padding: 0.25em 0.75ch 0.26em 0.75ch;
  113. margin: 0.75em 0.25ch 0.25em 0.25ch;
  114. background: none;
  115. border: none;
  116. border-radius: 0.2em;
  117. color: #CCC;
  118. cursor: pointer;
  119. }
  120. div.modal :global(button:hover), div.modal :global(button:focus) {
  121. background: #222;
  122. color: #FFF;
  123. }
  124. div.modal :global(label) {
  125. padding: 0 0 0.125em 0.25ch;
  126. font-size: 0.75em;
  127. user-select: none;
  128. -webkit-user-select: none;
  129. -moz-user-select: none;
  130. }
  131. div.modal :global(input), div.modal :global(select), div.modal :global(textarea) {
  132. width: 100%;
  133. margin-bottom: 0.5em;
  134. background: #222;
  135. color: #777;
  136. border: none;
  137. outline: none;
  138. resize: none;
  139. }
  140. div.modal :global(select) {
  141. padding-left: 0.5ch;
  142. }
  143. div.modal :global(input:disabled) {
  144. background: #444;
  145. color: #aaa;
  146. }
  147. div.modal :global(textarea) {
  148. height: 6em;
  149. }
  150. div.modal :global(textarea:disabled) {
  151. background: #444;
  152. color: #aaa;
  153. }
  154. div.modal :global(input:last-of-type) {
  155. margin-bottom: 1em;
  156. }
  157. div.modal :global(input.nolast) {
  158. margin-bottom: 0.5em;
  159. }
  160. div.modal :global(input[type="checkbox"]) {
  161. width: initial;
  162. display: inline-block;
  163. }
  164. div.modal :global(input[type="checkbox"] + label) {
  165. width: initial;
  166. display: inline-block;
  167. padding: 0;
  168. margin: 0;
  169. }
  170. div.modal :global(input:focus), div.modal :global(select:focus), div.modal :global(textarea:focus) {
  171. background: #111;
  172. color: #CCC;
  173. border: none;
  174. outline: none;
  175. }
  176. div.modal :global(p) {
  177. margin: 0.25em 1ch 1em 1ch;
  178. font-size: 0.9em;
  179. }
  180. @keyframes fadein {
  181. from { opacity: 0; }
  182. to { opacity: 1; }
  183. }
  184. </style>