diff --git a/package.json b/package.json
index 63b9df7..a03ce6e 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,8 @@
"vue-class-component": "^7.0.2",
"vue-property-decorator": "^8.1.0",
"vue-router": "^3.0.3",
- "vuex": "^3.0.1"
+ "vuex": "^3.0.1",
+ "vuex-class": "^0.3.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.8.0",
@@ -28,10 +29,12 @@
"@vue/cli-service": "^3.8.0",
"@vue/eslint-config-prettier": "^4.0.1",
"@vue/eslint-config-typescript": "^4.0.0",
+ "axios": "^0.18.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"typescript": "^3.4.3",
+ "vue-cli-plugin-axios": "^0.0.4",
"vue-cli-plugin-tailwindcss": "^0.1.1",
"vue-template-compiler": "^2.6.10"
}
diff --git a/src/App.vue b/src/App.vue
index afdab39..f47b4d0 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,10 +1,12 @@
-
+
+
+
@@ -13,18 +15,27 @@
@import "assets/styles/theme";
#app {
- display: flex;
+ @apply flex;
+}
+
+#navwrap {
+ @apply flex flex-1 flex-row px-2 justify-center;
+ background: var(--ink);
}
#topnav {
- flex: 1;
- display: flex;
- flex-direction: row;
- background: $ink;
+ @apply flex flex-auto flex-row w-full;
+ max-width: var(--maxwidth);
}
h1 {
- font-size: 18pt;
- font-weight: bolder;
+ @apply text-2xl font-bold;
}
+
+
diff --git a/src/assets/styles/theme.css b/src/assets/styles/theme.css
index 64809ed..6d828fd 100644
--- a/src/assets/styles/theme.css
+++ b/src/assets/styles/theme.css
@@ -3,6 +3,8 @@
--ink: #062f4f;
--posy: #813772;
--embers: #b82601;
+
+ --maxwidth: 960px;
}
body {
diff --git a/src/main.ts b/src/main.ts
index e4c32b2..2714d90 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,9 +1,11 @@
import Vue from "vue";
+import "./plugins/axios";
import App from "./App.vue";
import router from "./router";
-import store from "./store";
+import store from "./store/index";
import "./registerServiceWorker";
import "@/assets/styles/main.css";
+import "@/assets/styles/theme.css";
Vue.config.productionTip = false;
diff --git a/src/plugins/axios.js b/src/plugins/axios.js
new file mode 100644
index 0000000..04f5cd3
--- /dev/null
+++ b/src/plugins/axios.js
@@ -0,0 +1,61 @@
+"use strict";
+
+import Vue from "vue";
+import axios from "axios";
+
+// Full config: https://github.com/axios/axios#request-config
+// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
+// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
+// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
+
+let config = {
+ // baseURL: process.env.baseURL || process.env.apiUrl || ""
+ // timeout: 60 * 1000, // Timeout
+ // withCredentials: true, // Check cross-site Access-Control
+};
+
+const _axios = axios.create(config);
+
+_axios.interceptors.request.use(
+ function(config) {
+ // Do something before request is sent
+ return config;
+ },
+ function(error) {
+ // Do something with request error
+ return Promise.reject(error);
+ }
+);
+
+// Add a response interceptor
+_axios.interceptors.response.use(
+ function(response) {
+ // Do something with response data
+ return response;
+ },
+ function(error) {
+ // Do something with response error
+ return Promise.reject(error);
+ }
+);
+
+Plugin.install = function(Vue, options) {
+ Vue.axios = _axios;
+ window.axios = _axios;
+ Object.defineProperties(Vue.prototype, {
+ axios: {
+ get() {
+ return _axios;
+ }
+ },
+ $axios: {
+ get() {
+ return _axios;
+ }
+ }
+ });
+};
+
+Vue.use(Plugin);
+
+export default Plugin;
diff --git a/src/store.ts b/src/store.ts
deleted file mode 100644
index bb02ce2..0000000
--- a/src/store.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import Vue from "vue";
-import Vuex from "vuex";
-
-Vue.use(Vuex);
-
-export default new Vuex.Store({
- state: {},
- mutations: {},
- actions: {}
-});
diff --git a/src/store/actions.ts b/src/store/actions.ts
new file mode 100644
index 0000000..949171a
--- /dev/null
+++ b/src/store/actions.ts
@@ -0,0 +1,19 @@
+import { ActionTree } from "vuex";
+import { AppState } from "./types";
+
+const actions: ActionTree = {
+ // Add one or more sources
+ addSources({ commit, dispatch }, sources: EventSource[]) {
+ // Commit to state immediately
+ commit("appendSources", sources);
+ // Start fetching from each new source
+ sources.forEach(x => dispatch("fetchFromSource", x.url));
+ },
+
+ // Fetch events from a source url
+ async fetchFromSource({ commit }, url: string) {
+ //TODO
+ }
+};
+
+export default actions;
diff --git a/src/store/getters.ts b/src/store/getters.ts
new file mode 100644
index 0000000..3ca1892
--- /dev/null
+++ b/src/store/getters.ts
@@ -0,0 +1,17 @@
+import { GetterTree } from "vuex";
+import { AppState, Event, EventSource } from "./types";
+
+const getters: GetterTree = {
+ events(state): Event[] {
+ return Object.values(state.status)
+ .filter(x => x.fetched && x.error == null)
+ .map(x => x.events)
+ .flat();
+ },
+
+ sources(state): EventSource[] {
+ return state.sources;
+ }
+};
+
+export default getters;
diff --git a/src/store/index.ts b/src/store/index.ts
new file mode 100644
index 0000000..7bb6427
--- /dev/null
+++ b/src/store/index.ts
@@ -0,0 +1,20 @@
+import Vue from "vue";
+import Vuex from "vuex";
+import { AppState } from "./types";
+import mutations from "./mutations";
+import actions from "./actions";
+import getters from "./getters";
+
+Vue.use(Vuex);
+
+const state: AppState = {
+ sources: [],
+ status: {}
+};
+
+export default new Vuex.Store({
+ state,
+ mutations,
+ actions,
+ getters
+});
diff --git a/src/store/mutations.ts b/src/store/mutations.ts
new file mode 100644
index 0000000..51affd6
--- /dev/null
+++ b/src/store/mutations.ts
@@ -0,0 +1,20 @@
+import { MutationTree } from "vuex";
+import { AppState, FetchStatus, EventSource } from "./types";
+
+const mutations: MutationTree = {
+ appendSources(state, payload: EventSource[]) {
+ // Add sources to list
+ state.sources = state.sources.concat(payload);
+
+ // Set "loading" state for all of them
+ payload.forEach(x => {
+ state.status[x.url] = { fetched: false };
+ });
+ },
+
+ setSourceStatus(state, payload: { url: string; status: FetchStatus }) {
+ state.status[payload.url] = payload.status;
+ }
+};
+
+export default mutations;
diff --git a/src/store/types.ts b/src/store/types.ts
new file mode 100644
index 0000000..cf304e5
--- /dev/null
+++ b/src/store/types.ts
@@ -0,0 +1,25 @@
+import { Dict } from "@/types";
+
+export interface AppState {
+ sources: EventSource[];
+ status: Dict;
+}
+
+export interface EventSource {
+ url: string;
+}
+
+export interface Event {
+ source: string; // Source URL
+ data: EventData;
+}
+
+export interface EventData {
+ //TODO
+}
+
+export interface FetchStatus {
+ fetched: boolean;
+ error?: Error;
+ events?: Event[];
+}
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..48ca4ed
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1 @@
+export type Dict = { [key: string]: T };
diff --git a/yarn.lock b/yarn.lock
index 62bec56..1ebd4dd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1548,6 +1548,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+axios@^0.18.0:
+ version "0.18.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
+ integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
+ dependencies:
+ follow-redirects "1.5.10"
+ is-buffer "^2.0.2"
+
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -2712,6 +2720,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
dependencies:
ms "2.0.0"
+debug@=3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+ dependencies:
+ ms "2.0.0"
+
debug@^3.1.0, debug@^3.2.5, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -3717,6 +3732,13 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
+follow-redirects@1.5.10:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
+ dependencies:
+ debug "=3.1.0"
+
follow-redirects@^1.0.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
@@ -4520,6 +4542,11 @@ is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+is-buffer@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
+ integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
+
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -8343,6 +8370,11 @@ vue-class-component@^7.0.1, vue-class-component@^7.0.2:
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.1.0.tgz#b33efcb10e17236d684f70b1e96f1946ec793e87"
integrity sha512-G9152NzUkz0i0xTfhk0Afc8vzdXxDR1pfN4dTwE72cskkgJtdXfrKBkMfGvDuxUh35U500g5Ve4xL8PEGdWeHg==
+vue-cli-plugin-axios@^0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/vue-cli-plugin-axios/-/vue-cli-plugin-axios-0.0.4.tgz#29d4eb48275c7fe15b92e1fd5d95fbe2a966436f"
+ integrity sha512-p2b/fvPJuPBnvU8027PAAuU5DiOzUn2lku8XLG/f6c8FU0N+/MXWZAlOuHhqd9e7+KIZitwe/c8qlmv7TglbTg==
+
vue-cli-plugin-tailwindcss@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/vue-cli-plugin-tailwindcss/-/vue-cli-plugin-tailwindcss-0.1.1.tgz#e961e6f70a621fdbbf7b86b72cf065e7631d4c93"
@@ -8427,6 +8459,11 @@ vue@^2.6.10:
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
+vuex-class@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/vuex-class/-/vuex-class-0.3.2.tgz#c7e96a076c1682137d4d23a8dcfdc63f220e17a8"
+ integrity sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ==
+
vuex@^3.0.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"