summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Footer.vue5
-rw-r--r--src/components/Logo.vue9
-rw-r--r--src/components/Navigation.vue6
-rw-r--r--src/components/News.vue47
-rw-r--r--src/components/ServerStatus.vue11
5 files changed, 48 insertions, 30 deletions
diff --git a/src/components/Footer.vue b/src/components/Footer.vue
index 4d1df2e..076700e 100644
--- a/src/components/Footer.vue
+++ b/src/components/Footer.vue
@@ -13,10 +13,9 @@
</style>
<script lang="ts">
-import Vue from "vue"
-import Component from "vue-class-component"
+import { Options, Vue } from "vue-class-component";
-@Component
+@Options({})
export default class Copyright extends Vue {
year = Reflect.construct(Date, []).getFullYear();
}
diff --git a/src/components/Logo.vue b/src/components/Logo.vue
index 20f071e..8b653e1 100644
--- a/src/components/Logo.vue
+++ b/src/components/Logo.vue
@@ -14,7 +14,6 @@
url("../assets/fonts/AlbertusTMW.woff") format("woff"),
url("../assets/fonts/AlbertusTMW.ttf") format("truetype");
}
-
.logo {
/* this is all relative because our mobile site has to be responsive */
background: url(../assets/logo.svg) no-repeat left top; /* FIXME: the -small logo is fugly */
@@ -23,21 +22,19 @@
font-family: "Albertus TMW", "Arial Black", "Times New Roman", fantasy;
font-size: 7vw;
text-shadow: 0.03ch 0.07ch #070905;
+ text-decoration: none;
color: #34B039;
height: 11vw;
cursor: pointer;
z-index: 200;
max-width: calc(90% - 15vw);
-
&::selection {
text-shadow: none;
}
-
& span:last-of-type {
display: none;
}
}
-
@media (min-width: 800px) {
.logo {
background-image: url(../assets/logo.svg);
@@ -47,14 +44,12 @@
height: 100px;
margin-top: 20px;
position: relative;
-
& span:first-of-type {
position: absolute;
left: 125px;
top: 0;
font-size: 0.6em;
}
-
& span:last-of-type {
display: inline;
position: absolute;
@@ -69,7 +64,6 @@
}
}
}
-
@media (max-width: 300px) {
.logo {
background-image: url(../assets/logo-extrasmall.svg);
@@ -78,7 +72,6 @@
text-shadow: none;
}
}
-
@media (min-width: 1100px) {
.logo {
max-width: 100%;
diff --git a/src/components/Navigation.vue b/src/components/Navigation.vue
index bb40e22..783e12a 100644
--- a/src/components/Navigation.vue
+++ b/src/components/Navigation.vue
@@ -58,6 +58,7 @@
border-radius: 5px;
border: solid 1px #2f2e32;
margin-bottom: 13px;
+ min-width: 17ch;
& ul {
list-style: none;
@@ -149,11 +150,10 @@
</style>
<script lang="ts">
-import { Component, Vue } from "vue-property-decorator";
-import RouteRecord from "vue-router";
+import { Options, Vue } from "vue-class-component";
import ServerStatus from "@/components/ServerStatus.vue";
-@Component({
+@Options({
components: {
ServerStatus,
},
diff --git a/src/components/News.vue b/src/components/News.vue
index 7ad844f..3243b3b 100644
--- a/src/components/News.vue
+++ b/src/components/News.vue
@@ -2,12 +2,17 @@
<div class="news" v-if="count">
<span v-if="!entries.length">(no news entries)</span>
- <article class="entry" v-for="entry in entries" :id="entry.id">
+ <article class="entry" v-for="entry in entries" :id="entry.id" v-bind:key="entry.id">
<a :href="'#' + entry.id">{{ entry.title }}</a>
<time :datetime="entry.date" class="date">{{ entry.date }}</time>
<section class="body" v-html="entry.html"></section>
<q>{{entry.author}}</q>
</article>
+ <article v-if="count > 1 && !fullyLoaded" class="entry loading">
+ <section class="body">
+ Loading... Please wait.
+ </section>
+ </article>
</div>
</template>
@@ -55,7 +60,7 @@
& .body {
margin-top: 2ex;
- &::v-deep > b {
+ &:deep(b) {
display: block;
margin-bottom: 1ex;
}
@@ -95,7 +100,7 @@
</style>
<script lang="ts">
-import { Component, Prop, Vue } from "vue-property-decorator";
+import { Options, Vue } from "vue-class-component";
import newsEntries from "@/assets/news.json";
interface NewsEntry {
@@ -106,36 +111,57 @@ interface NewsEntry {
html: string;
}
-@Component
+@Options({
+ props: {
+ count: Number,
+ from: Number,
+ }
+})
export default class News extends Vue {
- @Prop({ default: Infinity }) private count!: number;
- @Prop({ default: 0 }) private from!: number;
+ private count = Infinity;
+ private from = 0;
private entries: NewsEntry[] = (newsEntries as NewsEntry[]).slice(this.from, this.count);
+ private fullyLoaded = false;
beautify () {
this.entries.forEach(entry => {
// FIXME: weird Vue bug
entry.html = entry.html.replace(/<br\/>/g,"<br></br>");
+
+ // compare the entry title with its first line:
+ const compare = `<b>${entry.title}</b><br></br>`;
+
+ if (entry.html.startsWith(compare)) {
+ // duplicate title: remove the extra one
+ entry.html = entry.html.slice(compare.length);
+ }
});
}
mounted () {
if (!process.env.VUE_APP_NEWS_JSON || !process.env.VUE_APP_NEWS_JSON.startsWith("https")) {
- // TODO: allow arbitrary paths (no hardcoded news.json)
this.beautify();
+ // no extra news to load so end here
return;
}
// restore from cache while we're loading a fresh copy
if (Reflect.has(self, "localStorage")) {
- let newsCache = localStorage.getItem("newsCache");
+ const newsCache = localStorage.getItem("newsCache");
if (newsCache !== null) {
this.entries = (JSON.parse(newsCache) as NewsEntry[]).slice(this.from, this.count);
- this.beautify();
}
}
+ // initial rendering
+ this.beautify();
+
+ if (this.count === 1 && this.entries.length >= 1) {
+ // don't loaad extra news unprompted
+ return;
+ }
+
const req = new Request(process.env.VUE_APP_NEWS_JSON, {
method: "GET",
cache: "default", // serve if fresh, else fetch
@@ -145,13 +171,14 @@ export default class News extends Vue {
.then(data => data.json())
.then(data => {
this.entries = (data as NewsEntry[]).slice(this.from, this.count);
+ this.fullyLoaded = true;
this.beautify();
if (Reflect.has(self, "localStorage")) {
localStorage.setItem("newsCache", JSON.stringify(data));
}
})
- .catch(e => {
+ .catch(() => {
// no news (will use cache, if any)
})
}
diff --git a/src/components/ServerStatus.vue b/src/components/ServerStatus.vue
index 68f7bd4..4b1e0d9 100644
--- a/src/components/ServerStatus.vue
+++ b/src/components/ServerStatus.vue
@@ -2,7 +2,7 @@
<aside>
<a v-if="Online && Players" target="_blank" rel="noopener" href="https://server.themanaworld.org">Online: {{Players}} players</a>
<a v-if="Online && !Players" target="_blank" rel="noopener" href="https://server.themanaworld.org">Online</a>
- <a v-if="!Online" class="offline" target="_blank" rel="noopener" href="https://www.youtube.com/watch?v=ILVfzx5Pe-A">Offline</a>
+ <a v-if="!Online" class="offline" target="_blank" rel="noopener" href="https://www.youtube-nocookie.com/embed/ILVfzx5Pe-A?autoplay=1&amp;modestbranding=1">Offline</a>
</aside>
</template>
@@ -21,15 +21,14 @@ aside :any-link {
</style>
<script lang="ts">
-import Vue from "vue"
-import Component from "vue-class-component"
+import { Options, Vue } from "vue-class-component";
interface StatusResponse {
serverStatus: string;
playersOnline?: number;
}
-@Component
+@Options({})
export default class ServerStatus extends Vue {
Players = 0;
Online = true;
@@ -41,8 +40,8 @@ export default class ServerStatus extends Vue {
});
try {
- const raw_response = await fetch(req);
- const data: StatusResponse = await raw_response.json();
+ const rawResponse = await fetch(req);
+ const data: StatusResponse = await rawResponse.json();
this.Online = data.serverStatus === "Online";
this.Players = data.playersOnline || 0;