dev-mailbox.html 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Vendure Development Inbox</title>
  6. <style>
  7. body {
  8. display: flex;
  9. flex-direction: column;
  10. height: 100vh;
  11. margin: 0;
  12. font-family: Helvetica, Arial, sans-serif;
  13. }
  14. .top-bar {
  15. padding: 12px;
  16. display: flex;
  17. align-items: center;
  18. background-color: #2a2929;
  19. color: #efefef;
  20. height: 60px;
  21. }
  22. .heading {
  23. margin: 0;
  24. font-size: 22px;
  25. }
  26. button#refresh {
  27. margin-left: 12px;
  28. border-radius: 3px;
  29. display: flex;
  30. align-items: center;
  31. }
  32. button#refresh .label {
  33. margin-left: 6px;
  34. }
  35. .generate-controls {
  36. flex: 1;
  37. display: flex;
  38. justify-content: flex-end;
  39. }
  40. input, select, button {
  41. padding: 6px;
  42. border-radius: 3px;
  43. border: 1px solid #0b384b;
  44. margin-left: 3px;
  45. }
  46. button {
  47. text-transform: uppercase;
  48. font-size: 12px;
  49. transition: background-color 0.2s;
  50. padding: 0 12px;
  51. height: 32px;
  52. }
  53. button:hover {
  54. background-color: #efefef;
  55. }
  56. #language-code {
  57. width: 32px;
  58. }
  59. .content {
  60. display: flex;
  61. flex: 1;
  62. height: calc(100% - 60px);
  63. }
  64. .list {
  65. width: 40vw;
  66. min-width: 300px;
  67. overflow: auto;
  68. }
  69. .row {
  70. border-bottom: 1px dashed #ddd;
  71. padding: 12px 6px;
  72. cursor: pointer;
  73. transition: background-color 0.2s;
  74. }
  75. .row.selected {
  76. background-color: #d4e1e7;
  77. }
  78. .row:not(.selected):hover {
  79. background-color: #efefef;
  80. }
  81. .meta {
  82. display: flex;
  83. justify-content: space-between;
  84. color: #666;
  85. }
  86. .detail {
  87. flex: 1;
  88. border: 1px solid #999;
  89. display: flex;
  90. flex-direction: column;
  91. }
  92. .detail iframe {
  93. height: 100%;
  94. border: 1px solid #eee;
  95. overflow: auto;
  96. }
  97. .metadata {
  98. padding: 6px;
  99. color: #333;
  100. background-color: white;
  101. z-index: 1;
  102. box-shadow: 0px 5px 8px -7px rgba(0, 0, 0, 0.49);
  103. }
  104. </style>
  105. </head>
  106. <body>
  107. <div class="top-bar">
  108. <h1 class="heading">Vendure Dev Mailbox</h1>
  109. <div class="generate-controls">
  110. <select id="type-selector"></select>
  111. <input id="language-code" value="en" type="text">
  112. <button id="generate-test">Generate test</button>
  113. </div>
  114. </div>
  115. <div class="content">
  116. <div class="list">
  117. </div>
  118. <div class="detail">
  119. </div>
  120. </div>
  121. <script>
  122. let selectedId = '';
  123. refreshInbox();
  124. setInterval(refreshInbox, 5000);
  125. const typeSelect = document.querySelector('#type-selector');
  126. fetch('./types')
  127. .then(res => res.json())
  128. .then(res => {
  129. res.forEach(type => {
  130. const option = document.createElement('option');
  131. option.value = type;
  132. option.text = type;
  133. typeSelect.appendChild(option);
  134. });
  135. });
  136. const languageCodeInput = document.querySelector('#language-code');
  137. const generateTestButton = document.querySelector('#generate-test');
  138. generateTestButton.addEventListener('click', e => {
  139. fetch(`./generate/${typeSelect.value}/${languageCodeInput.value}`)
  140. .then(() => new Promise(resolve => setTimeout(resolve, 500)))
  141. .then(() => refreshInbox());
  142. });
  143. const list = document.querySelector('.list');
  144. function refreshInbox() {
  145. fetch('./list')
  146. .then(res => res.json())
  147. .then(res => renderList(res));
  148. }
  149. function renderList(items) {
  150. const list = document.querySelector('.list');
  151. list.innerHTML = '';
  152. const rows = items.forEach(item => {
  153. const row = document.createElement('div');
  154. row.classList.add('row');
  155. row.dataset.id = item.fileName;
  156. row.innerHTML = `
  157. <div class="meta">
  158. <div class="date">${item.date}</div>
  159. <div class="recipient">${item.recipient}</div>
  160. </div>
  161. <div class="subject">${item.subject}</div>`;
  162. row.addEventListener('click', (e) => {
  163. selectedId = item.fileName;
  164. fetch('./item/' + item.fileName)
  165. .then(res => res.json())
  166. .then(res => renderEmail(res))
  167. .then(() => highlightSelectedRow());
  168. });
  169. list.appendChild(row);
  170. });
  171. highlightSelectedRow();
  172. }
  173. function highlightSelectedRow() {
  174. document.querySelectorAll('.list .row').forEach(row => {
  175. row.classList.remove('selected');
  176. if (row.dataset.id === selectedId) {
  177. row.classList.add('selected');
  178. }
  179. });
  180. }
  181. function renderEmail(email) {
  182. const content = `
  183. <div class="metadata">
  184. <table>
  185. <tr>
  186. <td>Recipient:</td>
  187. <td>${email.recipient}</td>
  188. </tr>
  189. <tr>
  190. <td>Subject:</td>
  191. <td>${email.subject}</td>
  192. </tr>
  193. <tr>
  194. <td>Date:</td>
  195. <td>${new Date().toLocaleString()}</td>
  196. </tr>
  197. </table>
  198. </div>
  199. <iframe srcdoc="${email.body.replace(/"/g, '&quot;')}"></iframe>
  200. `;
  201. document.querySelector('.detail').innerHTML = content;
  202. }
  203. </script>
  204. </body>
  205. </html>