fix misc issues

This commit is contained in:
Jake Potrebic 2021-12-20 00:06:03 -08:00
parent f9fdece3d8
commit 841f90d417
No known key found for this signature in database
GPG Key ID: ECE0B3C133C016C5
11 changed files with 239 additions and 180 deletions

32
.editorconfig Normal file
View File

@ -0,0 +1,32 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
ij_any_block_comment_at_first_column = false
ij_any_line_comment_at_first_column = false
ij_any_block_comment_add_space = true
ij_typescript_use_double_quotes = false
ij_javascript_use_double_quotes = false
ij_sass_use_double_quotes = false
ij_html_quote_style = double
[**/locales/*.ts]
indent_size = 2
[*.java]
ij_java_insert_inner_class_imports = false
ij_java_use_fq_class_names = false
ij_java_class_count_to_use_import_on_demand = 99999
ij_java_names_count_to_use_import_on_demand = 99999
[*.yml]
indent_size = 2
[*.md]
trim_trailing_whitespace = false

View File

@ -10,6 +10,10 @@ import MarkdownEditor from '~/components/markdown/MarkdownEditor.vue';
export class HangarProjectMixin extends HangarComponent {
@Prop({ type: Object as PropType<HangarProject>, required: true })
project!: HangarProject;
get slug(): string {
return `/${this.project.namespace.owner}/${this.project.namespace.slug}`;
}
}
@Component

View File

@ -27,8 +27,9 @@
<v-row v-for="(arr, arrIndex) in swatches" :key="arrIndex" justify="center">
<v-col v-for="(color, n) in arr" :key="n" class="flex-grow-0 flex-shrink-1 pa-2 px-1">
<v-item v-slot="{ active, toggle }" :value="color">
<!-- !important is needed for color otherwise the bg color overrides it -->
<v-card
:color="color"
:color="`${color} !important`"
class="d-flex align-center"
:dark="$util.isDark(color)"
:light="$util.isLight(color)"

View File

@ -11,6 +11,7 @@
<v-form ref="modalForm" v-model="validForm">
<v-text-field
v-model.trim="form.name"
autofocus
filled
:loading="validateLoading"
:rules="[

View File

@ -3,7 +3,7 @@
<template #activator="{ on: dialogOn, attrs }">
<v-tooltip :disabled="!project.userActions.flagged" bottom>
<template #activator="{ on: tooltipOn }">
<div class="flag-modal-trigger" v-on="tooltipOn">
<div class="d-inline" v-on="tooltipOn">
<!-- wrap in div so tooltip shows up when the button is disabled -->
<v-btn v-bind="attrs" small color="warning" :disabled="project.userActions.flagged" :class="activatorClass" v-on="dialogOn">
<v-icon>mdi-flag</v-icon>

View File

@ -0,0 +1,156 @@
<template>
<v-card>
<v-card-title>
<v-col cols="auto">
{{ $t('project.info.title') }}
</v-col>
<v-col v-if="isLoggedIn && !$util.isCurrentUser(project.owner.id)" cols="auto">
<FlagModal :project="project" activator-class="ml-1" />
</v-col>
<v-col v-if="$perms.isStaff" cols="auto">
<v-menu bottom offset-y open-on-hover>
<template #activator="{ on, attrs }">
<v-btn v-bind="attrs" small class="ml-1" color="info" v-on="on">
{{ $t('project.actions.adminActions') }}
</v-btn>
</template>
<v-list>
<v-list-item :to="slug + '/flags'" nuxt>
<v-list-item-title>
{{ $t('project.actions.flagHistory', [project.info.flagCount]) }}
</v-list-item-title>
</v-list-item>
<v-list-item :to="slug + '/notes'" nuxt>
<v-list-item-title>
{{ $t('project.actions.staffNotes', [project.info.noteCount]) }}
</v-list-item-title>
</v-list-item>
<v-list-item :to="'/admin/log/?projectFilter=' + slug" nuxt>
<v-list-item-title>
{{ $t('project.actions.userActionLogs') }}
</v-list-item-title>
</v-list-item>
<v-list-item :href="$util.forumUrl(project.namespace.owner)">
<v-list-item-title>
{{ $t('project.actions.forum') }}
<v-icon>mdi-open-in-new</v-icon>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
<v-col cols="auto">
<DonationModal
v-if="project.settings.donation.enable"
:donation-email="project.settings.donation.email"
:default-amount="project.settings.donation.defaultAmount"
:one-time-amounts="project.settings.donation.oneTimeAmounts"
:monthly-amounts="project.settings.donation.monthlyAmounts"
:donation-target="project.namespace.owner + '/' + project.name"
:return-url="$nuxt.context.env.publicHost + '/' + project.namespace.owner + '/' + project.name + '?donation=success'"
:cancel-return-url="$nuxt.context.env.publicHost + '/' + project.namespace.owner + '/' + project.name + '?donation=failure'"
>
<template #activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">
<v-icon left> mdi-currency-usd</v-icon>
{{ $t('general.donate') }}
</v-btn>
</template>
</DonationModal>
</v-col>
<v-col cols="auto">
<v-btn v-if="!$util.isCurrentUser(project.owner.id)" @click="toggleStar">
<v-icon v-if="project.userActions.starred" left color="amber"> mdi-star</v-icon>
<v-icon v-else left> mdi-star-outline</v-icon>
<span v-if="project.userActions.starred">{{ $t('project.actions.unstar') }}</span>
<span v-else>{{ $t('project.actions.star') }}</span>
</v-btn>
</v-col>
<v-col cols="auto">
<v-btn v-if="!$util.isCurrentUser(project.owner.id)" @click="toggleWatch">
<v-icon v-if="project.userActions.watching" left> mdi-eye-off</v-icon>
<v-icon v-else left> mdi-eye</v-icon>
<span v-if="project.userActions.watching">{{ $t('project.actions.unwatch') }}</span>
<span v-else>{{ $t('project.actions.watch') }}</span>
</v-btn>
</v-col>
</v-card-title>
<v-divider class="mx-4 mt-n4" />
<v-card-text>
<div class="project-info">
<!-- TODO this should really be a table -->
<div class="float-left">
<p>{{ $t('project.category.info') }}</p>
<p>{{ $t('project.info.publishDate') }}</p>
<p>{{ $tc('project.info.views', project.stats.views) }}</p>
<p>{{ $tc('project.info.totalDownloads', project.stats.downloads) }}</p>
<NuxtLink :to="`${$route.params.slug}/stars`" nuxt small class="d-block">
{{ $tc('project.info.stars', project.stats.stars) }}
</NuxtLink>
<NuxtLink :to="`${$route.params.slug}/watchers`" nuxt small class="d-block">
{{ $tc('project.info.watchers', project.stats.watchers) }}
</NuxtLink>
<p v-if="project && project.settings.license && project.settings.license.name">
{{ $t('project.license.link') }}
</p>
</div>
<div class="float-right text-right">
<p>{{ $store.state.projectCategories.get(project.category).title }}</p>
<p>{{ $util.prettyDate(project.createdAt) }}</p>
<p>{{ project.stats.views }}</p>
<p>{{ project.stats.downloads }}</p>
<p>{{ project.stats.stars }}</p>
<p>{{ project.stats.watchers }}</p>
<p v-if="project && project.settings.license && project.settings.license.name">
<a ref="noopener" :href="project.settings.license.url" target="_blank">{{ project.settings.license.name }}</a>
</p>
</div>
<div style="clear: both" />
</div>
</v-card-text>
</v-card>
</template>
<script lang="ts">
import { Component } from 'nuxt-property-decorator';
import { UserActions } from 'hangar-api';
import { HangarProjectMixin } from '~/components/mixins';
import DonationModal from '~/components/donation/DonationModal.vue';
import FlagModal from '~/components/modals/projects/FlagModal.vue';
@Component({
components: {
FlagModal,
DonationModal,
},
})
export default class ProjectInfo extends HangarProjectMixin {
toggleStar() {
this.toggleState('starred', 'star');
}
toggleWatch() {
this.toggleState('watching', 'watch');
}
toggleState(stateType: keyof UserActions, route: string, i18nName: string = route) {
this.$api
.requestInternal(`projects/project/${this.project.id}/${route}/${!this.project.userActions[stateType]}`, true, 'post')
.then(() => {
this.project.userActions[stateType] = !this.project.userActions[stateType];
})
.catch((err) => this.$util.handleRequestError(err, `project.error.${i18nName}`));
}
}
</script>
<style lang="scss" scoped>
.project-info {
p {
margin-bottom: 3px;
}
}
</style>

View File

@ -69,7 +69,7 @@ export default class ProjectPageList extends HangarProjectMixin {
<style lang="scss" scoped>
.v-treeview {
overflow-x: scroll;
overflow-x: auto;
&::v-deep .v-treeview-node__label {
overflow: visible;

View File

@ -89,10 +89,6 @@ export default class ProjectTabs extends HangarProjectMixin {
}
return tabs;
}
get slug(): string {
return `/${this.project.namespace.owner}/${this.project.namespace.slug}`;
}
}
</script>

View File

@ -17,118 +17,7 @@
<v-col cols="12" md="4">
<v-row>
<v-col cols="12">
<v-card>
<v-card-title>
<v-col cols="auto">
{{ $t('project.info.title') }}
</v-col>
<v-col v-if="isLoggedIn && !$util.isCurrentUser(project.owner.id)" cols="auto">
<FlagModal :project="project" activator-class="ml-1" />
</v-col>
<v-col v-if="$perms.isStaff" cols="auto">
<v-menu bottom offset-y open-on-hover>
<template #activator="{ on, attrs }">
<v-btn v-bind="attrs" small class="ml-1" color="info" v-on="on">
{{ $t('project.actions.adminActions') }}
</v-btn>
</template>
<v-list>
<v-list-item :to="slug + '/flags'" nuxt>
<v-list-item-title>
{{ $t('project.actions.flagHistory', [project.info.flagCount]) }}
</v-list-item-title>
</v-list-item>
<v-list-item :to="slug + '/notes'" nuxt>
<v-list-item-title>
{{ $t('project.actions.staffNotes', [project.info.noteCount]) }}
</v-list-item-title>
</v-list-item>
<v-list-item :to="'/admin/log/?projectFilter=' + slug" nuxt>
<v-list-item-title>
{{ $t('project.actions.userActionLogs') }}
</v-list-item-title>
</v-list-item>
<v-list-item :href="$util.forumUrl(project.namespace.owner)">
<v-list-item-title>
{{ $t('project.actions.forum') }}
<v-icon>mdi-open-in-new</v-icon>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
<v-col cols="auto">
<DonationModal
v-if="project.settings.donation.enable"
:donation-email="project.settings.donation.email"
:default-amount="project.settings.donation.defaultAmount"
:one-time-amounts="project.settings.donation.oneTimeAmounts"
:monthly-amounts="project.settings.donation.monthlyAmounts"
:donation-target="project.namespace.owner + '/' + project.name"
:return-url="publicHost + '/' + project.namespace.owner + '/' + project.name + '?donation=success'"
:cancel-return-url="publicHost + '/' + project.namespace.owner + '/' + project.name + '?donation=failure'"
>
<template #activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">
<v-icon left> mdi-currency-usd</v-icon>
{{ $t('general.donate') }}
</v-btn>
</template>
</DonationModal></v-col
>
<v-col cols="auto">
<v-btn v-if="!$util.isCurrentUser(project.owner.id)" @click="toggleStar">
<v-icon v-if="project.userActions.starred" left color="amber"> mdi-star</v-icon>
<v-icon v-else lef> mdi-star-outline</v-icon>
<span v-if="project.userActions.starred">{{ $t('project.actions.unstar') }}</span>
<span v-else>{{ $t('project.actions.star') }}</span>
</v-btn>
</v-col>
<v-col cols="auto">
<v-btn v-if="!$util.isCurrentUser(project.owner.id)" @click="toggleWatch">
<v-icon v-if="project.userActions.watching" left> mdi-eye-off</v-icon>
<v-icon v-else left> mdi-eye</v-icon>
<span v-if="project.userActions.watching">{{ $t('project.actions.unwatch') }}</span>
<span v-else>{{ $t('project.actions.watch') }}</span>
</v-btn>
</v-col>
</v-card-title>
<v-card-text>
<v-divider class="mb-5" />
<div class="project-info">
<div class="float-left">
<p>{{ $t('project.category.info') }}</p>
<p>{{ $t('project.info.publishDate') }}</p>
<p>{{ $tc('project.info.views', project.stats.views) }}</p>
<p>{{ $tc('project.info.totalDownloads', project.stats.downloads) }}</p>
<NuxtLink :to="`${$route.params.slug}/stars`" nuxt small class="d-block">
{{ $tc('project.info.stars', project.stats.stars) }}
</NuxtLink>
<NuxtLink :to="`${$route.params.slug}/watchers`" nuxt small class="d-block">
{{ $tc('project.info.watchers', project.stats.watchers) }}
</NuxtLink>
<p v-if="project && project.settings.license && project.settings.license.name">
{{ $t('project.license.link') }}
</p>
</div>
<div class="float-right">
<p>{{ $store.state.projectCategories.get(project.category).title }}</p>
<p>{{ $util.prettyDate(project.createdAt) }}</p>
<p>{{ project.stats.views }}</p>
<p>{{ project.stats.downloads }}</p>
<p>{{ project.stats.stars }}</p>
<p>{{ project.stats.watchers }}</p>
<p v-if="project && project.settings.license && project.settings.license.name">
<a ref="noopener" :href="project.settings.license.url" target="_blank">{{ project.settings.license.name }}</a>
</p>
</div>
</div>
</v-card-text>
</v-card>
<ProjectInfo :project="project" />
</v-col>
<v-col cols="12">
<v-card>
@ -167,20 +56,18 @@ import { ProjectPage } from 'hangar-internal';
import { Context } from '@nuxt/types';
import { Role } from 'hangar-api';
import Tag from '~/components/Tag.vue';
import DonationModal from '~/components/donation/DonationModal.vue';
import { Markdown, MarkdownEditor } from '~/components/markdown';
import { DocPageMixin } from '~/components/mixins';
import { DownloadButton, MemberList, ProjectPageList } from '~/components/projects';
import FlagModal from '~/components/modals/projects/FlagModal.vue';
import ProjectInfo from '~/components/projects/ProjectInfo.vue';
@Component({
components: {
FlagModal,
ProjectInfo,
DownloadButton,
ProjectPageList,
Markdown,
MemberList,
DonationModal,
MarkdownEditor,
Tag,
},
@ -188,32 +75,6 @@ import FlagModal from '~/components/modals/projects/FlagModal.vue';
export default class DocsPage extends DocPageMixin {
roles!: Role[];
get publicHost() {
return process.env.publicHost;
}
toggleStar() {
this.$api
.requestInternal<void>(`projects/project/${this.project.id}/star/${!this.project.userActions.starred}`, true, 'post')
.then(() => {
this.project.userActions.starred = !this.project.userActions.starred;
})
.catch((err) => this.$util.handleRequestError(err, 'project.error.star'));
}
toggleWatch() {
this.$api
.requestInternal(`projects/project/${this.project.id}/watch/${!this.project.userActions.watching}`, true, 'post')
.then(() => {
this.project.userActions.watching = !this.project.userActions.watching;
})
.catch((err) => this.$util.handleRequestError(err, 'project.error.watch'));
}
get slug(): string {
return `/${this.project.namespace.owner}/${this.project.namespace.slug}`;
}
async asyncData({ $api, params, $util }: Context) {
const page = await $api.requestInternal<ProjectPage>(`pages/page/${params.author}/${params.slug}`, false).catch<any>($util.handlePageRequestError);
const roles = await $api.requestInternal('data/projectRoles', false).catch($util.handlePageRequestError);
@ -223,20 +84,6 @@ export default class DocsPage extends DocPageMixin {
</script>
<style lang="scss">
.project-info {
height: 170px; // no idea why I have to set a height...
p {
margin-bottom: 3px;
}
.float-right p {
text-align: right;
}
}
.flag-modal-trigger {
display: inline;
}
.main-page-content {
padding-left: 25px;
}

View File

@ -2,9 +2,6 @@ import { Context } from '@nuxt/types';
import { Inject } from '@nuxt/types/app';
import { AxiosError } from 'axios';
import filesize from 'filesize';
// TODO fix it complaining about no type declaration file
// @ts-ignore
// import { contrastRatio, HexToRGBA, parseHex } from 'vuetify/es5/util/colorUtils'; // TODO remove or fix
import { HangarApiException, HangarValidationException, MultiHangarApiException } from 'hangar-api';
import { HangarProject, HangarUser } from 'hangar-internal';
import { TranslateResult } from 'vue-i18n';
@ -61,6 +58,39 @@ function collectErrors(exception: HangarApiException | MultiHangarApiException,
}
}
// https://awik.io/determine-color-bright-dark-using-javascript/
function lightOrDark(color: any): 'light' | 'dark' {
// Variables for red, green, blue values
let r, g, b;
// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
// If RGB --> store the red, green, blue values in separate variables
color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
r = color[1];
g = color[2];
b = color[3];
} else {
// If hex --> Convert it to RGB: http://gist.github.com/983661
color = +('0x' + color.slice(1).replace(color.length < 5 && /./g, '$&$&'));
r = color >> 16;
g = (color >> 8) & 255;
b = color & 255;
}
// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
// Using the HSP value, determine whether the color is light or dark
if (hsp > 127.5) {
return 'light';
} else {
return 'dark';
}
}
const createUtil = ({ store, error, app: { i18n } }: Context) => {
class Util {
dummyUser(): HangarUser {
@ -86,7 +116,7 @@ const createUtil = ({ store, error, app: { i18n } }: Context) => {
}
avatarUrl(name: string): string {
return `/avatar/${name}?size=120x120`;
return `/avatar/user/${name}`;
}
projectUrl(owner: string, slug: string): string {
@ -138,20 +168,12 @@ const createUtil = ({ store, error, app: { i18n } }: Context) => {
return filesize(input);
}
// TODO either fix or remove this
// white = HexToRGBA(parseHex('#ffffff'));
// black = HexToRGBA(parseHex('#000000'));
isDark(hex: string): boolean {
// const rgba = HexToRGBA(parseHex(hex));
// return contrastRatio(rgba, this.white) > 2;
return hex === null;
return lightOrDark(hex) === 'dark';
}
isLight(hex: string): boolean {
// const rgba = HexToRGBA(parseHex(hex));
// return contrastRatio(rgba, this.black) > 2;
return hex === null;
return lightOrDark(hex) === 'light';
}
/**

View File

@ -56,9 +56,9 @@ public class PopulationService {
}
}
private final List<String> paperVersions = List.of("1.8", "1.9", "1.10", "1.11", "1.12", "1.13", "1.14", "1.15", "1.16");
private final List<String> waterfallVersions = List.of("1.11", "1.12", "1.13", "1.14", "1.15", "1.16");
private final List<String> velocityVersions = List.of("1.0", "1.1");
private final List<String> paperVersions = List.of("1.8", "1.9", "1.10", "1.11", "1.12", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18");
private final List<String> waterfallVersions = List.of("1.11", "1.12", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18");
private final List<String> velocityVersions = List.of("1.0", "1.1", "3.0", "3.1");
private void populatePlatformVersions() {
Map<Platform, List<String>> platformVersions = platformVersionDAO.getVersions();