index.svelte 3.6 KB

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