Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Showing
with 2836 additions and 356 deletions
google-site-verification=i2hk16Pgpgw1Ld_XeejQrFttyZcKtEDwsdSa_oGs_Ms
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<html lang="no">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>Ordbok - Beta</title>
<link rel="apple-touch-icon" href="<%= BASE_URL %>touch-icon.png">
<meta property="og:title" content="Ordbøkene.no - Bokmålsordboka og Nynorskordboka" />
<meta property="twitter:title" content="Ordbøkene.no - Bokmålsordboka og Nynorskordboka" />
<meta property="og:type" content="website" />
<meta property="og:url" content="ordbokene.no" />
<meta property="og:description" content="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." />
<meta property="twitter:description" content="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." />
<meta property="og:image" content="<%= BASE_URL %>logo.png" />
<meta property="og:image:width" content="256px" />
<meta property="og:image:height" content="256px" />
<meta property="twitter:image" content="<%= BASE_URL %>logo.png" />
<meta property="description" content="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." />
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/fC1lPYxPY3rXxEndZJAzN3Srdy0.0ad9c62f.woff2" type="font/woff2" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/fC14PYxPY3rXxEndZJAzN3wQUjjCjl0.2712a85c.woff2" type="font/woff2" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/NotoSansParen.967bb7ff.woff" type="font/woff" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/o-0IIpQlx3QUlC5A4PNr5TRA.df7d440a.woff2" type="font/woff2" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/o-0NIpQlx3QUlC5A4PNjXhFVZNyBx2pqPA.887e23ab.woff2" type="font/woff2" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/o-0OIpQlx3QUlC5A4PNr4ARCQ_k.6816e3a8.woff2" type="font/woff2" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/MaterialIcons-Regular.51cf1d64.ttf" type="font/ttf" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/MaterialIcons-Regular.84a37de8.woff" type="font/woff" crossorigin="anonymous"/>
<link rel="preload" as="font" href="<%= BASE_URL %>fonts/MaterialIcons-Regular.703cf8f2.woff2" type="font/woff2" crossorigin="anonymous"/>
<title>Ordbøkene.no - Bokmålsordboka og Nynorskordboka</title>
</head>
<body>
<noscript>
<strong>We're sorry but ordbok_vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
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.
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
public/logo.png

4.96 KiB

# Disable search engine indexing
User-agent: *
Disallow: /
\ No newline at end of file
public/touch-icon.png

2.79 KiB

<template>
<v-app id="app">
<header>
<h1><a href="/">Ordbøkene <span class="beta">(BETA)</span></a></h1>
<p class="about-link"><a href="#">OM ORDBØKENE</a></p>
<p class="sub-title"><a href="/">Bokmålsordboka | Nynorskordboka – rett norsk</a></p>
</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>
<router-link ref="skip_link" to="#main" class="skip-link" @click.native="focus_main">{{$t('accessibility.main_content')}}</router-link>
<div>
<TopBar/>
</div>
<div v-if="$route.name!='about'" class = "banner" :class="$vuetify.breakpoint">
<div v-if="show_banner_text">
<a href="/">
<h1 :class="$vuetify.breakpoint.name">Ordbøkene</h1></a>
<p class="sub-title">{{$t("sub_title")}}</p>
</div>
</div>
<router-view ref="router_view"></router-view>
<footer :class="$vuetify.breakpoint.name">
<div id="photo-attribution" aria-hidden="true" v-if="!$route.name && $vuetify.breakpoint.mdAndUp">{{$t('photo')}}</div>
<div class="footer-row">
<div class="logos" :class="$vuetify.breakpoint.xs?'sm':'lg'">
<img id="srlogo" src="./assets/Sprakradet_logo_neg.png" alt="Språkrådet, logo">
<img id="uiblogo" src="./assets/uib-logo.svg" alt="Universitetet i Bergen, logo">
</div>
<img id="spinner" :class="waiting ? 'show' : 'hide'" src="./assets/spinner.gif" alt="Venter på innhold" />
<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 class="footer-text"><em>{{$t('dicts.bm')}}</em>{{$t('and')}}<em>{{$t('dicts.nn')}}</em>{{$t('footer_description')}}
</div>
<div class="welcome" v-show="! (article.error || article.lemmas.length || search_results.length || waiting)">
</div>
</main>
<footer>
<div>
<img id="srlogo" src="./assets/Sprakradet_logo_neg.png" alt="">
</div>
<div>
<img id="uiblogo" src="./assets/uib-logo.svg" alt="">
</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>
<FooterMenu />
<div></div></div>
<div class="accessibility-declaration"><a href="https://uustatus.no/nb/erklaringer/publisert/b2a6f8d0-3a16-4716-8bc8-46ac3c161935" target="_blank">{{$t('accessibility_statement')}}</a><v-icon color="white" small>open_in_new</v-icon></div>
</footer>
</v-app>
</template>
<script>
import axios from "axios"
import entities from './utils/entities.js'
import Article from './components/Article.vue'
import Preview from './components/Preview.vue'
import SearchResults from './components/SearchResults.vue'
import Autocomplete from './components/Autocomplete.vue'
var api_endpoint = 'https://beta.ordbok.uib.no/api/dict'
axios.interceptors.request.use(function (config) {
config.headers["x-api-key"] = "ZkYiyRVXxH86ijsvhx3cH4SY5Iik2ijI3BKVJGMm"
return config;
}, function (error) {
return Promise.reject(error);
});
window.onpopstate = function (event) {
if (event.state) {
// eslint-disable-next-line
app.__vue__._data.article = event.state.article
// eslint-disable-next-line
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)
.then(function(response){
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){
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: [], lang: self.lang}, '')
if (source) {
self.$plausible.trackEvent('internal link incoming', {props: {origin: source}})
}
})
}
import TopBar from './components/TopBar.vue'
import FooterMenu from './components/FooterMenu.vue'
function navigate_to_search(self, query) {
axios.get(self.api_pref + 'search?q=' + query)
.then(function(response){
self.search_results = response.data
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)"
}
}
self.waiting_for_articles = false
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}, '')
})
}
export default {
metaInfo() {
return { htmlAttrs: {lang: {nob: "nb", nno: "nn", eng: "en", ukr: "uk"}[this.$i18n.locale]}}
export default {
name: 'app',
data: function() {
return {
article_key: 0,
search_results: [],
lang: 'bob,nob',
waiting_for_articles: true,
waiting_for_metadata: true,
article: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
}
},
computed: {
waiting: function() {
return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
},
api_pref: function() {
return api_endpoint + '/' + this.lang + '/article/'
}
},
components: {
Article,
Autocomplete,
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.q, match: event.match}})
}else{
this.waiting_for_articles = true
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
this.$router.push(`/${this.lang}/search/${event.q}`)
navigate_to_search(this, event.q)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.q, match: '<fritekstsøk>'}})
computed: {
show_banner_text: function() {
return !this.$route.name || (window.innerHeight > 800 && this.$route.name != 'about' )
}
},
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}, '')
}else{
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
this.waiting_for_articles = true
navigate_to_article(this, item.source)
}
}
},
mounted: function(){
let self = this
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') {
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') {
self.lang = self.$route.params.lang
navigate_to_search(self, self.$route.params.query)
components: {
TopBar,
FooterMenu
},
data: function() {
return {
contact_dialog: false,
help_dialog: false,
announcement: localStorage.getItem('app_info') == 'false' ? false : true,
announce_test: localStorage.getItem('beta_info') == 'false' ? false : true
}
else {
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}, '')
},
methods: {
close_announcement: function() {
localStorage.setItem('app_info', 'false')
this.announcement = false
},
close_test_announcement: function() {
localStorage.setItem('beta_info', 'false')
this.announce_test = false
},
focus_main: function() {
this.$refs.router_view.$refs.main.focus();
}
})
},
watch: {
$route() {
this.$plausible.trackEvent('language', {props: {code: this.$route.params.lang}})
}
}
}
</script>
<style>
@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');
@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');
@font-face {
font-family: 'Noto Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('./assets/o-0NIpQlx3QUlC5A4PNjXhFVZNyBx2pqPA.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Inria Serif';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('./assets/fC1lPYxPY3rXxEndZJAzN3Srdy0.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Inria Serif';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('./assets/fC14PYxPY3rXxEndZJAzN3wQUjjCjl0.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Noto Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('./assets/o-0IIpQlx3QUlC5A4PNr5TRA.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Noto Sans';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('./assets/o-0OIpQlx3QUlC5A4PNr4ARCQ_k.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: NotoParen;
font-style: italic;
src: url('./assets/NotoSansParen.woff') format('woff');
unicode-range: U+28-29;
}
#app {
font-family: 'Noto Sans', Helvetica, Arial, sans-serif;
font-family: NotoParen, 'Noto Sans', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
display: flex;
flex-direction: column;
height: 100%;
color: var(--v-text-base);
background-color: var(--v-tertiary-base)
}
html, body {
height: 100%
}
body {
margin: 0px;
main {
flex: 1;
}
h1 {
h1, .article h3 {
font-family: Inria Serif;
font-size: 36px;
color: #560027;
padding-left: 15px;
color: var(--v-primary-base)
}
p a, .article a, .search_notification a, .did_you_mean a, .info-card a {
color: var(--v-text-base) !important;
text-decoration: none;
border-bottom: 1px solid var(--v-anchor-base);
header > h1 {
color: #BC477B;
font-size: 40px;
margin: 0px;
}
p.about-link {
text-align: right;
margin: 0px;
float: right;
p a:hover, .article a:hover, .search_notification a:hover, .info-card a:hover {
color: var(--v-anchor-base) !important;
}
header a {
color: inherit;
text-decoration: none;
a.article_header {
border: none;
}
span.beta {
color: #BBBBBB;
.banner h1 {
font-size: 48px;
}
p.about-link > a{
text-decoration: none;
border-bottom: solid #BC477B 4px;
font-size: 12px;
color: #FDF4F5;
h1.xs, h1.sm {
font-size: 36px;
}
main {
padding-bottom: 20px;
flex: 1 0 auto;
background-color: #FDF4F5;
.banner {
padding-top: 10px;
}
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 {
padding-left: calc((100vw - 1000px) / 2);
padding-right: calc((100vw - 1000px) / 2);
.v-list-item__title {
word-break: break-all;
overflow-wrap: break-word;
}
header {
padding-top: 20px;
padding-bottom: 20px;
background-color: #560027;
.banner p {
padding-bottom: 10px;
padding-top: 0;
padding-left: 18px;
}
div.welcome {
font-size: 20px;
.banner a {
text-decoration: none;
color: var(--v-primary-base) !important;
}
.top {
color: #560027;
font-weight: bold;
font-size: smaller;
border-bottom: solid;
border-color: #BC477B;
.beta {
font-family: Inria Serif;
font-size: 18px;
color: white;
margin-left: 10px;
}
.mission-statement {
font-size: 16px;
margin: 0px;
color: #FDF4F5;
.language-dialog-title {
font-family: Inria Serif;
color: white;
}
.sub-title {
font-size: 20px;
margin: 0px;
color: #FDF4F5;
.top-bar .v-toolbar__content {
padding-left: calc((100vw - 1200px) / 2) !important;
padding-right: calc((100vw - 1200px) / 2) !important;
}
.show {
display: block;
.banner {
position: relative;
padding-left: calc((100vw - 1200px) / 2);
padding-right: calc((100vw - 1200px) / 2);
background-color: var(--v-tertiary-base);
}
.hide {
.banner.xs, .banner.sm {
padding-top: 0px;
}
.banner.xs div, .banner.sm div{
display: none;
}
.autocomplete {
width: 25em;
border-bottom: solid #BC477B;
border-radius: 0px;
}
.sub-title {
font-size: 18px;
margin: 0px;
margin-bottom: 0px !important;
.autocomplete-input {
border-radius: 0px;
background-color: #FFFFFF;
}
.autocomplete-result-list {
max-height: 500px;
.sub-title {
color: var(--v-primary-base) !important;
}
.lang-select-intro {
font-size: smaller;
font-weight: bold;
footer a, .notification a {
color: #ffffff !important;
}
footer {
padding-left: calc((100vw - 1200px) / 2);
padding-right: calc((100vw - 1200px) / 2);
font-size: smaller;
display: table;
flex-direction: row;
background-color: #570B27;
background-color: var(--v-primary-base);
color: #ffffff;
padding-bottom: 10px;
}
.search_container {
.logos {
display: flex;
flex-direction: row;
padding-top: 50px;
align-items: center;
flex-direction: row !important;
gap: 10px;
padding: 10px;
padding-left: 24px;
}
li.suggestion {
font-weight: bold;
padding-left: 20px;
padding-top: 5px;
padding-bottom: 5px;
border: 0px;
background-image: none;
.accessibility-declaration {
text-align: center;
padding-top: 10px;
}
footer > div {
display: table-cell;
vertical-align: middle;
padding: 10px;
.footer-row {
display: flex;
flex-direction: rows;
align-content: center;
align-items:center;
padding-top: 24px;
gap: 10px;
}
footer.sm .footer-row, footer.xs .footer-row{
display: flex;
flex-direction: column;
padding-left: 24px;
gap: 10px;
}
footer.sm div, footer.xs div {
justify-content: center;
justify-items: center;
}
#srlogo {
height: 20px;
}
......@@ -382,23 +318,95 @@ footer > div {
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;
.v-btn {
font-weight: bold !important;
}
.article .v-btn:focus, .v-dialog .v-btn:focus {
outline: solid 2px var(--v-primary-base) !important;
}
/* all inflection-table css shoud be moved to beta.ordbok */
.infl-table caption {
position: absolute !important;
height: 1px; width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
}
td[class="infl-group"] {
background-color: var(--v-button-base) !important;
color: var(--v-text-base) !important;
font-style: normal !important;
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;
}
th[class="infl-group"] {
background-color: var(--v-button-base) !important;
font-style: unset;
}
.v-application .rounded-t-xl {
border-top-left-radius: 28px !important;
border-top-right-radius: 28px !important;
}
.v-application .rounded-xl {
border-radius: 28px !important;
}
.theme--light.v-label, .theme--light.v-subheader, .transparent-text{
color: var(--v-text-base)
}
#photo-attribution {
position: absolute;
right: 0px;
width: 100%;
text-align: right;
padding-right: 6px;
padding-top: 1px;
padding-right: 6px;
color: white;
font-size: smaller;
}
.article h5, .about h3 {
color: var(--v-primary-base);
font-size: 14px;
padding-left: 12px;
padding-top: 6px;
}
.article h4, .monthly-title h2, .about h2, .v-dialog h2 {
font-size: 1.17em;
color: var(--v-primary-base);
font-variant: all-small-caps;
}
.skip-link {
position: absolute;
top: -10
}
.skip-link:focus {
position: unset;
top: unset;
text-align: center;
padding: 10px;
width: 100%;
color: white;
background-color: var(--v-secondary-base)
}
.v-alert {
border-radius: 0px !important;
}
</style>
<template>
<router-view/>
</template>
File added
<svg width="23" height="18" viewBox="0 0 23 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.3145 7.98256L3.82615 7.98256L11.8993 0.737929C12.0284 0.621157 11.9501 0.404295 11.7795 0.404295L9.73927 0.404295C9.64936 0.404295 9.56406 0.437659 9.49721 0.497236L0.785442 8.31143C0.705653 8.38293 0.641662 8.47132 0.597805 8.57062C0.553949 8.66991 0.531251 8.77779 0.531251 8.88695C0.531252 8.99611 0.553949 9.10399 0.597805 9.20328C0.641662 9.30258 0.705653 9.39097 0.785443 9.46247L9.54793 17.3243C9.58251 17.3553 9.624 17.372 9.6678 17.372L11.7772 17.372C11.9478 17.372 12.0261 17.1527 11.897 17.0384L3.82615 9.79372L22.3145 9.79372C22.4159 9.79372 22.4989 9.70792 22.4989 9.60307L22.4989 8.17321C22.4989 8.06835 22.4159 7.98256 22.3145 7.98256Z" fill="#560027"/>
</svg>
<svg width="23" height="18" viewBox="0 0 23 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.247987 10.3045L18.7364 10.3045L10.6632 17.5492C10.5341 17.6659 10.6124 17.8828 10.783 17.8828L12.8232 17.8828C12.9131 17.8828 12.9984 17.8494 13.0653 17.7899L21.7771 9.97568C21.8568 9.90418 21.9208 9.81579 21.9647 9.71649C22.0086 9.6172 22.0313 9.50932 22.0313 9.40016C22.0313 9.291 22.0086 9.18312 21.9647 9.08383C21.9208 8.98453 21.8568 8.89614 21.7771 8.82464L13.0146 0.962785C12.98 0.931804 12.9385 0.915122 12.8947 0.915122L10.7853 0.915122C10.6147 0.915122 10.5364 1.13437 10.6655 1.24876L18.7364 8.49339L0.247987 8.49339C0.146554 8.49339 0.0635613 8.57918 0.0635613 8.68404L0.0635612 10.1139C0.0635612 10.2188 0.146554 10.3045 0.247987 10.3045Z" fill="#560027"/>
</svg>
src/assets/background.jpg

451 KiB

File added
File added
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="logo-icon.svg"
inkscape:export-filename="/home/has022/Documents/256.png"
inkscape:export-xdpi="170.66667"
inkscape:export-ydpi="170.66667">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4545">
<stop
style="stop-color:#560027;stop-opacity:1;"
offset="0"
id="stop4541" />
<stop
style="stop-color:#560027;stop-opacity:0;"
offset="1"
id="stop4543" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4545"
id="linearGradient4547"
x1="9.9130554"
y1="277.94998"
x2="28.186945"
y2="277.94998"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="233.45423"
inkscape:cy="-7.9212896"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2084"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-280.06665)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:35.27777863px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#bc477b;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="1.4181669"
y="295.72998"
id="text3715"><tspan
sodipodi:role="line"
x="1.4181669"
y="295.72998"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.16666603px;font-family:'Inria Serif';-inkscape-font-specification:'Inria Serif';fill:#bc477b;fill-opacity:1;stroke-width:0.26458332"
id="tspan21">O</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="144"
height="144"
viewBox="0 0 38.099999 38.100001"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="anchor-icon.svg"
inkscape:export-filename="/home/has022/Documents/logo-transparent.png"
inkscape:export-xdpi="170.66667"
inkscape:export-ydpi="170.66667">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4545">
<stop
style="stop-color:#560027;stop-opacity:1;"
offset="0"
id="stop4541" />
<stop
style="stop-color:#560027;stop-opacity:0;"
offset="1"
id="stop4543" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4545"
id="linearGradient4547"
x1="9.9130554"
y1="277.94998"
x2="28.186945"
y2="277.94998"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="180.06393"
inkscape:cy="31.926411"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2084"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-258.89998)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:35.27777863px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#bc477b;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="8.4772501"
y="288.745"
id="text3715"><tspan
sodipodi:role="line"
x="8.4772501"
y="288.745"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.75px;font-family:'Inria Serif';-inkscape-font-specification:'Inria Serif';fill:#bc477b;fill-opacity:1;stroke-width:0.26458332"
id="tspan21">O</tspan></text>
</g>
</svg>
File added
File added
File added
This diff is collapsed.
<template>
<article v-show="article.lemmas.length || article.error">
<Header :lemmas="article.lemmas" :dictionary="dictionary" :article_id="article.article_id" />
<section v-if="! article.error && article.body.pronunciation && article.body.pronunciation.length">
<h3>Uttale</h3>
<ul>
<DefElement v-for="(element, index) in article.body.pronunciation" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" />
</ul>
</section>
<section v-if="! article.error && article.body.etymology && article.body.etymology.length">
<h3>Etymologi</h3>
<div v-if="article" :lang="{nob:'nb', nno: 'nn', eng: 'en', 'ukr': 'uk'}[dictionary]" class="article-container">
<span :lang="lang_tag_locale" v-if="$vuetify.breakpoint.smAndDown || !$route.name || $route.name == 'lookup'" class="dict-label" role="heading" aria-level="2">{{dict_label}}</span>
<div class="article" v-bind:class="{'expanded': !collapsed && collapsable, 'collapsable': collapsable, 'hide-label': hide_label, 'v-sheet v-card rounded-xl': !$parent.article}" v-if="article">
<div :class="$vuetify.breakpoint.name" v-if="!invalid">
<Header :title_id="title_id" :lemmas="article.lemmas" :dictionary="dictionary" :article_id="article.article_id" @toggle-collapse = "toggle_collapse"/>
<div class="article_content" :class="$vuetify.breakpoint.name" v-show="!collapsed" ref="article_content">
<section v-if="article.body.pronunciation && article.body.pronunciation.length" class="pronunciation">
<h4 :lang="lang_tag_locale">{{$t('article.headings.pronunciation', content_locale)}}</h4>
<ul>
<DefElement v-for="(element, index) in article.body.pronunciation" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" @error="article_error"/>
</ul>
</section>
<section v-if="article.body.etymology && article.body.etymology.length" class="etymology">
<h4 :lang="lang_tag_locale">{{$t('article.headings.etymology', content_locale)}}</h4>
<ul>
<DefElement v-for="(element, index) in article.body.etymology" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" @error="article_error"/>
</ul>
</section>
<section class="definitions" v-if="has_content">
<h4 :lang="lang_tag_locale">{{$t('article.headings.definitions', content_locale)}}</h4>
<ol>
<Definition v-for="definition in article.body.definitions" :dictionary="dictionary" :level="1" :key="definition.id" :body='definition' @article-click="article_link_click" @error="article_error"/>
</ol>
</section>
<section v-if="sub_articles.length" class="expressions">
<h4 :lang="lang_tag_locale">{{$t('article.headings.expressions', content_locale)}}</h4>
<ul>
<DefElement v-for="(element, index) in article.body.etymology" :dictionary="dictionary" :key="index" :body='element' @article-click="article_link_click" />
<SubArticle :body="subart" v-for="(subart, index) in sub_articles" :dictionary="dictionary" :key="index" @article-click="article_link_click" @error="article_error"/>
</ul>
</section>
<section v-if="! article.error">
<h3>Definisjoner</h3>
<ol>
<Definition v-for="definition in article.body.definitions" :dictionary="dictionary" :level="1" :key="definition.id" :body='definition' @article-click="article_link_click" />
</ol>
</section>
<section v-if="article.error">
<h1>Ooops...</h1>
<p>{{article.error}}</p>
</section>
</article>
</section>
</div>
<ArticleFooter v-if="!collapsed" :article="article"/>
</div>
<div v-else><v-icon left>warning</v-icon> {{$t('error.article', {no: article.article_id, dict: $t('dicts_inline.'+this.dictionary)})}}</div>
</div>
</div>
</template>
<script>
import DefElement from './DefElement.vue'
import Definition from './Definition.vue'
import SubArticle from './SubArticle.vue'
import Header from './Header.vue'
import ArticleFooter from './ArticleFooter.vue'
import entities from '../utils/entities.js'
import Mark from 'mark.js';
function find_sub_articles(definition) {
let sub_art_list = []
try {
let sub_definitions = definition.elements.filter(el => el.type_ == 'definition')
let sub_articles = definition.elements.filter(el => el.type_ == 'sub_article' && el.lemmas)
sub_definitions.forEach((subdef, i) => {
sub_art_list = sub_art_list.concat(find_sub_articles(subdef))
})
sub_art_list = sub_art_list.concat(sub_articles)
return sub_art_list
}
catch(error) {
console.log("find_sub_articles", this.article.article_id, this.dictionary, '"'+error.message+'"')
return []
}
}
export default {
name: 'Article',
props: {
article: Object
article: Object,
articleLookup: Boolean,
title_id: String,
queryPattern: String,
scope: String,
},
data: function() {
return {
is_collapsed: true,
invalid: false
}
},
metaInfo() {
if (this.articleLookup) {
return {title: this.article.lemmas[0].lemma + ' | ' + {"bm,nn": "Bokmålsordboka og Nynorskordboka", "bm": "Bokmålsordboka", "nn": "Nynorskordboka"}[this.dictionary],
meta: [{name: 'description', vmid: 'description', content: this.meta_description}],
link: [{rel: "canonical", href: `https://ordbokene.no/${this.article.dictionary}/${this.article.article_id}`} ]
}
}
},
computed: {
hide_label: function() {
//collapsable || (collapsed && $store.state.collapseArticles != 'never')
if (this.$parent.count_bm || this.$parent.count_nn) {
let two_results = (this.$parent.count_bm + this.$parent.count_nn) < 3
if (two_results) {
return false
}
else if (this.$vuetify.breakpoint.mdAndUp && (this.collapsed || this.$store.state.collapseArticles == 'never')) {
return true
}
else {
return false
}
}
},
dictionary: function() {
return this.article.dictionary || this.$route.params.lang
return this.article.dictionary
},
content_locale: function() {
if (this.$i18n.locale == 'eng') {
return 'eng'
} else if (this.$i18n.locale == 'ukr') {
return 'ukr'
} else {
return {bm: 'nob', nn: 'nno'}[this.dictionary]
}
},
fulltext_highlight: function() {
return this.$store.state.fulltextHighlight
},
collapsable: function() {
if (this.$parent.$options.name != 'SearchResults') {
this.is_collapsed = false
return false
}
let collapsable = this.$store.state.collapseArticles
if (collapsable == 'never') {
this.is_collapsed = false
return false
}
if (collapsable == 'always') {
this.is_collapsed = true
return true
}
if (collapsable == 'auto') {
this.is_collapsed = this.$parent.$options.name == 'SearchResults' && (this.$parent.results_bm.length + this.$parent.results_nn.length > 2)
return this.$parent.$options.name == 'SearchResults' && (this.$parent.results_bm.length + this.$parent.results_nn.length > 2)
}
},
collapsed: {
get() {
if (this.$parent.$options.name != 'SearchResults') {
return false
}
if (!this.collapsable) {
this.is_collapsed = false
}
return this.is_collapsed
},
set(value) {
this.is_collapsed = value
}
},
snippet: function() {
if (this.collapsable && this.article.body.definitions) {
return this.meta_description
}
return null
},
meta_description: function() {
return this.parse_definitions(this.article.body.definitions)
},
link_to_self: function() {
try {
return {
ref: '/' + this.dictionary + '/' + this.article.article_id,
article: this.article
}
} catch(error) {
console.log("link_to_self",this.article.article_id, this.dictionary, '"'+error.message+'"')
this.invalid = true
//console.error(error)
return {ref: "", article: this.article}
}
},
lang_tag_locale: function() {
return {nob: "nb", nno: "nn", eng: "en", ukr: "uk"}[this.content_locale]
},
dict_label: function() {
let label = ''
const dictionary = this?.article?.dictionary
if (dictionary) {
if (this.$route.name) {
label = this.$t(`dicts.${dictionary}`, this.content_locale)
} else {
label = this.$t('from', this.content_locale) + " " + this.$t(`dicts_from.${dictionary}`, this.content_locale)
}
}
return label
},
sub_articles: function() {
return this.article.body.definitions.reduce((acc, val) => acc.concat(find_sub_articles(val)), []).sort((s1, s2) => s1.lemmas[0].localeCompare(s2.lemmas[0]))
},
has_content: function() {
for (const definition of this.article.body.definitions) {
for (const element of definition.elements) {
if (['explanation', 'example', 'compound_list', 'definition'].includes(element.type_)) {
return true
}
}
}
return false
}
},
components: {
DefElement,
Definition,
Header
SubArticle,
Header,
ArticleFooter
},
mounted: function() {
if (this.scope && this.scope.includes("f")) {
let instance = new Mark(this.$refs.article_content)
if (/[_%|]/.test(this.queryPattern)) {
instance.markRegExp(new RegExp(this.queryPattern), {acrossElements: true, separateWordSearch:false});
}
else {
instance.mark(this.queryPattern, {acrossElements: true, separateWordSearch:false, accuracy: 'exact', wildcards: 'enabled'});
}
}
if (this.$route.hash == "#"+ this.title_id) {
let focused = document.getElementById(this.title_id)
if (focused) focused.focus()
}
else if (this.$route.hash) {
let focused =document.getElementById(this.$route.hash.replace("#",""))
if (focused) focused.scrollIntoView({block: "center"})
}
},
methods: {
article_error: function(payload) {
console.log("DefElement",payload.location, this.article.article_id, this.dictionary, '"'+payload.message+'"')
},
parse_subitems: function(explanation, text) {
let new_string = ""
let old_parts = text.split(/(\$)/)
let linkIndex = 0
let self = this
old_parts.forEach((item) => {
if (item == '$') {
let subitem = explanation.items[linkIndex]
if (/^\d$/.test(subitem.text)) {
if (subitem.type_ == "superscript") {
new_string += "⁰¹²³⁴⁵⁶⁷⁸⁹"[parseInt(subitem.text)]
}
else if (subitem.type_ == "subscript") {
new_string += "₀₁₂₃₄₅₆₇₈₉"[parseInt(subitem.text)]
}
}
else if (subitem.id) {
new_string += entities[self.dictionary][explanation.items[linkIndex].id].expansion
}
else if (subitem.text) {
if (subitem.text.includes('$')) {
new_string += self.parse_subitems(subitem, subitem.text)
}
else new_string += subitem.text
}
else {
if (explanation.items[linkIndex].lemmas) {
new_string += explanation.items[linkIndex].word_form || explanation.items[linkIndex].lemmas[0].lemma
}
}
linkIndex += 1
}
else {
new_string += item
}
})
return new_string
},
parse_definitions: function(node) {
let definitionTexts = []
let self = this
try {
node.forEach((definition) => {
if (definition.elements) {
if (definition.elements[0].content) {
let new_string = self.parse_subitems(definition.elements[0], definition.elements[0].content)
if (new_string.substring(new_string.length, new_string.length - 1) == ":") {
new_string = new_string.slice(0, -1)
}
definitionTexts.push(new_string)
}
else if (definition.elements[0].elements) {
definitionTexts.push(self.parse_definitions(definition.elements))
}
}
})
} catch(error) {
console.log("parse_definitions",this.article.article_id, this.dictionary, '"'+error.message+'"')
this.invalid = true
definitionTexts = []
}
let snippet = definitionTexts.join("\u00A0•\u00A0")
return snippet
},
toggle_collapse: function() {
if (this.collapsed) {
this.$plausible.trackEvent('expand article', {props: {article: `${this.dictionary} ${this.article.article_id}`}})
}
this.collapsed = !this.collapsed
},
article_link_click: function(item) {
this.$emit('article-click', item)
},
details_click: function(item) {
item.title_id = this.title_id
this.$emit('details-click', item)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
article {
padding: 10px;
margin: 10px;
border-radius: 10px;
background-color: #FFFFFF;
box-shadow: 10px 5px 5px rgba(0, 0, 0, 0.5);
.article {
position: relative;
padding: 24px;
padding-bottom: 12px;
margin-bottom: 20px;
margin-right: 10px;
margin-left: 10px;
background-color: #ffffff;
}
section.xs .article, section.sm .article {
margin-bottom: 10px !important;
}
h3 {
margin: 40px 0 0;
color: #560027;
section.md .article, section.lg .article, section.xl .article {
padding-top: 10px;
}
a {
color: #560027;
.welcome .article_footer {
display: block;
}
#single_article_container .article {
border: none;
margin-top: 10px;
}
section {
padding-top: 10px;
padding-bottom: 10px
}
section.etymology > h4, section.pronunciation > h4 {
display: inline;
}
section.etymology ul, section.pronunciation ul, section.etymology li, section.pronunciation li {
display: inline;
}
section.etymology li:not(:first-child):not(:last-child):before, section.pronunciation li:not(:first-child):not(:last-child):before {
content: ", ";
}
section.etymology li:not(:first-child):last-child:before, section.pronunciation li:not(:first-child):last-child:before {
content: "; ";
font-size: smaller;
}
li {
......@@ -86,23 +394,21 @@ li.level2.definition {
}
li.level3.definition {
list-style: lower-alpha;
/* Norsk ordbok skal ha "lower.alpha" her */
list-style: disc;
}
li.sub_article > ul {
padding-left: 0px;
}
li.definition.level1, li.definition.level2 {
padding-bottom: 2em;
}
::marker {
font-weight: bold;
color: #560027;
color: var(--v-primary-base);
}
ol > li:only-child.level1, li:only-child.level2, li:only-child.level3 {
ol > li:only-child.level1, li:only-child.level2 {
/* level3 a.k.a. underdefinisjoner skal vises med bullet selv om de står alene */
list-style: none;
}
......@@ -111,7 +417,7 @@ li:only-child.level1 > ol {
}
ul, ol {
padding-left: 20px;
padding-left: 12px !important;
}
ul li {
......@@ -122,4 +428,36 @@ ul li.definition {
list-style: disc;
}
.choose {
color: var(--v-primary-base) !important;
text-decoration: none;
}
.info-card {
padding: 12px;
}
.expanded {
padding-bottom: 34px;
}
.header {
border-radius: 0px !important;
}
.dict-label {
color: var(--v-primary-base) ;
font-weight: bold;
position: absolute;
padding-left: 34px;
margin-top: -2px;
z-index: 2;
font-variant-caps: all-small-caps;
font-size: 1.17em;
}
</style>