Skip to content
Snippets Groups Projects
App.vue 12.9 KiB
Newer Older
  <v-app id="app">
Ole Voldsæter's avatar
Ole Voldsæter committed
    <header>
      <h1><a href="/">Ordbøkene <span class="beta">(BETA)</span></a></h1>
Ole Voldsæter's avatar
Ole Voldsæter committed
      <p class="about-link"><a href="#">OM ORDBØKENE</a></p>
      <p class="sub-title"><a href="/">Bokmålsordboka | Nynorskordboka – rett norsk</a></p>
Ole Voldsæter's avatar
Ole Voldsæter committed
    </header>
    <main :class="(article.error || article.lemmas.length || search_results.length || waiting) ? '' : 'welcome  '">
      <div class="search_container">
        <div class="lang_select_container">
          <v-radio-group row v-model="lang">
            <template v-slot:label>
              <span>VIS TREFF PÅ</span>
            </template>
            <v-radio value="bob,nob" color="rgb(188, 71, 123)">
              <template v-slot:label>
                <span>Begge ordbøker</span>
              </template>
            </v-radio>
            <v-radio value="bob" color="rgb(188, 71, 123)">
              <template v-slot:label>
                <span>Bokmål</span>
              </template>
            </v-radio>
            <v-radio value="nob" label="Nynorsk" color="rgb(188, 71, 123)">
              <template v-slot:label>
                <span>Nynorsk</span>
              </template>
            </v-radio>
          </v-radio-group>
        <Autocomplete @submit="select_result" :endpoint="api_pref">
        </Autocomplete>
      </div>
      <div id="spinner">
        <v-progress-circular indeterminate color="rgb(188, 71, 123)" size="120" v-show="waiting"></v-progress-circular>
      </div>
      <SearchResults :hits="search_results" :lang="lang" @article-click="article_link_click" v-show="! waiting" />
      <div id="single_article_container">
        <Article :key="article_key" :article="article" @article-click="article_link_click" />
      </div>
      <div class="welcome" v-show="! (article.error || article.lemmas.length || search_results.length || waiting)">
        <div class="monthly">
            <Article :article="monthly_bm" @article-click="article_link_click" />
          </div>
            <Article :article="monthly_nn" @article-click="article_link_click" />
          </div>
        </div>
Ole Voldsæter's avatar
Ole Voldsæter committed
    <footer>
      <div>
        <img id="srlogo" src="./assets/Sprakradet_logo_neg.png" alt="">
Ole Voldsæter's avatar
Ole Voldsæter committed
      </div>
      <div>
        <img id="uiblogo" src="./assets/uib-logo.svg" alt="">
Ole Voldsæter's avatar
Ole Voldsæter committed
      </div>
      <div>Bokmålsordboka og Nynorskordboka viser skrivemåte og bøying i tråd med norsk rettskriving. Språkrådet og Universitetet i Bergen står bak ordbøkene.</div>
Ole Voldsæter's avatar
Ole Voldsæter committed
    </footer>
Ole Voldsæter's avatar
Ole Voldsæter committed
</template>

<script>
Ole Voldsæter's avatar
Ole Voldsæter committed
import axios from "axios"
import entities from './utils/entities.js'
Ole Voldsæter's avatar
Ole Voldsæter committed
import Article from './components/Article.vue'
Ole Voldsæter's avatar
Ole Voldsæter committed
import SearchResults from './components/SearchResults.vue'
import Autocomplete from './components/Autocomplete.vue'
var api_endpoint = 'https://beta.ordbok.uib.no/api/dict'
Ole Voldsæter's avatar
Ole Voldsæter committed

axios.interceptors.request.use(function (config) {
    config.headers["x-api-key"] = "ZkYiyRVXxH86ijsvhx3cH4SY5Iik2ijI3BKVJGMm"
    return config;
  }, function (error) {
    return Promise.reject(error);
  });

function navigate_to_article(self, source) {
  axios.get(api_endpoint + '/' + self.$route.params.lang + '/article/' + self.$route.params.id)
    self.article = Object.assign(response.data, {'dictionary': self.$route.params.lang})
    self.search_results = []
  })
  .catch(function(error){
    if (error.response && error.response.status == 404) {
      self.article = {
        lemmas: [],
        error: "Vi har ingen artikkel med id " + self.$route.params.id
      }
    } else {
      self.article = {
        lemmas: [],
        error: "Noe gikk galt..."
      }
      console.log(error)
    }
  })
  .then(function(response){
    history.replaceState({article: self.article, search_results: [], lang: self.lang}, '')
    if (source) {
      self.$plausible.trackEvent('internal link incoming', {props: {origin: source}})
    }
  })
}

function navigate_to_search(self, query) {
  axios.get(self.api_pref + 'search?q=' + query)
  .then(function(response){
    self.search_results = response.data
Ole Voldsæter's avatar
Ole Voldsæter committed
    if (! self.search_results.length) {
      self.article = {
        lemmas: [],
        error: "Vi fant ingen resultater for '" + decodeURIComponent(query) + "'. (Søkeforlag kommer i en senere oppatering av Ordbøkene)"
Ole Voldsæter's avatar
Ole Voldsæter committed
      }
    }
  })
  .catch(function(error){
    if (error.response && error.response.status == 400) {
      self.article = {
        lemmas: [],
        error: "Søkeuttrykket inneholder feil"
      }
    } else if (error.response) {
      self.article = {
        lemmas: [],
        error: "Noe gikk galt på serversiden"
      }
    } else {
      self.article = {
        lemmas: [],
        error: "Nettverksproblemer, prøv igjen"
      }
    }
  })
  .then(function(_){
    history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
  })
}

function navigate_to_word(self, word) {
  axios.get(self.api_pref + 'suggest?q=' + word)
  .then(function(response){
    self.search_results = response.data.filter(result => result.match.length == word.length)
    if (! self.search_results.length) {
      self.article = {
        lemmas: [],
        error: "Ordet '" + decodeURIComponent(word) + "' finnes ikke i ordbøkene"
      }
    }
  })
  .catch(function(error){
    if (error.response) {
      self.article = {
        lemmas: [],
        error: "Noe gikk galt på serversiden"
      }
    } else {
      self.article = {
        lemmas: [],
        error: "Nettverksproblemer, prøv igjen"
      }
    }
  })
  .then(function(_){
    self.waiting_for_articles = false
    history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
  })
}

Ole Voldsæter's avatar
Ole Voldsæter committed
export default {
  name: 'app',
  data: function() {
    return {
Ole Voldsæter's avatar
Ole Voldsæter committed
      search_results: [],
Ole Voldsæter's avatar
Ole Voldsæter committed
      lang: 'bob,nob',
      waiting_for_metadata: true,
      article: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
      monthly_bm: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
      monthly_nn: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
Ole Voldsæter's avatar
Ole Voldsæter committed
  computed: {
Ole Voldsæter's avatar
Ole Voldsæter committed
      return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
    api_pref: function() {
      return api_endpoint + '/' + this.lang + '/article/'
Ole Voldsæter's avatar
Ole Voldsæter committed
  components: {
  },
  methods: {
    select_result: function(event) {
      if(event.articles){
        this.$router.push('/' + this.lang + '/w/' + event.word)
        this.search_results = event.articles
        this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
        history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang}, '')
        this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: event.match}})
Ole Voldsæter's avatar
Ole Voldsæter committed
      }else{
        this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
Ole Voldsæter's avatar
Ole Voldsæter committed
        this.$router.push(`/${this.lang}/search/${event.q}`)
        this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: '<fritekstsøk>'}})
Ole Voldsæter's avatar
Ole Voldsæter committed
      }
Ole Voldsæter's avatar
Ole Voldsæter committed
    },
    article_link_click: function(item) {
      if (this.article.article_id == item.article_id){
        this.article_key++
        history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang}, '')
        this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
        navigate_to_article(this, item.source)
    }
  },
  mounted: function(){
    this.lang = 'bob,nob'

    Promise.all([
      axios.get(api_endpoint + '/bob').then(function(response){
        let concepts = response.data.concepts
        entities.bob = concepts
      }),
      axios.get(api_endpoint + '/nob').then(function(response){
        let concepts = response.data.concepts
        entities.nob = concepts
      })
    ]).then(function(_) {
      self.waiting_for_metadata = false
      if(self.$route.name == 'word') {
Ole Voldsæter's avatar
Ole Voldsæter committed
        self.lang = self.$route.params.lang
        navigate_to_word(self, self.$route.params.word)
      }
      else if(self.$route.name == 'lookup'){
        navigate_to_article(self, self.$route.params.id)
      }
      else if (self.$route.name == 'search') {
Ole Voldsæter's avatar
Ole Voldsæter committed
        self.lang = self.$route.params.lang
        navigate_to_search(self, self.$route.params.query)
Ole Voldsæter's avatar
Ole Voldsæter committed
        self.lang = self.$route.params.lang || 'bob,nob'
        self.waiting_for_articles = false
        history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
      }

      // words of the month
      axios.get(api_endpoint + '/bob/article/5607').then(function(response){
        self.monthly_bm = Object.assign(response.data, {dictionary: 'bob'})
      })

      axios.get(api_endpoint + '/nob/article/78569').then(function(response){
        self.monthly_nn = Object.assign(response.data, {dictionary: 'nob'})
      })
    }).catch(function(_){
      self.article = {
        lemmas: [],
        error: "Et nettverksproblem hindret lasting av siden. Prøv å laste siden på nytt"
      }
      self.waiting_for_metadata = false
      self.waiting_for_articles = false
  },
  watch: {
    $route() {
      this.$plausible.trackEvent('language', {props: {code: this.$route.params.lang}})
    }
Ole Voldsæter's avatar
Ole Voldsæter committed
  },
  created: function() {
    let self = this
    window.onpopstate = function (event) {
      if (event.state) {
        self.article = event.state.article
        self.search_results = event.state.search_results
        self.lang = event.state.lang
      }
    }

Ole Voldsæter's avatar
Ole Voldsæter committed
  }
}
</script>

<style>
Ole Voldsæter's avatar
Ole Voldsæter committed
  @import url('https://fonts.googleapis.com/css2?family=Inria+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
  @import url('https://fonts.googleapis.com/css2?family=Inria+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap');

Ole Voldsæter's avatar
Ole Voldsæter committed
#app {
Ole Voldsæter's avatar
Ole Voldsæter committed
  font-family: 'Noto Sans', Helvetica, Arial, sans-serif;
Ole Voldsæter's avatar
Ole Voldsæter committed
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
Ole Voldsæter's avatar
Ole Voldsæter committed
  display: flex;
  flex-direction: column;
  height: 100%;
}

html, body {
    height: 100%
Ole Voldsæter's avatar
Ole Voldsæter committed
}

body {
  margin: 0px;
h1 {
  font-family: Inria Serif;
  font-size: 36px;
  color: #560027;
}


header > h1 {
  color: #BC477B;
  font-size: 40px;
  margin: 0px;
}

p.about-link {
  text-align: right;
  margin: 0px;
  float: right;
Ole Voldsæter's avatar
Ole Voldsæter committed
header a {
  color: inherit;
  text-decoration: none;
}

span.beta {
  color: #BBBBBB;
}

p.about-link > a{
  text-decoration: none;
  border-bottom: solid #BC477B 4px;
  font-size: 12px;
  color: #FDF4F5;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
main {
  padding-bottom: 20px;
  flex: 1 0 auto;
  background-color: #FDF4F5;
}

main.welcome {
  background-image: url('./assets/books.jpg');
  background-repeat: no-repeat;
  background-attachment: fixed;
}

header, #search_results, #spinner, #single_article_container, footer, div.welcome, div.search_container {
Ole Voldsæter's avatar
Ole Voldsæter committed
  padding-left: calc((100vw - 1000px) / 2);
  padding-right: calc((100vw - 1000px) / 2);
#spinner {
  padding-top: 40px;
  background-color: #560027;
div.monthly {
  padding: 20px;
  border-radius: 10px;
  display: flex;
div.monthly > div {
  flex: 50%;
div.monthly article.bob .dict-label::before {
  content: "månedens ";
div.monthly article.nob .dict-label::before {
  content: "månadens ";
Ole Voldsæter's avatar
Ole Voldsæter committed
.top {
  color: #560027;
  font-weight: bold;
  font-size: smaller;
  border-bottom: solid;
  border-color: #BC477B;
}

.mission-statement {
  font-size: 16px;
  margin: 0px;
  color: #FDF4F5;
Ole Voldsæter's avatar
Ole Voldsæter committed
}
.sub-title {
  font-size: 20px;
  margin: 0px;
  color: #FDF4F5;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
footer {
  font-size: smaller;
  display: table;
Ole Voldsæter's avatar
Ole Voldsæter committed
  flex-direction: row;
  background-color: #570B27;
  color: #ffffff;
}

.search_container {
  padding-top: 50px;
.v-label span {
  color: rgba(86, 0, 39, 1)
}

li.suggestion {
  font-weight: bold;
  padding-left: 20px;
  padding-top: 5px;
  padding-bottom: 5px;
  border: 0px;
  background-image: none;
footer > div {
  display: table-cell;
  vertical-align: middle;
  padding: 10px;
Ole Voldsæter's avatar
Ole Voldsæter committed
}

#srlogo {
  height: 20px;
}

#uiblogo {
  height: 60px;
}

select.lang_select {
  appearance: none;
  background-color: #EEEEEE;
  border: none;
  padding: 0 1em 0 0;
  width: 100%;
  height: 100%;
  font-family: inherit;
  font-size: inherit;
  font-weight: bold;
  cursor: inherit;
  line-height: inherit;
  background-image: url('./assets/down_arrow.png');
	background-position: 98% center;
	background-repeat: no-repeat;
  background-size: 10%;
  border-bottom: solid  #BC477B;
::selection {
  background: rgb(188, 71, 123);
  color: white;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
</style>