Skip to content

Commit

Permalink
Themes
Browse files Browse the repository at this point in the history
  • Loading branch information
ThetaSinner authored and ThetaSinner committed Feb 17, 2024
1 parent 01fa2da commit a78481e
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 138 deletions.
3 changes: 1 addition & 2 deletions ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@

<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">

</head>
<body>
<body class="font-sans bg-base-100">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
Expand Down
124 changes: 80 additions & 44 deletions ui/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,57 +1,93 @@
<script setup lang="ts">
import { defineComponent, computed, inject, ComputedRef, ref, watch, provide, onMounted } from 'vue';
import { AppAgentClient, AppAgentWebsocket } from '@holochain/client';
import '@material/mwc-circular-progress';
import '@material/mwc-button';
import DistributeGpgKey from './trusted/trusted/DistributeGpgKey.vue';
import MyKeys from './trusted/trusted/MyKeys.vue';
import SearchKeys from './trusted/trusted/SearchKeys.vue';
import Notify from './component/Notify.vue';
import { useThemeStore } from './store/theme-store';
import Settings from './component/Settings.vue';
const themeStore = useThemeStore();
const client = ref<AppAgentClient | null>(null);
provide('client', client);
const loading = ref(true);
const showScreen = ref<'home' | 'search' | 'settings' | 'about'>('home');
const applyTheme = (theme: string) => {
document.documentElement.setAttribute('data-theme', theme);
};
onMounted(async () => {
// Set the current theme on load
applyTheme(themeStore.theme);
// then listen for changes to the theme and apply them
themeStore.$subscribe((_, state) => {
applyTheme(state.theme);
});
// We pass an unused string as the url because it will dynamically be replaced in launcher environments
client.value = await AppAgentWebsocket.connect(new URL('https://UNUSED'), 'hWOT');
loading.value = false;
});
</script>

<template>
<div>
<div v-if="loading">
<p class="text-lg p-12">Connecting to Holochain</p>
<span class="loading loading-infinity loading-lg"></span>
</div>
<div v-else>
<div id="content">
<DistributeGpgKey @gpg-key-dist-created="() => {}"></DistributeGpgKey>
<div class="navbar bg-base-100">
<div class="navbar-start">
<div class="dropdown">
<div tabindex="0" role="button" class="btn btn-ghost btn-circle">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" />
</svg>
</div>
<ul tabindex="0" class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52">
<li><a @click="showScreen = 'home'">Home</a></li>
<li><a @click="showScreen = 'settings'">Settings</a></li>
<li><a @click="showScreen = 'about'">About</a></li>
</ul>
</div>
</div>
<div class="navbar-center">
<button class="btn btn-ghost text-xl" @click="showScreen = 'home'">Web of Trust</button>
</div>
<div class="navbar-end">
<button class="btn btn-ghost btn-circle" @click="showScreen = 'search'">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</button>
</div>
</div>

<div v-if="showScreen === 'home'">
<MyKeys></MyKeys>

<SearchKeys></SearchKeys>

<Notify></Notify>
<DistributeGpgKey @gpg-key-dist-created="() => { }"></DistributeGpgKey>
</div>
<div v-else-if="showScreen === 'settings'">
<div class="container mx-auto w-1/2">
<Settings></Settings>
</div>
</div>
<div v-else-if="showScreen === 'search'">
<div class="container mx-auto">
<SearchKeys></SearchKeys>
</div>
</div>

<Notify></Notify>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
import { AppAgentClient, AppAgentWebsocket } from '@holochain/client';
import '@material/mwc-circular-progress';
import '@material/mwc-button';
import DistributeGpgKey from './trusted/trusted/DistributeGpgKey.vue';
import MyKeys from './trusted/trusted/MyKeys.vue';
import SearchKeys from './trusted/trusted/SearchKeys.vue';
import Notify from './component/Notify.vue';
export default defineComponent({
components: {
DistributeGpgKey,
MyKeys,
SearchKeys,
Notify,
},
data(): {
client: AppAgentClient | undefined;
loading: boolean;
} {
return {
client: undefined,
loading: true,
};
},
async mounted() {
// We pass an unused string as the url because it will dynamically be replaced in launcher environments
this.client = await AppAgentWebsocket.connect(new URL('https://UNUSED'), 'hWOT');
this.loading = false;
},
provide() {
return {
client: computed(() => this.client),
};
},
});
</script>
2 changes: 1 addition & 1 deletion ui/src/component/Notify.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useNotificationsStore } from '../store/notifications';
import { useNotificationsStore } from '../store/notifications-store';
const notifications = useNotificationsStore();
Expand Down
30 changes: 30 additions & 0 deletions ui/src/component/Settings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useThemeStore, Theme } from '../store/theme-store';
const themeStore = useThemeStore();
const themeToggle = ref(!themeStore.isDefault);
watch(themeToggle, (newVal) => {
console.log('set theme', newVal)
if (newVal) {
console.log('call set theme');
themeStore.setTheme(Theme.Luxury);
} else {
themeStore.setTheme(Theme.Bumblebee);
}
});
</script>

<template>

<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Theme</span>
<input type="checkbox" class="toggle" v-model="themeToggle" />
</label>
</div>

</template>
File renamed without changes.
33 changes: 33 additions & 0 deletions ui/src/store/theme-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { defineStore } from "pinia";
import { computed, ref } from "vue";

export enum Theme {
Bumblebee = 'bumblebee',
Luxury = 'luxury'
}

export const useThemeStore = defineStore('theme', () => {
const theme = ref<string>(Theme.Bumblebee)

const stored = localStorage.getItem('theme')
if (stored) {
console.log('recover from stored', stored)
theme.value = stored as Theme
}

const setTheme = (newTheme: Theme) => {
console.log('do set theme', newTheme)
theme.value = newTheme
localStorage.setItem('theme', newTheme)
}

const isDefault = computed(() => {
return theme.value === Theme.Bumblebee
})

return {
theme,
setTheme,
isDefault,
}
})
83 changes: 0 additions & 83 deletions ui/src/style.css
Original file line number Diff line number Diff line change
@@ -1,86 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--mdc-theme-primary: #7B1FA2;
--mdc-theme-secondary: #FF5722;
}

:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;

font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}

a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}

body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}

h1 {
font-size: 3.2em;
line-height: 1.1;
}

button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}

.card {
padding: 2em;
}

#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
48 changes: 40 additions & 8 deletions ui/src/trusted/trusted/SearchKeys.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { AppAgentClient, Record } from '@holochain/client';
import { ComputedRef, inject, ref } from 'vue';
import { GpgKeyDist, SearchKeysRequest } from './types';
import { decode } from '@msgpack/msgpack';
import { useNotificationsStore } from '../../store/notifications';
import { useNotificationsStore } from '../../store/notifications-store';
import { useMyKeysStore } from '../../store/my-keys-store';
const searchQuery = ref('');
const searching = ref(false)
Expand All @@ -12,6 +13,7 @@ const results = ref<GpgKeyDist[]>([]);
const client = inject('client') as ComputedRef<AppAgentClient>;
const notifications = useNotificationsStore();
const myKeysStore = useMyKeysStore();
const searchKeys = async () => {
if (!client.value || searching.value) return;
Expand Down Expand Up @@ -45,23 +47,53 @@ const searchKeys = async () => {
}
}
const isMine = (keyDist: GpgKeyDist) => {
return myKeysStore.myKeys.some((r) => r.fingerprint === keyDist.fingerprint);
}
</script>

<template>
<span>Search for keys by user id, email or fingerprint</span>
<p>Search for keys by user id, email or fingerprint.</p>
<p class="text-sm italic">An exact match is required for all fields and the fingerprint should be in upper-case hex.</p>

<form @submit="e => e.preventDefault()">
<div class="join">
<input type="text" class="input input-bordered join-item" placeholder="Search" name="search-for-keys" id="search-for-keys" v-model="searchQuery" />
<button class="btn join-item min-w-24" @click="searchKeys" :disabled="!searchQuery">
<div class="join flex w-full">
<input type="text" class="input input-bordered join-item grow" placeholder="Search" name="search-for-keys"
id="search-for-keys" v-model="searchQuery" />
<button class="btn btn-primary join-item min-w-24" @click="searchKeys" :disabled="!searchQuery">
<span v-if="searching" class="loading loading-spinner"></span>
<span v-else>Search</span>
</button>
</div>
</form>

<div v-for="r in results" v-bind:key="r.fingerprint">
<div class="font-bold">{{ r.fingerprint }}</div>
<div>{{ r.user_id }}</div>
<div class="mt-5">
<p>Search results</p>

<table class="table">
<!-- head -->
<thead>
<tr>
<th>User ID</th>
<th>Email</th>
<th>Fingerprint</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="r in results" v-bind:key="r.fingerprint">
<td>{{ r.user_id }}</td>
<td>{{ r.email ?? '-' }}</td>
<td>{{ r.fingerprint }}</td>
<td>
<p v-if="isMine(r)" class="font-bold text-primary">Mine</p>
<div v-else>
<button class="btn btn-primary" @click="() => { }">Add</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
4 changes: 4 additions & 0 deletions ui/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ export default {
extend: {},
},
plugins: [require('daisyui')],
daisyui: {
themes: ['bumblebee', 'luxury'],
darkTheme: 'luxury',
},
}

0 comments on commit a78481e

Please sign in to comment.