Skip to content
Snippets Groups Projects
App.vue 12.1 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">
        <Autocomplete @submit="select_result" :endpoint="api_pref">
        </Autocomplete>
        <div class="lang_select_container">
          <select class="lang_select" name="lang"  v-model="lang">
            <option value="bob,nob">Begge ordbøker </option>
            <option value="bob">Bokmål</option>
            <option value="nob">Nynorsk</option>
          </select>
        </div>
      </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">
          <h2>Månedens ord</h2>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
          <div id="word-of-month-bm">
            <Article :article="monthly_bm" @article-click="article_link_click" />
          </div>
          <div id="word-of-month-nn">
            <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 Preview from './components/Preview.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);
  });

Ole Voldsæter's avatar
Ole Voldsæter committed
window.onpopstate = function (event) {
  if (event.state) {
    // eslint-disable-next-line
Ole Voldsæter's avatar
Ole Voldsæter committed
    app.__vue__._data.article = event.state.article
    // eslint-disable-next-line
Ole Voldsæter's avatar
Ole Voldsæter committed
    app.__vue__._data.search_results = event.state.search_results
    // eslint-disable-next-line
    app.__vue__._data.lang = event.state.lang
function navigate_to_article(self, source) {
  axios.get(api_endpoint + '/' + self.$route.params.lang + '/article/' + self.$route.params.id)
Ole Voldsæter's avatar
Ole Voldsæter committed
    self.article = response.data
    self.search_results = []
  })
  .catch(function(error){
    if (error.response && error.response.status == 404) {
      self.article = {
        lemmas: [],
        error: "Vi har ingen artikkel med id " + article_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 ''" + query + "'. (Søkeforlag kommer i en senere oppatering av Ordbøkene)"
      }
    }
    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)
    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: {
Ole Voldsæter's avatar
Ole Voldsæter committed
    SearchResults,
    Preview
  },
  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'})
      })
  },
  watch: {
    $route() {
      this.$plausible.trackEvent('language', {props: {code: this.$route.params.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: grid;
  grid-template-columns: 50% 50%;
  grid-template-rows: auto auto auto;
  gap: 10px;
  width: 100%;
  background-color: rgba(256,256,256,0.5)
}

div.monthly > h2{
  padding: 0px;
  grid-row: 1;
  grid-column: 1 / 3;
}

div.monthly > p {
  grid-row: 2;
  grid-column: 1 / 3;
}

div#monthly_bm {
  grid-row: 3;
  grid-column: 1;
}

div#monthly_nn {
  grid-row: 3;
  grid-column: 2;
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;
}

.show {
  display: block;
}

.hide {
  display: none;
}

.autocomplete {
  width: 25em;
Ole Voldsæter's avatar
Ole Voldsæter committed
  border-bottom: solid  #BC477B;
  border-radius: 0px;
.autocomplete-input {
  border-radius: 0px;
  background-color: #FFFFFF;
.autocomplete-result-list {
  max-height: 500px;
Ole Voldsæter's avatar
Ole Voldsæter committed
}

.lang-select-intro {
  font-size: smaller;
  font-weight: bold;
}
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 {
  display: flex;
  flex-direction: row;
  padding-top: 50px;
}

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>