index.svelte 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <script lang="typescript" context="module">
  2. import type { AppSession, PageData, PreloadContext } from "src/utils/session";
  3. import type { Option } from "@shared/common/async_utils";
  4. import type { MDText } from "./md";
  5. import type { VerifyInfo } from "./verify";
  6. export async function preload(
  7. this: PreloadContext,
  8. { path }: PageData,
  9. session: AppSession
  10. ) {
  11. const mdResult = await this.fetch("/rules/md", { credentials: "include" });
  12. const md = (await mdResult.json()) as Option<MDText, { error: string }>;
  13. const verifyReusult = await this.fetch("/rules/verify", { credentials: "include" });
  14. const verify = (await verifyReusult.json()) as VerifyInfo;
  15. return {
  16. rulesText: md.ok ? md.text : "",
  17. sitekey: verify.captchaSitekey,
  18. verified: verify.userVerified,
  19. };
  20. }
  21. </script>
  22. <script lang="typescript">
  23. import { Converter } from "showdown";
  24. import { onMount, tick } from "svelte";
  25. import Icon from "svelte-awesome/components/Icon.svelte";
  26. import { faSpinner } from "@fortawesome/free-solid-svg-icons";
  27. import { fade } from "svelte/transition";
  28. import type { VerifyRequest } from "./verify";
  29. export let rulesText: string = "";
  30. export let sitekey: string = "";
  31. export let verified!: boolean;
  32. let showVerify: boolean = false;
  33. const spinner = (faSpinner as unknown) as undefined;
  34. let htmlContent = new Converter().makeHtml(rulesText);
  35. enum State {
  36. None,
  37. Verify,
  38. Error,
  39. Message,
  40. }
  41. let state: State = State.None;
  42. let message: string = "";
  43. async function onVerified(e: { key: string }) {
  44. state = State.Verify;
  45. const result = await fetch("/rules/verify", {
  46. credentials: "include",
  47. method: "post",
  48. headers: {
  49. Accept: "application/json",
  50. "Content-Type": "application/json",
  51. },
  52. body: JSON.stringify({ captchaResponse: e.key } as VerifyRequest),
  53. });
  54. const opt = (await result.json()) as Option<unknown, { error: string }>;
  55. if (!opt.ok) {
  56. state = State.Error;
  57. message = opt.error;
  58. } else {
  59. state = State.Message;
  60. message = "Verification done! Welcome to the server!";
  61. }
  62. }
  63. function onExpired() {
  64. state = State.Error;
  65. message = "Captcha expired, please solve it again";
  66. }
  67. function onError(error: string) {
  68. state = State.Error;
  69. message = `${error}; Please try refreshing the page.`;
  70. }
  71. </script>
  72. <style>
  73. @import "./markdown-dark.css";
  74. .message {
  75. @apply text-white;
  76. }
  77. .error {
  78. @apply text-red-600;
  79. }
  80. </style>
  81. <svelte:head>
  82. <title>Rules</title>
  83. </svelte:head>
  84. <div class="viewport md-dark md-body">
  85. <div>
  86. {@html htmlContent}
  87. </div>
  88. {#if !verified}
  89. <div class="flex flex-col flex-wrap items-center">
  90. <form class="py-4">
  91. <input type="checkbox" id="show-verify" bind:checked={showVerify} disabled={state != State.None} />
  92. <label for="show-verify">I understand these rules and agree to abide to
  93. them</label>
  94. </form>
  95. {#if showVerify}
  96. <!-- <a href="asd" on:click|preventDefault={() => onVerified({ key: 'wew' })}>Verify test</a> -->
  97. <h-captcha site-key={sitekey} dark on:verified={onVerified} on:expired={onExpired} on:error={onError} />
  98. {/if}
  99. <div class="py-2 pointer-events-none select-none">
  100. {#if state == State.Verify}
  101. <span transition:fade={{ duration: 50 }}><Icon data={spinner} spin />
  102. Verifying</span>
  103. {:else if state == State.Error || state == State.Message}
  104. <span
  105. class:message={state == State.Message}
  106. class:error={state == State.Error}>{message}</span>
  107. {/if}
  108. </div>
  109. </div>
  110. {/if}
  111. </div>