main.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. 'use strict'
  2. import 'picocrank/styles.css'
  3. import 'femtocrank/dark.css'
  4. import './style.css'
  5. import 'iconify-icon'
  6. import { createClient } from '@connectrpc/connect'
  7. import { createConnectTransport } from '@connectrpc/connect-web'
  8. import { OliveTinApiService } from './resources/scripts/gen/olivetin/api/v1/olivetin_pb'
  9. import { createApp, h } from 'vue'
  10. import { createI18n } from 'vue-i18n'
  11. import router from './resources/vue/router.js'
  12. import App from './resources/vue/App.vue'
  13. import { initWebsocket } from './js/websocket.js'
  14. import { applyThemeStyles, getStoredThemePreference } from './resources/vue/utils/themeLoader.js'
  15. import combinedTranslations from '../lang/combined_output.json'
  16. function getSelectedLanguage () {
  17. const storedLanguage = localStorage.getItem('olivetin-language')
  18. if (storedLanguage && storedLanguage !== 'auto') {
  19. return storedLanguage
  20. }
  21. if (storedLanguage === 'auto') {
  22. localStorage.removeItem('olivetin-language')
  23. }
  24. if (navigator.languages && navigator.languages.length > 0) {
  25. const available = Object.keys(combinedTranslations.messages || {})
  26. for (const candidate of navigator.languages) {
  27. const lowerCandidate = candidate.toLowerCase()
  28. const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
  29. if (exact) {
  30. return exact
  31. }
  32. const prefix = available.find(locale => locale.toLowerCase().startsWith(lowerCandidate.split('-')[0] + '-'))
  33. if (prefix) {
  34. return prefix
  35. }
  36. }
  37. }
  38. return 'en'
  39. }
  40. async function initClient () {
  41. const transport = createConnectTransport({
  42. baseUrl: window.location.protocol + '//' + window.location.host + '/api/'
  43. })
  44. window.client = createClient(OliveTinApiService, transport)
  45. window.initResponse = await window.client.init({})
  46. if (window.initResponse.enableCustomJs) {
  47. const script = document.createElement('script')
  48. script.src = '/custom-webui/custom.js'
  49. script.async = true
  50. script.id = 'olivetin-custom-js'
  51. document.head.appendChild(script)
  52. }
  53. const i18nSettings = createI18n({
  54. legacy: false,
  55. locale: getSelectedLanguage(),
  56. fallbackLocale: 'en',
  57. messages: combinedTranslations.messages,
  58. postTranslation: (translated) => {
  59. const params = new URLSearchParams(window.location.search)
  60. if (params.has('debug-translations')) {
  61. return '____'
  62. } else {
  63. return translated
  64. }
  65. }
  66. })
  67. return i18nSettings
  68. }
  69. function setupVue (i18nSettings) {
  70. const app = createApp(App)
  71. app.use(router)
  72. app.use(i18nSettings)
  73. window.i18n = i18nSettings.global
  74. app.mount('#app')
  75. }
  76. function setupErrorDisplay (errorMessage) {
  77. const ErrorApp = {
  78. render () {
  79. return h('section', { class: 'bad', style: 'padding: 2em; text-align: center; margin: 2em auto;' }, [
  80. h('h2', 'OliveTin Init Failed'),
  81. h('p', errorMessage),
  82. h('p', 'Please check your browser console for more details.')
  83. ])
  84. }
  85. }
  86. const app = createApp(ErrorApp)
  87. app.mount('#app')
  88. }
  89. async function main () {
  90. try {
  91. const i18nSettings = await initClient()
  92. try {
  93. await applyThemeStyles(getStoredThemePreference())
  94. } catch (err) {
  95. console.warn('Failed to load theme CSS:', err)
  96. }
  97. initWebsocket()
  98. setupVue(i18nSettings)
  99. } catch (err) {
  100. const errorMessage = err.message || 'Failed to initialize. Please check your configuration and try again.'
  101. console.error('Init failed:', err)
  102. setupErrorDisplay(errorMessage)
  103. }
  104. }
  105. main()