project-open-window.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <template>
  2. <div class="project-open-window">
  3. <project-creation-window v-if="create"
  4. :status="status"
  5. :socket="socket"
  6. @cancel="create = false"></project-creation-window>
  7. <template v-else>
  8. <div class="title">
  9. <h1>Open Project</h1>
  10. Click a project to open it or create a new one.
  11. </div>
  12. <div class="projects">
  13. <div class="project"
  14. v-for="project in sortedProjects"
  15. :key="project.id"
  16. @click="load(project.index)">
  17. <h2>{{ project.name }}</h2>
  18. <div class="description">{{ project.description }}</div>
  19. <div v-if="project.access === 0">
  20. created on {{ datetime(project.created) }}
  21. </div>
  22. <div v-else>
  23. {{ datetime(project.access) }}
  24. </div>
  25. </div>
  26. </div>
  27. <div class="footer">
  28. <button-input @click="create = true" type="primary">
  29. New Project
  30. </button-input>
  31. </div>
  32. </template>
  33. </div>
  34. </template>
  35. <script>
  36. import ButtonInput from "@/components/base/button-input";
  37. import ProjectCreationWindow from "@/components/projects/project-creation-window";
  38. export default {
  39. name: "project-open-window",
  40. components: {ProjectCreationWindow, ButtonInput},
  41. props: ['projects', 'status', 'socket'],
  42. data: function() {
  43. return {
  44. create: false
  45. }
  46. },
  47. computed: {
  48. sortedProjects: function() {
  49. return [...this.projects].map((e, i) => {
  50. e.index = i;
  51. return e;
  52. }).sort((a, b) => {
  53. const x = a.access === 0 ? a.created : a.access;
  54. const y = b.access === 0 ? b.created : b.access;
  55. if (x < y)
  56. return 1;
  57. else
  58. return -1;
  59. });
  60. }
  61. },
  62. methods: {
  63. load: function(index) {
  64. this.socket.set('projects/' + index + '/status', 'load');
  65. },
  66. datetime: function(timestamp) {
  67. const date = new Date(timestamp * 1000);
  68. const da = date.getDate();
  69. const mo = date.getMonth() + 1;
  70. const ye = date.getFullYear();
  71. const ho = date.getHours();
  72. const mi = date.getMinutes();
  73. return [
  74. [
  75. da < 10 ? '0' + da : da,
  76. mo < 10 ? '0' + mo : mo,
  77. ye
  78. ].join('.'),
  79. [
  80. ho < 10 ? '0' + ho : ho,
  81. mi < 10 ? '0' + mi : mi
  82. ].join(':')
  83. ].join(' ');
  84. }
  85. }
  86. }
  87. </script>
  88. <style scoped>
  89. .project-open-window {
  90. display: flex;
  91. flex-direction: column;
  92. }
  93. h1 {
  94. margin: 0 0 0.4rem 0;
  95. }
  96. h2 {
  97. margin: 0;
  98. font-size: 120%;
  99. font-family: "Roboto Condensed";
  100. }
  101. .title {
  102. margin: 0;
  103. padding: 2rem;
  104. border-bottom: 1px solid rgba(0, 0, 0, 0.2);
  105. flex-grow: 0;
  106. }
  107. .projects {
  108. overflow: auto;
  109. flex-grow: 1;
  110. }
  111. .project:not(:last-child) {
  112. border-bottom: 1px solid rgba(0, 0, 0, 0.2);
  113. }
  114. .project {
  115. padding: 1rem 2rem;
  116. cursor: pointer;
  117. }
  118. .description {
  119. text-overflow: ellipsis;
  120. white-space: nowrap;
  121. overflow: hidden;
  122. }
  123. .footer {
  124. padding: 2rem;
  125. display: flex;
  126. justify-content: flex-end;
  127. }
  128. </style>