Compare commits

...

1 Commits

Author SHA1 Message Date
  Jared 461f3d6b13 Possible new custom interface 1 year ago
65 changed files with 450 additions and 323 deletions
Split View
  1. +2
    -2
      package.json
  2. +93
    -64
      src/App.vue
  3. BIN
      src/assets/PassionOne-Black.ttf
  4. BIN
      src/assets/PassionOne-Bold.ttf
  5. BIN
      src/assets/PassionOne-Regular.ttf
  6. BIN
      src/assets/SofiaSans-Italic-VariableFont_wght.ttf
  7. BIN
      src/assets/SofiaSans-VariableFont_wght.ttf
  8. BIN
      src/assets/SofiaSansExtraCondensed-Italic-VariableFont_wght.ttf
  9. BIN
      src/assets/SofiaSansExtraCondensed-VariableFont_wght.ttf
  10. BIN
      src/assets/icons8-coin-wallet-30.png
  11. BIN
      src/assets/icons8-expensive-24.png
  12. BIN
      src/assets/icons8-goal-48.png
  13. BIN
      src/assets/icons8-menu-96.png
  14. BIN
      src/assets/icons8-wallet-24.png
  15. BIN
      src/assets/static/SofiaSans-Black.ttf
  16. BIN
      src/assets/static/SofiaSans-BlackItalic.ttf
  17. BIN
      src/assets/static/SofiaSans-Bold.ttf
  18. BIN
      src/assets/static/SofiaSans-BoldItalic.ttf
  19. BIN
      src/assets/static/SofiaSans-ExtraBold.ttf
  20. BIN
      src/assets/static/SofiaSans-ExtraBoldItalic.ttf
  21. BIN
      src/assets/static/SofiaSans-ExtraLight.ttf
  22. BIN
      src/assets/static/SofiaSans-ExtraLightItalic.ttf
  23. BIN
      src/assets/static/SofiaSans-Italic.ttf
  24. BIN
      src/assets/static/SofiaSans-Light.ttf
  25. BIN
      src/assets/static/SofiaSans-LightItalic.ttf
  26. BIN
      src/assets/static/SofiaSans-Medium.ttf
  27. BIN
      src/assets/static/SofiaSans-MediumItalic.ttf
  28. BIN
      src/assets/static/SofiaSans-Regular.ttf
  29. BIN
      src/assets/static/SofiaSans-SemiBold.ttf
  30. BIN
      src/assets/static/SofiaSans-SemiBoldItalic.ttf
  31. BIN
      src/assets/static/SofiaSans-Thin.ttf
  32. BIN
      src/assets/static/SofiaSans-ThinItalic.ttf
  33. BIN
      src/assets/static/SofiaSansExtraCondensed-Black.ttf
  34. BIN
      src/assets/static/SofiaSansExtraCondensed-BlackItalic.ttf
  35. BIN
      src/assets/static/SofiaSansExtraCondensed-Bold.ttf
  36. BIN
      src/assets/static/SofiaSansExtraCondensed-BoldItalic.ttf
  37. BIN
      src/assets/static/SofiaSansExtraCondensed-ExtraBold.ttf
  38. BIN
      src/assets/static/SofiaSansExtraCondensed-ExtraBoldItalic.ttf
  39. BIN
      src/assets/static/SofiaSansExtraCondensed-ExtraLight.ttf
  40. BIN
      src/assets/static/SofiaSansExtraCondensed-ExtraLightItalic.ttf
  41. BIN
      src/assets/static/SofiaSansExtraCondensed-Italic.ttf
  42. BIN
      src/assets/static/SofiaSansExtraCondensed-Light.ttf
  43. BIN
      src/assets/static/SofiaSansExtraCondensed-LightItalic.ttf
  44. BIN
      src/assets/static/SofiaSansExtraCondensed-Medium.ttf
  45. BIN
      src/assets/static/SofiaSansExtraCondensed-MediumItalic.ttf
  46. BIN
      src/assets/static/SofiaSansExtraCondensed-Regular.ttf
  47. BIN
      src/assets/static/SofiaSansExtraCondensed-SemiBold.ttf
  48. BIN
      src/assets/static/SofiaSansExtraCondensed-SemiBoldItalic.ttf
  49. BIN
      src/assets/static/SofiaSansExtraCondensed-Thin.ttf
  50. BIN
      src/assets/static/SofiaSansExtraCondensed-ThinItalic.ttf
  51. +9
    -0
      src/assets/styles/general.styl
  52. +17
    -14
      src/components/EditQueue.vue
  53. +3
    -3
      src/components/ErrorDisplay.vue
  54. +59
    -34
      src/components/FundLink.vue
  55. +45
    -34
      src/components/FundTierInput.vue
  56. +17
    -9
      src/components/HelloWorld.vue
  57. +9
    -9
      src/views/AddFundView.vue
  58. +16
    -7
      src/views/AdminView.vue
  59. +11
    -0
      src/views/EditFundView.vue
  60. +14
    -0
      src/views/EditQueueView.vue
  61. +126
    -121
      src/views/FundView.vue
  62. +10
    -7
      src/views/HomeView.vue
  63. +5
    -5
      src/views/LoginView.vue
  64. +5
    -5
      src/views/RegisterView.vue
  65. +9
    -9
      yarn.lock

+ 2
- 2
package.json View File

@@ -9,9 +9,9 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@mdi/js": "^7.0.96",
"@jamescoyle/vue-icon": "^0.1.2",
"@mdi/js": "^7.1.96",
"@vueuse/core": "^9.5.0",
"bulma": "^0.9.4",
"core-js": "^3.8.3",
"jenesius-vue-modal": "^1.8.2",
"jwt-decode": "^3.1.2",


+ 93
- 64
src/App.vue View File

@@ -1,34 +1,14 @@
<template>
<nav class="navbar has-background-grey-dark" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<RouterLink to="/" class="navbar-item">
<span class="signet-logo title is-3-desktop is-4-mobile">
<nav role="navigation" aria-label="main navigation">
<div class="signet-logo">
<RouterLink to="/">
<span>
<template v-for="(element, i) in logoElements" v-bind:key="i">
<span :style="`color: #${element.color}`">{{ element.letter }}</span>
<span :style="`color: ${element.color}`">{{ element.letter }}</span>
</template>
</span>
</RouterLink>
</div>

<div class="navbar-end">
<div class="navbar-item">
<div class="buttons is-hidden-mobile is-hidden-tablet-only">
<div class="authentication" v-if="!hasToken">
<RouterLink to="/login" class="button is-primary">
Log in
</RouterLink>
</div>
<div v-else>
<RouterLink to="/addfund" class="button is-primary">
Add Fund
</RouterLink>
<RouterLink to="/register" class="button is-white">
Register
</RouterLink>
</div>
</div>
</div>
</div>
</nav>

<div id="content">
@@ -37,9 +17,11 @@
<Component :is="Component"/>

<template #fallback>
<div class="is-flex is-flex-direction-row is-justify-content-center"
style="height: 90vh">
<span style="font-size: 1.25em; color: greenyellow; margin: auto 0">Loading...</span>
<div
style="height: 90vh">
<span style="font-size: 1.25em; color: greenyellow; margin: auto 0">
Loading...
</span>
</div>
</template>
</Suspense>
@@ -49,7 +31,7 @@
<footer>
<div>
Proudly made in Michigan
<div class="michigan-icon"></div>
<div></div>
</div>
</footer>
</template>
@@ -83,42 +65,65 @@ interface LogoElement {
color: string;
}

const logoElements: LogoElement[] = [
{
color: '9fe82c',
letter: 'B',
},
{
color: '8ee045',
letter: 'e',
},
{
color: '7dd95c',
letter: 'i',
},
{
color: '6dd373',
letter: 'g',
},
{
color: '5dcb8a',
letter: 'n',
},
{
color: '4cc4a2',
letter: 'e',
},
{
color: '3dbeb8',
letter: 't',
},
];
const gradientize = (text: string, start: string, end: string): LogoElement[] => {
const extractChannels = (hex: string): { 'r': number, 'g': number, 'b': number } => {
const h = ref(hex);
if (h.value.startsWith('#')) {
h.value = hex.slice(1);
} else {
h.value = hex;
}
const [r, g, b] = [
parseInt(h.value.slice(0, 2), 16),
parseInt(h.value.slice(2, 4), 16),
parseInt(h.value.slice(4, 6), 16),
];

return {
r,
g,
b,
};
};
const composeHex = (r: number, g: number, b: number) => {
const padIfNeeded = (hex: string) => (hex.length === 1 ? `0${hex}` : hex);
const [rHex, gHex, bHex] = [
`${padIfNeeded(r.toString(16))}`,
`${padIfNeeded(g.toString(16))}`,
`${padIfNeeded(b.toString(16))}`,
];
return `#${rHex}${gHex}${bHex}`;
};
const logoElements = ref([] as LogoElement[]);
const startChannels = extractChannels(start);
const endChannels = extractChannels(end);
const differences = {
r: endChannels.r - startChannels.r,
g: endChannels.g - startChannels.g,
b: endChannels.b - startChannels.b,
};

const [r, g, b] = [ref(startChannels.r), ref(startChannels.g), ref(startChannels.b)];
for (let i = 0; i < text.length; i += 1) {
r.value += differences.r / text.length;
g.value += differences.g / text.length;
b.value += differences.b / text.length;
logoElements.value.push({
color: composeHex(Math.round(r.value), Math.round(g.value), Math.round(b.value)),
letter: text[i],
});
}
return logoElements.value;
};

const logoElements: LogoElement[] = gradientize('Beignet', '#f23525', '#e99406');
</script>

<style lang="stylus">
@import "../node_modules/bulma/css/bulma.min.css"
@import "assets/styles/general.styl"

#content
margin-top 1.5em
min-height 80vh

#app
@@ -132,8 +137,8 @@ html, body

body
min-height 100vh
color #e8dbca
background-color #313538
color text-color
background-color bg-color

footer
color #707070
@@ -144,9 +149,18 @@ footer
vertical-align middle
text-align center

nav
background-color bg-color
padding 0.15em 0.7em
filter signet-shadow

a
text-decoration none

.signet-logo
font-family Paytone
letter-spacing 1px
font-size 3em

.michigan-icon
display inline-block
@@ -158,10 +172,25 @@ footer
background-size 28px
margin-left 4px

.navbar-burger > *
background-color #fff !important
.layout-section
margin 0 auto
width 61.8034%

@media screen and (max-width: 1080px)
width 82%

@media screen and (max-width: 860px)
width 96%

@font-face
font-family Paytone
src url("./assets/PaytoneOne-Regular.ttf")

@font-face
font-family "Passion One"
src url("./assets/PassionOne-Regular.ttf")

@font-face
font-family "Passion One Bold"
src url("./assets/PassionOne-Bold.ttf")
</style>

BIN
src/assets/PassionOne-Black.ttf View File


BIN
src/assets/PassionOne-Bold.ttf View File


BIN
src/assets/PassionOne-Regular.ttf View File


BIN
src/assets/SofiaSans-Italic-VariableFont_wght.ttf View File


BIN
src/assets/SofiaSans-VariableFont_wght.ttf View File


BIN
src/assets/SofiaSansExtraCondensed-Italic-VariableFont_wght.ttf View File


BIN
src/assets/SofiaSansExtraCondensed-VariableFont_wght.ttf View File


BIN
src/assets/icons8-coin-wallet-30.png View File

Before After
Width: 24  |  Height: 24  |  Size: 283 B

BIN
src/assets/icons8-expensive-24.png View File

Before After
Width: 24  |  Height: 24  |  Size: 863 B

BIN
src/assets/icons8-goal-48.png View File

Before After
Width: 48  |  Height: 48  |  Size: 1.2 KiB

BIN
src/assets/icons8-menu-96.png View File

Before After
Width: 96  |  Height: 96  |  Size: 203 B

BIN
src/assets/icons8-wallet-24.png View File

Before After
Width: 24  |  Height: 24  |  Size: 275 B

BIN
src/assets/static/SofiaSans-Black.ttf View File


BIN
src/assets/static/SofiaSans-BlackItalic.ttf View File


BIN
src/assets/static/SofiaSans-Bold.ttf View File


BIN
src/assets/static/SofiaSans-BoldItalic.ttf View File


BIN
src/assets/static/SofiaSans-ExtraBold.ttf View File


BIN
src/assets/static/SofiaSans-ExtraBoldItalic.ttf View File


BIN
src/assets/static/SofiaSans-ExtraLight.ttf View File


BIN
src/assets/static/SofiaSans-ExtraLightItalic.ttf View File


BIN
src/assets/static/SofiaSans-Italic.ttf View File


BIN
src/assets/static/SofiaSans-Light.ttf View File


BIN
src/assets/static/SofiaSans-LightItalic.ttf View File


BIN
src/assets/static/SofiaSans-Medium.ttf View File


BIN
src/assets/static/SofiaSans-MediumItalic.ttf View File


BIN
src/assets/static/SofiaSans-Regular.ttf View File


BIN
src/assets/static/SofiaSans-SemiBold.ttf View File


BIN
src/assets/static/SofiaSans-SemiBoldItalic.ttf View File


BIN
src/assets/static/SofiaSans-Thin.ttf View File


BIN
src/assets/static/SofiaSans-ThinItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Black.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-BlackItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Bold.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-BoldItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-ExtraBold.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-ExtraBoldItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-ExtraLight.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-ExtraLightItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Italic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Light.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-LightItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Medium.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-MediumItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Regular.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-SemiBold.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-SemiBoldItalic.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-Thin.ttf View File


BIN
src/assets/static/SofiaSansExtraCondensed-ThinItalic.ttf View File


+ 9
- 0
src/assets/styles/general.styl View File

@@ -0,0 +1,9 @@
text-color = #383838
bg-color = #fffbfa
primary = #f23525
secondary = #e99406

signet-shadow = drop-shadow(0 0 3px #222222)

.heading
font-size 2em

+ 17
- 14
src/components/EditQueue.vue View File

@@ -1,5 +1,5 @@
<template>
<div class="is-flex is-flex-direction-row is-justify-content-space-between">
<div>
<div class="select mr-1">
<select
ref="queueOptions"
@@ -25,13 +25,13 @@
>
</div>
<div v-else-if="queueSelection >= 0" class="is-flex-grow-1 ml-1">
<Draggable :list="queueMembers" tag="div" class="edit-queue-list" @change="reorder">
<Draggable :list="queueMembers" tag="div" @change="reorder">
<div
class="p-2 has-background-grey-dark edit-queue-list-item"
v-for="element in queueMembers"
:key="element.order"
>
<div class="is-flex is-flex-direction-row is-justify-content-space-between">
<div>
<div>{{ element.title }} ({{ element.asset }})</div>
<div>{{ element.order }}</div>
</div>
@@ -65,7 +65,7 @@ interface QueueMember {
}

// eslint-disable-next-line no-undef
const props = defineProps<{ newMember: RewardFund & { order: number; } }>();
const props = defineProps<{ newMember: RewardFund & { order: number; } | undefined }>();

// eslint-disable-next-line no-undef
const emits = defineEmits(['selected', 'created']);
@@ -111,17 +111,20 @@ const populateQueueMembers = async (id: number) => {
asset: m.asset,
order: m.order,
}));
serverQueues.value = queueMembers.value.length;

if (queueMembers.value && props.newMember.title && props.newMember.asset) {
const newMember = {
id: undefined,
title: props.newMember.title,
asset: props.newMember.asset,
order: queueMembers.value.length + 1,
};
if (props.newMember) {
serverQueues.value = queueMembers.value.length;

if (queueMembers.value && props.newMember.title && props.newMember.asset) {
const newMember = {
id: undefined,
title: props.newMember.title,
asset: props.newMember.asset,
order: queueMembers.value.length + 1,
};

queueMembers.value.push(newMember);
queueMembers.value.push(newMember);
}
}
};

@@ -134,7 +137,7 @@ watch(queueSelection, async (newValue) => {
const addedMember = computed(() => props.newMember);

watch(addedMember, (newVal) => {
if (newVal.title && newVal.asset) {
if (newVal && newVal.title && newVal.asset) {
const assembleNewMember = (order: number) => ({
id: undefined,
title: newVal.title,


+ 3
- 3
src/components/ErrorDisplay.vue View File

@@ -1,9 +1,9 @@
<template>
<article class="message is-danger">
<div class="message-header">
<article>
<div>
<p>Errors</p>
</div>
<div class="message-body">
<div>
<ol class="ml-2">
<template v-for="(err, i) in props.errors" v-bind:key="i">
<li v-show="err.condition">


+ 59
- 34
src/components/FundLink.vue View File

@@ -1,25 +1,24 @@
<template>
<div class="card py-2 px-4 has-text-dark"
:style="generateBackgroundStyle(`${fund.asset} ${fund.title}`)">
<div class="is-size-2-desktop is-size-2-tablet is-size-3-mobile">
<div class="fund-link">
<div class="fund-name">
{{ fund.asset }}
</div>
<div>
<ul class="is-flex is-flex-direction-row is-justify-content-space-between">
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base coin"></span>
<ul class="fund-details">
<li>
<svg-icon type="mdi" height="18" width="18" :path="mdiCircleMultipleOutline"/>
<span class="fund-label">{{ props.fund.minContribution.toLocaleString() }}</span>
</li>
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base goal"></span>
<li>
<svg-icon type="mdi" height="18" width="18" :path="mdiBullseyeArrow"/>
<span class="fund-label">{{ props.fund.amountAvailable.toLocaleString() }}</span>
</li>
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base memo"></span>
<li>
<svg-icon type="mdi" height="18" width="18" :path="mdiNoteTextOutline"/>
<span class="fund-label">{{ props.fund.memo }}</span>
</li>
<li class="is-size-7 is-inline-block px-2">
<span class="stellar-icon-base wallet"></span>
<li>
<svg-icon type="mdi" height="18" width="18" :path="mdiWalletOutline"/>
<span class="fund-label">
{{ truncateWallet(props.fund.fundWallet, 5, undefined) }}
</span>
@@ -30,43 +29,69 @@
</template>
<script setup lang="ts">
import { truncateWallet } from '@/lib/helpers';
import {
FundInfo,
} from '@/api/types';
import { FundInfo } from '@/api/types';
import { PropType } from 'vue';
import SvgIcon from '@jamescoyle/vue-icon';
import {
mdiBullseyeArrow,
mdiCircleMultipleOutline,
mdiNoteTextOutline,
mdiWalletOutline,
} from '@mdi/js';

// eslint-disable-next-line no-undef
const props = defineProps({ fund: Object as PropType<FundInfo> });

const generateHue = (seed: string) => seed.split('').map((c) => c.charCodeAt(0)).reduce((v1, v2) => v1 + v2) % 256;
const generateHue = (seed: string) => seed.split('')
.map((c) => c.charCodeAt(0))
.reduce((v1, v2) => v1 + v2) % 256;

const generateBackgroundStyle = (hueSeed: string) => {
const hue = generateHue(hueSeed);
return `background-color: hsl(${hue}deg, 54%, 76%)`;
return `background-color: hsl(${hue}deg, 32%, 47%)`;
};
</script>
<style scoped lang="stylus">
@import "../assets/styles/general.styl"

.fund-link
background-color bg-color
border-radius 8px
overflow hidden
filter signet-shadow

.fund-name
font-size 3em
margin 0.4em
color text-color
font-family "Passion One Bold"
font-weight 900

.fund-label
color text-color
vertical-align top
margin-left 6px

.stellar-icon-base
display inline-block
height 20px
width 20px
margin-right 4px
background-position center
background-size 16px
background-repeat no-repeat

&.coin
background-image url("../assets/icons8-expensive-24.png")
.fund-details
background-color secondary
display flex
flex-direction row
justify-content space-between
list-style none
padding 4px 10px 2px 10px
margin 0
vertical-align middle

&.goal
background-image url("../assets/icons8-goal-48.png")
svg
color text-color

&.memo
background-image url("../assets/icons8-note-24.png")
@media screen and (max-width: 780px)
.fund-label
display inline-block
font-size 12px
vertical-align text-top

&.wallet
background-image url("../assets/icons8-wallet-24.png")
@media screen and (max-width: 300px)
.fund-label
font-size 10px
</style>

+ 45
- 34
src/components/FundTierInput.vue View File

@@ -1,36 +1,36 @@
<template>
<div>
<table class="table is-fullwidth">
<table>
<thead>
<tr>
<th>Goal Amount</th>
<th>Percent Bonus</th>
</tr>
<tr>
<th>Goal Amount</th>
<th>Percent Bonus</th>
</tr>
</thead>
<tbody>
<tr v-for="kv in bonuses" v-bind:key="kv.id">
<td class="p-0">
<input
type="text"
class="input is-small"
v-model="kv.goal"
:aria-label="`Goal #${bonuses.length}`"
@input="checkInputs"
@blur="saveValues"
>
</td>
<td class="p-0">
<input
type="text"
class="input is-small"
:class="kv.percent < 1 ? 'is-danger' : ''"
v-model="kv.percent"
:aria-label="`Cashback percent #${bonuses.length}`"
@input="checkInputs"
@blur="saveValues"
>
</td>
</tr>
<tr v-for="kv in bonuses" v-bind:key="kv.id">
<td class="p-0">
<input
type="text"
v-model="kv.goal"
:aria-label="`Goal #${bonuses.length}`"
@input="checkInputs"
@blur="saveValues"
>
</td>
<td class="p-0">
<input
type="text"
:class="kv.percent < 1 ? 'is-danger' : ''"
v-model="kv.percent"
:aria-label="`Cashback percent #${bonuses.length}`"
@input="checkInputs"
@blur="saveValues"
>
</td>
</tr>
</tbody>
</table>
</div>
@@ -48,22 +48,33 @@ interface Bonus {
// eslint-disable-next-line no-undef
const emits = defineEmits(['save']);

const bonuses = ref([{ id: 1, goal: undefined, percent: undefined }] as Bonus[]);
const bonuses = ref([{
id: 1,
goal: undefined,
percent: undefined,
}] as Bonus[]);

const getNextId = () => bonuses.value.length + 1;

const checkInputs = () => {
if (bonuses.value.every((b) => Object.values(b).every((v) => !!v))) {
if (bonuses.value.every((b) => Object.values(b)
.every((v) => !!v))) {
bonuses.value.push({
id: getNextId(), goal: undefined, percent: undefined,
id: getNextId(),
goal: undefined,
percent: undefined,
});
}
};

const saveValues = () => {
emits('save', bonuses.value.filter((b) => !!b.goal && !!b.percent).map((b) => (
{ goal: parseFloat(b.goal as string), percent: parseFloat(b.percent as string) }
)));
emits('save', bonuses.value.filter((b) => !!b.goal && !!b.percent)
.map((b) => (
{
goal: parseFloat(b.goal as string),
percent: parseFloat(b.percent as string),
}
)));
};
</script>



+ 17
- 9
src/components/HelloWorld.vue View File

@@ -1,5 +1,5 @@
<template>
<div class="hello">
<div>
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
@@ -8,12 +8,18 @@
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-mocha" target="_blank" rel="noopener">unit-mocha</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-mocha"
target="_blank" rel="noopener">unit-mocha</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript"
target="_blank" rel="noopener">typescript</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
@@ -27,9 +33,11 @@
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank"
rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank"
rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>


+ 9
- 9
src/views/AddFundView.vue View File

@@ -1,31 +1,31 @@
<template>
<div class="container is-max-desktop">
<section class="section is-small">
<div>
<section>
<div class="title is-4 has-text-white-ter has-text-centered">Add Fund</div>
<section class="section px-0 py-4">
<div class="title is-5 has-text-white-ter">Post</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
<input type="text"
placeholder="Title" aria-label="Title" v-model="title">
</div>
<div class="control my-2">
<textarea class="textarea is-normal has-background-white has-text-black"
placeholder="Description" aria-label="Description" v-model="description">
<textarea
placeholder="Description" aria-label="Description" v-model="description">
</textarea>
</div>
</section>
<section class="section px-0 py-4">
<div class="title is-5 has-text-white-ter">Wallet</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
<input type="text"
placeholder="Fund Wallet" aria-label="Fund Wallet" v-model="fundWallet">
</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
<input type="text"
placeholder="Selling Wallet" aria-label="Selling Wallet" v-model="sellWallet">
</div>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
<input type="text"
placeholder="Issuer Wallet" aria-label="Issuer Wallet" v-model="issuerWallet">
</div>
</section>
@@ -56,7 +56,7 @@
</section>
<div class="buttons is-flex is-justify-content-end mt-5">
<button
class="button is-success"
:class="requesting ? 'is-loading' : ''"
@click="submit"
>Submit


+ 16
- 7
src/views/AdminView.vue View File

@@ -1,8 +1,8 @@
<template>
<!-- Unused -->
<div class="is-flex is-flex-direction-row">
<nav class="is-hidden-tablet-only is-hidden-mobile has-background-white-ter">
<div class="has-background-primary">
<div>
<nav>
<div>
<span class="has-text-white has-text-weight-bold my-4 mx-2">Administration</span>
</div>
<ul class="p-2">
@@ -11,7 +11,7 @@
</li>
</ul>
</nav>
<div class="container is-max-desktop">
<div>
<RouterView></RouterView>
</div>
</div>
@@ -19,9 +19,18 @@

<script setup lang="ts">
const links = [
{ text: 'Add Fund', to: '/admin/addfund' },
{ text: 'Modify Fund', to: '' },
{ text: 'Create Tag', to: '' },
{
text: 'Add Fund',
to: '/admin/addfund',
},
{
text: 'Modify Fund',
to: '',
},
{
text: 'Create Tag',
to: '',
},
];
</script>



+ 11
- 0
src/views/EditFundView.vue View File

@@ -0,0 +1,11 @@
<template>

</template>

<script setup lang="ts">

</script>

<style scoped lang="stylus">

</style>

+ 14
- 0
src/views/EditQueueView.vue View File

@@ -0,0 +1,14 @@
<template>
<EditQueue :new-member="member"/>
</template>

<script setup lang="ts">
import EditQueue from '@/components/EditQueue.vue';

const member = null;

</script>

<style scoped lang="stylus">

</style>

+ 126
- 121
src/views/FundView.vue View File

@@ -1,48 +1,43 @@
<template>
<div class="container is-max-desktop pb-4">
<section class="section is-small">
<div class="title is-size-4 has-text-white-ter has-text-centered">
<div>
<section class="layout-section">
<div class="heading">
{{ fund.fundInfo.title }}
</div>
<div
class="is-block-mobile
is-flex-tablet-only
is-flex-desktop
is-flex-direction-row
is-justify-content-space-between">
<div class="fund-description pr-5" v-html="fixNewlines(fund.fundInfo.description)">
</div>
<div
class="fund-details is-flex is-flex-direction-row is-justify-content-end my-auto py-6">
<ul>
<li v-for="(detail, i) in fundDetails" v-bind:key="i">
<span class="has-text-weight-bold is-size-6 mr-2">{{ detail.title }}</span>
<span class="is-size-6">{{ detail.val }}</span>
<div>
<p v-html="fixNewlines(fund.fundInfo.description)"></p>
<div>
<ul class="fund-details">
<li v-for="(detail, i) in fundDetails" :key="i" class="fund-detail">
<div class="detail-icon">
<svg-icon type="mdi" height="22" width="22" :path="detail.icon"/>
</div>
<div class="detail-text">
{{ detail.val }}
</div>
</li>
</ul>
</div>
</div>
</section>
<section>
<div class="box">
<div class="title is-size-4 has-text-grey-dark has-text-centered">
<div>
<div class="heading">
Tracker
</div>
<div class="level" v-if="fund.fundInfo.bonuses.length > 0">
<div class="level-item has-text-centered"
v-for="bonus in fund.fundInfo.bonuses.sort((v1, v2) => v1.goal - v2.goal)"
v-bind:key="bonus.goal"
<div v-if="fund.fundInfo.bonuses.length > 0">
<div
v-for="bonus in fund.fundInfo.bonuses.sort((v1, v2) => v1.goal - v2.goal)"
v-bind:key="bonus.goal"
>
<div>
<p
class="heading"
:class="amountHeld >= bonus.goal
? 'has-text-success' : 'has-text-grey-dark'"
>
{{ bonus.goal.toLocaleString() }} XLM
</p>
<p
class="title"
:class="amountHeld >= bonus.goal
? 'has-text-success' : 'has-text-grey-dark'"
>
@@ -52,15 +47,8 @@
</div>
</div>
</div>
<div
class="is-flex
is-flex-direction-row
is-justify-content-space-around
is-size-4
has-text-white
mb-3"
>
<div class="total">
<div>
<div>
<span class="total-label is-size-3 pr-2 has-text-weight-light">
Raised
</span>
@@ -68,7 +56,7 @@
{{ amountHeld.toLocaleString() }} XLM
</span>
</div>
<div class="remaining">
<div>
<span class="remaining-label is-size-3 pr-2 has-text-weight-light">
Remaining
</span>
@@ -77,19 +65,17 @@
</span>
</div>
</div>
</section>
<section class="section is-small">
<div class="title is-size-4 has-text-white-ter has-text-centered">
Contribute
</div>
<ErrorDisplay :errors="errs" v-if="invalidContributionForm"/>
<div class="control my-2">
<input class="input is-normal has-background-white has-text-black" type="text"
<input type="text"
placeholder="Private Key" aria-label="Wallet" v-model="pk" @blur="queryAccount">
</div>
<div class="control my-2" :class="loading.balance ? 'is-loading' : null">
<input
class="input is-normal has-background-white has-text-black"
type="number"
placeholder="Amount"
aria-label="Amount"
@@ -98,90 +84,89 @@
:disabled="loading.balance"
>
</div>
<div class="is-flex is-justify-content-end">
<div>
<button
class="button is-primary"
:class="loading.contribution ? 'is-loading' : ''"
:disabled="invalidContributionForm"
@click="makeContribution"
>Submit
</button>
</div>
</section>
<section class="section is-small" v-if="contributions.length > 0">
<div class="title is-size-4 has-text-white-ter has-text-centered">
Contributions
</div>
<div class="is-flex is-justify-content-space-between is-rounded my-2">
<div class="select">
<select v-model="selectedDate" aria-label="Filter by date">
<option v-for="date in selectableDates" v-bind:key="date" :value="date">
{{ date ?? 'Cutoff Date' }}
</option>
</select>
<section v-if="contributions.length > 0">
<div class="title is-size-4 has-text-white-ter has-text-centered">
Contributions
</div>
<div class="consolidate-option has-background-white px-4 py-1 my-auto">
<label for="consolidate" class="checkbox has-text-dark is-size-6">
<span class="consolidate-label is-inline-block">
<div class="is-flex is-justify-content-space-between is-rounded my-2">
<div>
<select v-model="selectedDate" aria-label="Filter by date">
<option v-for="date in selectableDates" v-bind:key="date" :value="date">
{{ date ?? 'Cutoff Date' }}
</option>
</select>
</div>
<div class="consolidate-option has-background-white px-4 py-1 my-auto">
<label for="consolidate" class="checkbox has-text-dark is-size-6">
<span>
Consolidate wallets
</span>
<input
type="checkbox"
class="ml-2"
id="consolidate"
aria-label="Consolidate wallets"
v-model="enableConsolidation"
>
</label>
<input
type="checkbox"
class="ml-2"
id="consolidate"
aria-label="Consolidate wallets"
v-model="enableConsolidation"
>
</label>
</div>
</div>
</div>
<div id="contribution-container" @scroll="loadMoreIfNeeded">
<table class="contribution-table table is-fullwidth">
<thead>
<tr>
<th>Wallet</th>
<th>Amount</th>
<th v-if="!enableConsolidation">Time</th>
<th v-else>Tokens</th>
</tr>
</thead>
<tbody>
<tr v-for="(contribution, i) in contributions" v-bind:key="i">
<td>{{ truncateWallet(contribution.wallet, 6, undefined) }}</td>
<td>{{ contribution.amount }}</td>
<td v-if="!enableConsolidation">
<span class="transaction-date" :title="formatDate(contribution.createdAt, true)">
<div id="contribution-container" @scroll="loadMoreIfNeeded">
<table>
<thead>
<tr>
<th>Wallet</th>
<th>Amount</th>
<th v-if="!enableConsolidation">Time</th>
<th v-else>Tokens</th>
</tr>
</thead>
<tbody>
<tr v-for="(contribution, i) in contributions" v-bind:key="i">
<td>{{ truncateWallet(contribution.wallet, 6, undefined) }}</td>
<td>{{ contribution.amount }}</td>
<td v-if="!enableConsolidation">
<span :title="formatDate(contribution.createdAt, true)">
{{ formatDate(contribution.createdAt, true) }}
</span>
</td>
<td v-else>
<span>{{ calculateReward(contribution.amount / fund.fundInfo.price) }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<section v-if="store.getters.getToken && hasPermission(Privileges.AdminPlus)">
<div class="title is-size-4 has-text-white-ter has-text-centered">
Close Group Fund
</div>
<div class="box is-flex is-flex-direction-row is-justify-content-space-between">
<div class="my-auto">
<label class="checkbox" for="delete-confirm">
<input type="checkbox" id="delete-confirm" v-model="allowDelete"> Close
</label>
</td>
<td v-else>
<span>{{ calculateReward(contribution.amount / fund.fundInfo.price) }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<section v-if="store.getters.getToken && hasPermission(Privileges.AdminPlus)">
<div class="title is-size-4 has-text-white-ter has-text-centered">
Close Group Fund
</div>
<div>
<button
class="button is-danger"
:disabled="!allowDelete"
@click="deleteFund"
>
Close
</button>
<div>
<label for="delete-confirm">
<input type="checkbox" id="delete-confirm" v-model="allowDelete"> Close
</label>
</div>
<div>
<button

:disabled="!allowDelete"
@click="deleteFund"
>
Close
</button>
</div>
</div>
</div>
</section>
</section>
</div>
</template>
@@ -220,6 +205,13 @@ import {
getContributions,
getRewardFund,
} from '@/api/composed';
import SvgIcon from '@jamescoyle/vue-icon';
import {
mdiCircleMultipleOutline,
mdiGreaterThanOrEqual,
mdiNoteTextOutline,
mdiTarget,
} from '@mdi/js';

const route = useRoute();
const router = useRouter();
@@ -260,7 +252,7 @@ const fund = ref(
} as GetRewardFundResponse | null,
);
const fundDetails = ref([{
title: '',
icon: '',
val: '',
}]);

@@ -271,19 +263,19 @@ if (!fund.value) {
}
fundDetails.value = [
{
title: 'Asset',
icon: mdiCircleMultipleOutline,
val: fund.value.fundInfo.asset,
},
{
title: 'Min',
icon: mdiGreaterThanOrEqual,
val: `${fund.value.fundInfo.minContribution.toLocaleString()}`,
},
{
title: 'Goal',
icon: mdiTarget,
val: `${fund.value.fundInfo.amountAvailable.toLocaleString()}`,
},
{
title: 'Memo',
icon: mdiNoteTextOutline,
val: `"${fund.value.fundInfo.memo}"`,
},
];
@@ -528,14 +520,27 @@ watch(data, (newVal) => {
min-height 280px

.fund-details
width 182px
display flex
flex-direction row
justify-content space-around
background-color darkorange
border-radius 4px
list-style-type none
margin 0
padding 8px 4px

.detail-icon
display flex
justify-content center
color #fff
margin-bottom 8px

.detail-text
font-size 16px
text-align center
color #fff
font-family "Passion One"

#consolidate
vertical-align middle

@media screen and (min-width: 1024px)
.fund-details
max-width 14vw
border-left 1px #777 solid
padding-left 10px
</style>

+ 10
- 7
src/views/HomeView.vue View File

@@ -1,8 +1,8 @@
<template>
<div class="container is-max-desktop">
<section class="section is-small px-0">
<div>
<section class="layout-section">
<div class="container-grid" v-if="rewardFunds">
<template v-for="fund in rewardFunds" v-bind:key="fund.id">
<template v-for="fund in rewardFunds" :key="fund.id">
<RouterLink :to="`/fund/${fund.id}`">
<FundLink :fund="fund"/>
</RouterLink>
@@ -36,11 +36,14 @@ offset.value = total;
<style scoped lang="stylus">
.container-grid
display grid
grid-template-columns: repeat(2, 1fr);
gap: 10px;
grid-auto-rows: 120px;
grid-template-columns: repeat(2, 1fr)
gap: 10px
grid-auto-rows: 120px

@media screen and (max-width: 768px)
a
text-decoration none

@media screen and (max-width: 680px)
.container-grid
display flex
flex-direction column


+ 5
- 5
src/views/LoginView.vue View File

@@ -1,17 +1,17 @@
<template>
<div class="container is-max-desktop">
<section class="section is-large">
<div>
<section>
<div class="title is-4 has-text-white-ter has-text-centered">Login</div>
<div class="control my-2">
<input class="input is-medium" type="text" placeholder="Username"
<input type="text" placeholder="Username"
aria-label="Username" v-model="username" @keyup.enter="submit">
</div>
<div class="control my-2">
<input class="input is-medium" type="password" placeholder="Password"
<input type="password" placeholder="Password"
aria-label="Password" v-model="password" @keyup.enter="submit">
</div>
<div class="buttons is-flex is-justify-content-end mt-5">
<button class="button is-success" @click="submit">Submit</button>
<button @click="submit">Submit</button>
</div>
</section>
</div>


+ 5
- 5
src/views/RegisterView.vue View File

@@ -1,17 +1,17 @@
<template>
<div class="container is-max-desktop">
<section class="section is-large">
<div>
<section>
<div class="title is-4 has-text-white-ter has-text-centered">Register</div>
<div class="control my-2">
<input class="input is-medium" type="text" placeholder="Username"
<input type="text" placeholder="Username"
aria-label="Username" v-model="username">
</div>
<div class="control my-2">
<input class="input is-medium" type="password" placeholder="Password"
<input type="password" placeholder="Password"
aria-label="Password" v-model="password">
</div>
<div class="buttons is-flex is-justify-content-end mt-5">
<button class="button is-success" @click="submit">Submit</button>
<button @click="submit">Submit</button>
</div>
</section>
</div>


+ 9
- 9
yarn.lock View File

@@ -1002,6 +1002,11 @@
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==

"@jamescoyle/vue-icon@^0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz#b9e254187de6716b81bf9e0e8400ec012231bd05"
integrity sha512-KFrImXx5TKIi6iQXlnyLEBl4rNosNKbTeRnr70ucTdUaciVmd9qK9d/pZAaKt1Ob/8xNnX2GMp8LisyHdKtEgw==

"@jridgewell/gen-mapping@^0.1.0":
version "0.1.1"
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz"
@@ -1055,10 +1060,10 @@
resolved "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==

"@mdi/js@^7.0.96":
version "7.0.96"
resolved "https://registry.npmjs.org/@mdi/js/-/js-7.0.96.tgz"
integrity sha512-lNqhkV3cpPfYb/Avh+vXLFukUTbHbyHoFo4Jdc7Oc9UvURGVhamFIpgOVvEf2bNA78zvjXTZeVWExUTR+DLBfQ==
"@mdi/js@^7.1.96":
version "7.1.96"
resolved "https://registry.yarnpkg.com/@mdi/js/-/js-7.1.96.tgz#9c5a7f8a20ea63c03b09a0dba1768fe8b70eeaf9"
integrity sha512-wlrJs6Ryhaa5CqhK3FjTfMRnb/s7HeLkKMFqwQySkK86cdN1TGdzpSM3O4tsmzCA1dYBeTbXvOwSE/Y42cUrvA==

"@node-ipc/js-queue@2.0.3":
version "2.0.3"
@@ -2440,11 +2445,6 @@ buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"

bulma@^0.9.4:
version "0.9.4"
resolved "https://registry.npmjs.org/bulma/-/bulma-0.9.4.tgz"
integrity sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==

bytes@3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz"


Loading…
Cancel
Save