edit.svelte 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <script lang="typescript" context="module">
  2. import type { AppSession, PageData, PreloadContext } from "src/utils/session";
  3. export async function preload(
  4. this: PreloadContext,
  5. { path }: PageData,
  6. session: AppSession
  7. ) {
  8. const result = await this.fetch("/rules/md");
  9. const md = (await result.json()) as Option<MDText, { error: string }>;
  10. if (md.ok) {
  11. return { rulesText: md.text };
  12. }
  13. return { rulesText: "" };
  14. }
  15. </script>
  16. <script lang="typescript">
  17. import { onMount } from "svelte";
  18. import "easymde/dist/easymde.min.css";
  19. import { fade } from "svelte/transition";
  20. import type { MDText } from "./md";
  21. import { Option } from "@shared/common/async_utils";
  22. export let rulesText!: string;
  23. let vpHeight: number;
  24. let textArea!: HTMLTextAreaElement;
  25. let statusMessage: string = "";
  26. let error = false;
  27. onMount(async () => {
  28. const EasyMDE = (await import("easymde")).default;
  29. let mde = new EasyMDE({
  30. element: textArea,
  31. previewClass: "md-dark md-editor-preview md-body",
  32. forceSync: true,
  33. initialValue: rulesText,
  34. });
  35. });
  36. async function save() {
  37. const result = await fetch("/rules/md", {
  38. method: "post",
  39. headers: {
  40. Accept: "application/json",
  41. "Content-Type": "application/json",
  42. },
  43. body: JSON.stringify({ text: textArea.value } as MDText),
  44. });
  45. const opt = (await result.json()) as Option<unknown, { error: string }>;
  46. let waitTime = 2000;
  47. if (opt.ok) {
  48. statusMessage = "Saved!";
  49. error = false;
  50. } else {
  51. statusMessage = opt.error;
  52. error = true;
  53. waitTime = 10000;
  54. }
  55. setTimeout(() => {
  56. statusMessage = "";
  57. error = false;
  58. }, waitTime);
  59. }
  60. </script>
  61. <style>
  62. @import "./markdown-dark.css";
  63. @import "./easymde-style.css";
  64. .viewport {
  65. @apply bg-gray-800 rounded-sm px-20 py-5 shadow-lg w-screen pt-10;
  66. height: 100vh;
  67. }
  68. span.status {
  69. @apply text-white px-4;
  70. &.error {
  71. @apply text-red-600;
  72. }
  73. }
  74. .save-button {
  75. @apply text-base bg-green-600 p-2 px-3 text-white rounded-sm;
  76. &:hover {
  77. @apply bg-green-800 text-gray-100 cursor-pointer;
  78. }
  79. }
  80. :global .CodeMirror-scroll {
  81. max-height: calc(90vh - 250px) !important;
  82. min-height: calc(90vh - 250px) !important;
  83. }
  84. @screen lg {
  85. .viewport {
  86. @apply w-3/4;
  87. height: 80vh;
  88. }
  89. :global .CodeMirror-scroll {
  90. max-height: calc(70vh - 250px) !important;
  91. min-height: calc(70vh - 250px) !important;
  92. }
  93. }
  94. #easy-mde {
  95. visibility: hidden;
  96. }
  97. </style>
  98. <svelte:head>
  99. <title>Edit rules</title>
  100. </svelte:head>
  101. <div class="viewport" bind:clientHeight={vpHeight}>
  102. <h1 class="text-white text-4xl font-light py-2">Edit rules</h1>
  103. <form on:submit|preventDefault={save}>
  104. <p class="text-white md-editor">
  105. <textarea id="easy-mde" bind:this={textArea} />
  106. </p>
  107. <span class="float-right">
  108. {#if statusMessage}
  109. <span
  110. transition:fade={{ duration: 100 }}
  111. class="status {error ? 'error' : ''}">{statusMessage}</span>
  112. {/if}
  113. <input type="submit" class="save-button" value="Save" />
  114. </span>
  115. </form>
  116. </div>