dashboard.html 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. {% extends "base.html" %}
  2. {% block content %}
  3. <div class="columns">
  4. <div class="column is-3">
  5. <aside class="menu">
  6. <p class="menu-label">Administration</p>
  7. <ul class="menu-list">
  8. <li><a href="{{ url_for('admin.dashboard') }}" class="is-active">Dashboard</a></li>
  9. <li><a href="{{ url_for('admin.user_search') }}">User Search</a></li>
  10. <li><a>Players</a></li>
  11. <li><a>Bans</a></li>
  12. </ul>
  13. </aside>
  14. </div>
  15. <div class="column">
  16. <h1 class="title">Live Feed</h1>
  17. <div class="box" style="height: 400px; overflow-y: auto; background-color: #111;" id="event-feed">
  18. <!-- Events will be appended here via WebSocket -->
  19. </div>
  20. <div class="field is-grouped">
  21. <div class="control">
  22. <div class="select">
  23. <select id="event-filter">
  24. <option value="ALL">All Events</option>
  25. <option value="CHAT">Chat</option>
  26. <option value="JOIN">Join/Quit</option>
  27. <option value="DEATH">Death</option>
  28. </select>
  29. </div>
  30. </div>
  31. <div class="control">
  32. <button class="button is-info" onclick="clearFeed()">Clear Feed</button>
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. {% endblock %}
  38. {% block scripts %}
  39. <script>
  40. const socket = io();
  41. const feed = document.getElementById('event-feed');
  42. const filter = document.getElementById('event-filter');
  43. socket.on('connect', () => {
  44. console.log('Connected to WebSocket');
  45. });
  46. socket.on('game_event', (data) => {
  47. const div = document.createElement('div');
  48. div.className = 'notification is-small is-dark';
  49. div.style.marginBottom = '0.5rem';
  50. div.style.padding = '0.5rem';
  51. div.dataset.type = data.type; // Store type for filtering
  52. // Check if we should show this event based on current filter
  53. if (!shouldShowEvent(data.type, filter.value)) {
  54. div.style.display = 'none';
  55. }
  56. let content = '';
  57. const time = new Date(data.timestamp).toLocaleTimeString();
  58. switch (data.type) {
  59. case 'CHAT':
  60. content = `[${time}] <strong>${data.player}</strong>: ${data.content}`;
  61. break;
  62. case 'JOIN':
  63. content = `[${time}] <span class="has-text-success">+</span> <strong>${data.player}</strong> joined the game.`;
  64. break;
  65. case 'QUIT':
  66. content = `[${time}] <span class="has-text-danger">-</span> <strong>${data.player}</strong> left the game.`;
  67. break;
  68. case 'DEATH':
  69. content = `[${time}] <span class="has-text-danger">☠</span> ${data.content}`;
  70. break;
  71. default:
  72. content = `[${time}] [${data.type}] ${data.content}`;
  73. }
  74. div.innerHTML = content;
  75. feed.appendChild(div);
  76. // Only scroll if visible or if we want to force scroll (usually good to scroll if new event arrived)
  77. if (div.style.display !== 'none') {
  78. feed.scrollTop = feed.scrollHeight;
  79. }
  80. });
  81. filter.addEventListener('change', () => {
  82. const selectedFilter = filter.value;
  83. const events = feed.children;
  84. for (let event of events) {
  85. const type = event.dataset.type;
  86. if (shouldShowEvent(type, selectedFilter)) {
  87. event.style.display = '';
  88. } else {
  89. event.style.display = 'none';
  90. }
  91. }
  92. });
  93. function shouldShowEvent(eventType, filterValue) {
  94. if (filterValue === 'ALL') return true;
  95. if (filterValue === eventType) return true;
  96. if (filterValue === 'JOIN' && (eventType === 'JOIN' || eventType === 'QUIT')) return true;
  97. return false;
  98. }
  99. function clearFeed() {
  100. feed.innerHTML = '';
  101. }
  102. </script>
  103. {% endblock %}