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.

146 lines
3.2 KiB

  1. <script lang="ts" context="module">
  2. import type { IconName } from "../external/icons";
  3. interface ToCGroup {
  4. icon: IconName
  5. href: string
  6. name: string
  7. completed: boolean
  8. items: ToCItem[]
  9. }
  10. interface ToCItem {
  11. href: string
  12. name: string
  13. completed: boolean
  14. }
  15. </script>
  16. <script lang="ts">
  17. import type { GroupResult } from "../models/group";
  18. import type { ProjectResult } from "../models/project";
  19. import Icon from "./Icon.svelte";
  20. export let projects: ProjectResult[] = [];
  21. export let groups: GroupResult[] = [];
  22. export let hideInactive: boolean = false;
  23. let tocGroups: ToCGroup[];
  24. let show = false;
  25. function toggleShow() {
  26. show = !show;
  27. }
  28. $: {
  29. tocGroups = [];
  30. for (const project of projects) {
  31. tocGroups.push({
  32. icon: project.icon,
  33. name: project.name,
  34. href: `/projects#${project.id}`,
  35. completed: !project.active,
  36. items: project.tasks.filter(t => !hideInactive || t.active).map(task => ({
  37. name: task.name,
  38. completed: !task.active,
  39. href: `/projects#${task.id}`,
  40. })),
  41. })
  42. }
  43. for (const group of groups) {
  44. tocGroups.push({
  45. icon: group.icon,
  46. name: group.name,
  47. href: `/items#${group.id}`,
  48. completed: false,
  49. items: group.items.map(item => ({
  50. name: item.name,
  51. completed: false,
  52. href: `/items#${item.id}`,
  53. })),
  54. })
  55. }
  56. }
  57. </script>
  58. <div class="toc" class:show={show}>
  59. <div class="show-button" on:click={toggleShow}>
  60. <div class="icon"><Icon name={show ? "chevron_down" : "chevron_right"} /></div>
  61. <div class="text">{show ? "Hide" : "Show"} Table of Contents</div>
  62. </div>
  63. {#if show}
  64. {#each tocGroups as tocGroup (tocGroup.href)}
  65. <div class="toc-group" class:completed={tocGroup.completed}>
  66. <a href={tocGroup.href}>
  67. <div class="icon">
  68. <Icon name={tocGroup.icon} />
  69. </div>
  70. <div class="text">{tocGroup.name}</div>
  71. </a>
  72. </div>
  73. {#each tocGroup.items as tocItem (tocItem.href)}
  74. <div class="toc-item" class:completed={tocItem.completed}>
  75. <a href={tocItem.href}>
  76. <div class="text">{tocItem.name}</div>
  77. </a>
  78. </div>
  79. {/each}
  80. {/each}
  81. {/if}
  82. </div>
  83. <style>
  84. div.toc {
  85. padding: 1em;
  86. color: #777;
  87. margin: 0 auto;
  88. }
  89. div.toc.show {
  90. padding-bottom: 2em;
  91. }
  92. div.toc-item {
  93. margin-left: 1.5ch;
  94. padding-left: 1ch;
  95. border-left: 2px solid #222;
  96. }
  97. div.toc-item + div.toc-group, div.toc-group + div.toc-group {
  98. padding-top: 1em;
  99. }
  100. a {
  101. color: inherit;
  102. display: flex;
  103. flex-direction: row;
  104. padding: 0.125em 0.5ch;
  105. }
  106. a > div.icon {
  107. padding: 0.125em 0.5ch;
  108. }
  109. a > div.text {
  110. vertical-align: middle;
  111. }
  112. div.show-button {
  113. display: flex;
  114. flex-direction: row;
  115. -webkit-user-select: none;
  116. -moz-user-select: none;
  117. padding-bottom: 1em;
  118. }
  119. div.show-button div.icon {
  120. margin-left: auto;
  121. padding: 0 1ch;
  122. padding-top: 0.25em;
  123. }
  124. div.show-button div.text {
  125. margin-right: auto;
  126. margin-top: auto;
  127. margin-bottom: auto;
  128. }
  129. div.completed {
  130. color: #484;
  131. }
  132. </style>