add Loading placeholder
This commit is contained in:
@ -264,7 +264,7 @@ const mediaComponent = computed(() => {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
top: calc(50px + 49px + 30px);
|
top: calc(96px + 30px);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
border-top: var(--tui-border);
|
border-top: var(--tui-border);
|
||||||
|
|||||||
@ -26,8 +26,8 @@
|
|||||||
<span class="selectable" v-text="action.refName"></span>
|
<span class="selectable" v-text="action.refName"></span>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="action.commitList">
|
<template v-if="action.commitList">
|
||||||
<h4 v-if="showRepo || showBranch">提交记录:</h4>
|
|
||||||
<div class="commits">
|
<div class="commits">
|
||||||
|
<h4 v-if="showRepo || showBranch" class="title">提交记录:</h4>
|
||||||
<div
|
<div
|
||||||
class="commit"
|
class="commit"
|
||||||
v-for="(commit, commitIndex) in action.commitList"
|
v-for="(commit, commitIndex) in action.commitList"
|
||||||
@ -103,9 +103,17 @@ const { items } = toRefs(props);
|
|||||||
|
|
||||||
.commits {
|
.commits {
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: .5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
.commit {
|
.commit {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
&:nth-last-child(n + 2) {
|
&:nth-last-child(n + 2) {
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="repository-layout" v-if="repositoryStore.value">
|
<div class="repository-layout" v-if="repositoryStore.value">
|
||||||
<t-layout class="header">
|
<div class="header">
|
||||||
<t-content>
|
<section class="top">
|
||||||
<t-space class="title" align="center">
|
<t-space class="left" align="center">
|
||||||
<h3 class="title" v-text="repositoryStore.value.name"></h3>
|
<h4 class="title" v-text="repositoryStore.value.name"></h4>
|
||||||
<p class="light-gray" v-text="repositoryStore.value.description"></p>
|
<p class="description light-gray" v-text="repositoryStore.value.description"></p>
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-content>
|
<t-space class="right" align="center">
|
||||||
<t-aside class="aside" width="auto">
|
|
||||||
<t-space align="center">
|
|
||||||
<t-button class="repository-list" theme="default" variant="text" @click="backRepositoryList">
|
<t-button class="repository-list" theme="default" variant="text" @click="backRepositoryList">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon class="icon" name="LIST" />
|
<icon class="icon" name="LIST" />
|
||||||
@ -17,8 +15,7 @@
|
|||||||
</t-button>
|
</t-button>
|
||||||
<login-menu />
|
<login-menu />
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-aside>
|
</section>
|
||||||
</t-layout>
|
|
||||||
<t-head-menu class="menu" v-model="menuValue">
|
<t-head-menu class="menu" v-model="menuValue">
|
||||||
<t-menu-item
|
<t-menu-item
|
||||||
:to="`/${repositoryStore.value.name}/${repositoryStore.value.defaultBranch}`"
|
:to="`/${repositoryStore.value.name}/${repositoryStore.value.defaultBranch}`"
|
||||||
@ -51,6 +48,7 @@
|
|||||||
版本发布
|
版本发布
|
||||||
</t-menu-item>
|
</t-menu-item>
|
||||||
</t-head-menu>
|
</t-head-menu>
|
||||||
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
@ -119,11 +117,12 @@ onMounted(async () => repositoryStore.value = await RepositoryAPI.view(route.par
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.repository-layout {
|
.repository-layout {
|
||||||
|
display: flex;
|
||||||
border-bottom: var(--tui-border);
|
border-bottom: var(--tui-border);
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 50px;
|
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
background: rgba(231, 234, 239, .8);
|
background: rgba(231, 234, 239, .8);
|
||||||
@ -131,36 +130,49 @@ onMounted(async () => repositoryStore.value = await RepositoryAPI.view(route.par
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
border-bottom: var(--tui-border);
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
margin: 0;
|
||||||
padding-left: .5rem;
|
padding-left: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aside {
|
.description {
|
||||||
display: flex;
|
margin: 0;
|
||||||
align-items: center;
|
font-size: 13px;
|
||||||
padding-right: 1rem;
|
|
||||||
|
|
||||||
.repository-list {
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-right: .5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
top: 50px;
|
|
||||||
z-index: 3;
|
|
||||||
position: sticky;
|
|
||||||
background: rgba(255, 255, 255, .8);
|
|
||||||
border-bottom: var(--tui-border);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
|
|
||||||
:deep(.t-menu) {
|
:deep(.t-menu) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
min-height: 520px;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 1200px) {
|
||||||
|
.repository-layout {
|
||||||
|
// - 底部
|
||||||
|
min-height: calc(100% - 110px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -60,6 +60,7 @@ export type File = {
|
|||||||
lastCommitterDate: number;
|
lastCommitterDate: number;
|
||||||
|
|
||||||
children: boolean;
|
children: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FileViewerType {
|
export enum FileViewerType {
|
||||||
|
|||||||
@ -1,30 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="repository-list">
|
<div class="repository-list">
|
||||||
|
<loading :showOn="isLoading" margin="1rem" />
|
||||||
<t-list class="items" v-if="page" :split="true">
|
<t-list class="items" v-if="page" :split="true">
|
||||||
<t-list-item class="item" v-for="item in pageResult.list" :key="item.id">
|
<t-list-item class="item" v-for="item in pageResult.list" :key="item.id">
|
||||||
<t-layout>
|
|
||||||
<t-aside class="icon" width="auto">
|
|
||||||
<icon name="DUPLICATE" :scale="2" />
|
<icon name="DUPLICATE" :scale="2" />
|
||||||
</t-aside>
|
<div class="content">
|
||||||
<t-content class="content">
|
<div class="header">
|
||||||
<t-layout>
|
<h3 class="name">
|
||||||
<t-header class="header" height="auto">
|
|
||||||
<div class="name">
|
|
||||||
<router-link class="link black" :to="`/${item.name}/${item.defaultBranch}`">
|
<router-link class="link black" :to="`/${item.name}/${item.defaultBranch}`">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</h3>
|
||||||
<div class="time light-gray"
|
<div class="time light-gray"
|
||||||
v-text="`最近推送 ${Time.toPassedDate(item.updatedAt)}`"
|
v-text="`最近推送 ${Time.toPassedDate(item.updatedAt)}`"
|
||||||
v-popup="Time.toDateTime(item.updatedAt)"
|
v-popup="Time.toDateTime(item.updatedAt)"
|
||||||
></div>
|
></div>
|
||||||
</t-header>
|
</div>
|
||||||
<t-content>
|
<div class="description gray" v-text="item.description"></div>
|
||||||
<span class="gray" v-text="item.description"></span>
|
</div>
|
||||||
</t-content>
|
|
||||||
</t-layout>
|
|
||||||
</t-content>
|
|
||||||
</t-layout>
|
|
||||||
</t-list-item>
|
</t-list-item>
|
||||||
</t-list>
|
</t-list>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
@ -44,7 +37,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import RepositoryAPI from "@/api/RepositoryAPI";
|
import RepositoryAPI from "@/api/RepositoryAPI";
|
||||||
import { Repository } from "@/types/Repository";
|
import { Repository } from "@/types/Repository";
|
||||||
import { Icon, Page, PageResult, Time } from "timi-web";
|
import { Icon, Loading, Page, PageResult, Time } from "timi-web";
|
||||||
|
|
||||||
const page = ref<Page>({
|
const page = ref<Page>({
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -54,11 +47,13 @@ const pageResult = reactive<PageResult<Repository>>({
|
|||||||
total: 0,
|
total: 0,
|
||||||
list: []
|
list: []
|
||||||
});
|
});
|
||||||
|
const isLoading = ref(false);
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
isLoading.value = true;
|
||||||
const result = await RepositoryAPI.page(page.value);
|
const result = await RepositoryAPI.page(page.value);
|
||||||
pageResult.total = result.total;
|
pageResult.total = result.total;
|
||||||
pageResult.list = result.list;
|
pageResult.list = result.list;
|
||||||
|
isLoading.value = false;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -71,25 +66,22 @@ onMounted(async () => {
|
|||||||
min-height: 520px;
|
min-height: 520px;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
display: flex;
|
||||||
.icon {
|
padding: 16px;
|
||||||
padding: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding-left: .5rem;
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
margin-left: 16px;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
flex: 1;
|
margin: 0;
|
||||||
display: block;
|
|
||||||
|
|
||||||
.link {
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="repository-log">
|
<div class="repository-log">
|
||||||
<push-log-timeline :items="list"/>
|
<push-log-timeline :items="list" />
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<loading :showOn="isLoading"/>
|
<loading :showOn="isLoading" />
|
||||||
<empty-tips :showOn="isFinished && !isLoading"/>
|
<empty-tips :showOn="isFinished && !isLoading" />
|
||||||
<t-button v-show="!isFinished && !isLoading" @click="doFetchEvent">加载更多</t-button>
|
<t-button v-show="!isFinished && !isLoading" @click="doFetchEvent">加载更多</t-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="repositoryStore.value" class="commit-log">
|
<div v-if="repositoryStore.value" class="commit-log">
|
||||||
<t-layout>
|
<div class="header">
|
||||||
<t-header class="header">
|
|
||||||
<div>
|
|
||||||
<t-select class="branch" v-model="branch" label="分支:" placeholder="全部" clearable>
|
<t-select class="branch" v-model="branch" label="分支:" placeholder="全部" clearable>
|
||||||
<t-option
|
<t-option
|
||||||
v-for="item in repositoryStore.value.branchList"
|
v-for="item in repositoryStore.value.branchList"
|
||||||
@ -12,19 +10,18 @@
|
|||||||
/>
|
/>
|
||||||
</t-select>
|
</t-select>
|
||||||
</div>
|
</div>
|
||||||
</t-header>
|
<div class="content">
|
||||||
<t-content class="content">
|
<loading :showOn="isLoading" margin="0 0 1rem 0" />
|
||||||
<push-log-timeline :items="commits" :show-repo="false" :show-branch="!branch" />
|
<push-log-timeline :items="commits" :show-repo="false" :show-branch="!branch" />
|
||||||
<div class="more">
|
<div class="more">
|
||||||
<empty-tips :showOn="isFinished" />
|
<empty-tips :showOn="isFinished" />
|
||||||
<t-button v-if="!isFinished" @click="doFetchEvent">加载更多</t-button>
|
<t-button v-if="!isLoading && !isFinished" @click="doFetchEvent">加载更多</t-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t-content>
|
|
||||||
</t-layout>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { EmptyTips, Page } from "timi-web";
|
import { EmptyTips, Loading, Page } from "timi-web";
|
||||||
import RepositoryAPI from "@/api/RepositoryAPI";
|
import RepositoryAPI from "@/api/RepositoryAPI";
|
||||||
import { useRepositoryStore } from "@/store/repository.ts";
|
import { useRepositoryStore } from "@/store/repository.ts";
|
||||||
import { ActionLogView } from "@/types/Common.ts";
|
import { ActionLogView } from "@/types/Common.ts";
|
||||||
@ -32,33 +29,32 @@ import PushLogTimeline from "@/components/PushLogTimeline.vue";
|
|||||||
|
|
||||||
const repositoryStore = useRepositoryStore();
|
const repositoryStore = useRepositoryStore();
|
||||||
|
|
||||||
const branch = ref();
|
|
||||||
|
|
||||||
const page = ref<Page>({
|
const page = ref<Page>({
|
||||||
index: 0,
|
index: 0,
|
||||||
size: 12
|
size: 12
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const branch = ref();
|
||||||
const commits = reactive<ActionLogView[]>([]);
|
const commits = reactive<ActionLogView[]>([]);
|
||||||
|
const isLoading = ref(false);
|
||||||
const isFinished = ref(false);
|
const isFinished = ref(false);
|
||||||
|
|
||||||
const doFetchEvent = async () => {
|
const doFetchEvent = async () => {
|
||||||
if (repositoryStore.value) {
|
isLoading.value = true;
|
||||||
const result = await RepositoryAPI.pagePush(repositoryStore.value.name, branch.value ?? "all", page.value);
|
const result = await RepositoryAPI.pagePush(repositoryStore.value!.name, branch.value ?? "all", page.value);
|
||||||
const list = result.list;
|
const list = result.list;
|
||||||
commits.push(...list);
|
commits.push(...list);
|
||||||
page.value.index++;
|
page.value.index++;
|
||||||
if (result.list.length < page.value.size) {
|
if (result.list.length < page.value.size) {
|
||||||
isFinished.value = true;
|
isFinished.value = true;
|
||||||
}
|
}
|
||||||
}
|
isLoading.value = false;
|
||||||
};
|
};
|
||||||
watch(branch, () => {
|
watch(branch, () => {
|
||||||
if (repositoryStore.value) {
|
|
||||||
page.value.index = 0;
|
page.value.index = 0;
|
||||||
commits.length = 0;
|
commits.length = 0;
|
||||||
isFinished.value = false;
|
isFinished.value = false;
|
||||||
doFetchEvent();
|
doFetchEvent();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
onMounted(doFetchEvent);
|
onMounted(doFetchEvent);
|
||||||
</script>
|
</script>
|
||||||
@ -66,7 +62,8 @@ onMounted(doFetchEvent);
|
|||||||
.commit-log {
|
.commit-log {
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
top: calc(50px + 49px);
|
top: 96px;
|
||||||
|
height: 50px;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
@ -76,10 +73,15 @@ onMounted(doFetchEvent);
|
|||||||
border-bottom: var(--tui-border);
|
border-bottom: var(--tui-border);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
.branch {
|
||||||
|
width: 12rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 1rem 2rem 1rem 1rem;
|
padding: 1rem 2rem 1rem 1rem;
|
||||||
|
min-height: 520px;
|
||||||
|
|
||||||
.more {
|
.more {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
></t-option>
|
></t-option>
|
||||||
</t-select>
|
</t-select>
|
||||||
<div class="tree-container">
|
<div class="tree-container">
|
||||||
|
<loading :showOn="treeLoading" margin="1rem" />
|
||||||
<t-tree
|
<t-tree
|
||||||
ref="tree"
|
ref="tree"
|
||||||
class="tree"
|
class="tree"
|
||||||
@ -28,6 +29,7 @@
|
|||||||
:expand-parent="true"
|
:expand-parent="true"
|
||||||
value-mode="all"
|
value-mode="all"
|
||||||
expand-all
|
expand-all
|
||||||
|
:empty="() => ''"
|
||||||
:load="treeLoad"
|
:load="treeLoad"
|
||||||
:onActive="onTreeActivated"
|
:onActive="onTreeActivated"
|
||||||
>
|
>
|
||||||
@ -35,6 +37,9 @@
|
|||||||
<icon name="FILE" fill="GRAY" v-if="node.data.type === FileType.FILE" />
|
<icon name="FILE" fill="GRAY" v-if="node.data.type === FileType.FILE" />
|
||||||
<icon name="FOLDER" v-if="node.data.type === FileType.DIRECTORY" />
|
<icon name="FOLDER" v-if="node.data.type === FileType.DIRECTORY" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #operations="{ node }">
|
||||||
|
<loading v-if="node.data.isLoading" :size="14" :tips="false" margin="0 .5rem 0 0" />
|
||||||
|
</template>
|
||||||
</t-tree>
|
</t-tree>
|
||||||
</div>
|
</div>
|
||||||
</pane>
|
</pane>
|
||||||
@ -69,7 +74,7 @@
|
|||||||
</split-pane>
|
</split-pane>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Icon } from "timi-web";
|
import { Icon, Loading } from "timi-web";
|
||||||
import type { TreeInstanceFunctions, TreeProps } from "tdesign-vue-next";
|
import type { TreeInstanceFunctions, TreeProps } from "tdesign-vue-next";
|
||||||
import RepositoryAPI from "@/api/RepositoryAPI";
|
import RepositoryAPI from "@/api/RepositoryAPI";
|
||||||
import { File, FileType } from "@/types/Repository";
|
import { File, FileType } from "@/types/Repository";
|
||||||
@ -100,6 +105,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// ---------- 文件树 ----------
|
// ---------- 文件树 ----------
|
||||||
const tree = ref<TreeInstanceFunctions>();
|
const tree = ref<TreeInstanceFunctions>();
|
||||||
|
const treeLoading = ref(false);
|
||||||
const treeItems = ref<File[]>([]);
|
const treeItems = ref<File[]>([]);
|
||||||
const treeMap = {
|
const treeMap = {
|
||||||
value: "path",
|
value: "path",
|
||||||
@ -110,9 +116,14 @@ watch(branch, async () => {
|
|||||||
if (!repositoryStore.value || !branch.value) {
|
if (!repositoryStore.value || !branch.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
treeLoading.value = true;
|
||||||
treeItems.value = await RepositoryAPI.listFile(repositoryStore.value!.name, branch.value, "/");
|
treeItems.value = await RepositoryAPI.listFile(repositoryStore.value!.name, branch.value, "/");
|
||||||
treeItems.value.forEach((item) => item.children = item.type === FileType.DIRECTORY);
|
treeItems.value.forEach((item) => {
|
||||||
|
item.isLoading = false;
|
||||||
|
item.children = item.type === FileType.DIRECTORY;
|
||||||
|
});
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
treeLoading.value = false;
|
||||||
// 文件树
|
// 文件树
|
||||||
if (tree.value) {
|
if (tree.value) {
|
||||||
const items = treeItems.value;
|
const items = treeItems.value;
|
||||||
@ -127,6 +138,7 @@ watch(branch, async () => {
|
|||||||
const treeLabel: TreeProps["label"] = (_h, node) => node.data.name;
|
const treeLabel: TreeProps["label"] = (_h, node) => node.data.name;
|
||||||
const treeLoad: TreeProps["load"] = async (node) => {
|
const treeLoad: TreeProps["load"] = async (node) => {
|
||||||
const file = node.data;
|
const file = node.data;
|
||||||
|
file.isLoading = true;
|
||||||
const result = await RepositoryAPI.listFile(
|
const result = await RepositoryAPI.listFile(
|
||||||
repositoryStore.value!.name,
|
repositoryStore.value!.name,
|
||||||
branch.value,
|
branch.value,
|
||||||
@ -138,7 +150,11 @@ const treeLoad: TreeProps["load"] = async (node) => {
|
|||||||
file.path = `${file.path}/${deep.name}`;
|
file.path = `${file.path}/${deep.name}`;
|
||||||
return await treeLoad!(node);
|
return await treeLoad!(node);
|
||||||
}
|
}
|
||||||
result.forEach((item) => item.children = item.type === FileType.DIRECTORY);
|
result.forEach((item) => {
|
||||||
|
item.isLoading = false;
|
||||||
|
item.children = item.type === FileType.DIRECTORY;
|
||||||
|
});
|
||||||
|
file.isLoading = false;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,7 +208,7 @@ const onTreeActivated = (_value: any, context: { node: any }) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.branch {
|
.branch {
|
||||||
top: calc(50px + 49px);
|
top: 96px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
border-bottom: var(--tui-border);
|
border-bottom: var(--tui-border);
|
||||||
@ -246,7 +262,7 @@ const onTreeActivated = (_value: any, context: { node: any }) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
top: calc(50px + 49px);
|
top: 96px;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<t-layout class="issue-list" v-if="repositoryStore.value">
|
<div class="issue-list" v-if="repositoryStore.value">
|
||||||
<t-header class="header">
|
<header class="header">
|
||||||
<t-row justify="space-between">
|
<div class="search">
|
||||||
<t-col flex="auto">
|
|
||||||
<t-input-adornment prepend="搜索">
|
<t-input-adornment prepend="搜索">
|
||||||
<t-input v-model="page.keyword" placeholder="请输入关键字" />
|
<t-input v-model="page.keyword" placeholder="请输入关键字" />
|
||||||
</t-input-adornment>
|
</t-input-adornment>
|
||||||
</t-col>
|
</div>
|
||||||
<t-col class="right">
|
<t-space class="filter">
|
||||||
<t-space>
|
|
||||||
<t-select v-model="page.type" label="类型" placeholder="全部" autoWidth clearable>
|
<t-select v-model="page.type" label="类型" placeholder="全部" autoWidth clearable>
|
||||||
<t-option v-for="(value, key) in Type" :key="key" :value="key" :label="value" />
|
<t-option v-for="(value, key) in Type" :key="key" :value="key" :label="value" />
|
||||||
</t-select>
|
</t-select>
|
||||||
@ -19,14 +17,11 @@
|
|||||||
<t-button theme="success">新建反馈</t-button>
|
<t-button theme="success">新建反馈</t-button>
|
||||||
</router-link>
|
</router-link>
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-col>
|
</header>
|
||||||
</t-row>
|
<t-list class="issues" :split="true">
|
||||||
</t-header>
|
<loading :showOn="isLoading" margin="1rem 0" />
|
||||||
<t-content class="list">
|
<empty-tips v-if="!isLoading && pageResult?.total === 0" />
|
||||||
<t-list v-if="pageResult" :split="true">
|
<t-list-item class="issue" v-for="item in pageResult?.list" :key="item.id">
|
||||||
<t-list-item class="action" v-for="item in pageResult.list" :key="item.id">
|
|
||||||
<t-layout>
|
|
||||||
<t-aside width="auto">
|
|
||||||
<t-space class="tags" :size="4">
|
<t-space class="tags" :size="4">
|
||||||
<div
|
<div
|
||||||
v-if="item.type"
|
v-if="item.type"
|
||||||
@ -41,8 +36,7 @@
|
|||||||
v-text="(<any>Status)[item.status]"
|
v-text="(<any>Status)[item.status]"
|
||||||
></div>
|
></div>
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-aside>
|
<div class="content">
|
||||||
<t-content class="content">
|
|
||||||
<router-link :to="`/${repositoryStore.value.name}/issues/${item.id}`">
|
<router-link :to="`/${repositoryStore.value.name}/issues/${item.id}`">
|
||||||
<t-link theme="default" size="large" hover="color" :content="item.title" />
|
<t-link theme="default" size="large" hover="color" :content="item.title" />
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -50,26 +44,22 @@
|
|||||||
<span v-if="item.closedAt" v-text="`关闭于 ${Time.toPassedDateTime(item.closedAt)}`"></span>
|
<span v-if="item.closedAt" v-text="`关闭于 ${Time.toPassedDateTime(item.closedAt)}`"></span>
|
||||||
<span v-else v-text="`创建于 ${Time.toPassedDateTime(item.createdAt)}`"></span>
|
<span v-else v-text="`创建于 ${Time.toPassedDateTime(item.createdAt)}`"></span>
|
||||||
</p>
|
</p>
|
||||||
</t-content>
|
</div>
|
||||||
</t-layout>
|
|
||||||
</t-list-item>
|
</t-list-item>
|
||||||
</t-list>
|
</t-list>
|
||||||
<empty-tips :showOn="pageResult?.total === 0" />
|
<footer v-if="pageResult" class="footer">
|
||||||
</t-content>
|
|
||||||
<t-footer class="footer" height="auto">
|
|
||||||
<t-pagination
|
<t-pagination
|
||||||
v-if="pageResult"
|
|
||||||
:total="pageResult.total"
|
:total="pageResult.total"
|
||||||
:pageSize="16"
|
:pageSize="16"
|
||||||
:showPageSize="false"
|
:showPageSize="false"
|
||||||
:onCurrentChange="(current: number) => page.index = current - 1"
|
:onCurrentChange="(current: number) => page.index = current - 1"
|
||||||
/>
|
/>
|
||||||
</t-footer>
|
</footer>
|
||||||
</t-layout>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { EmptyTips, PageResult, Time, Toolkit } from "timi-web";
|
import { EmptyTips, Loading, PageResult, Time, Toolkit } from "timi-web";
|
||||||
import IssueAPI from "@/api/IssueAPI";
|
import IssueAPI from "@/api/IssueAPI";
|
||||||
import { Issue, Page, Status, Type } from "@/types/Issue";
|
import { Issue, Page, Status, Type } from "@/types/Issue";
|
||||||
import { useRepositoryStore } from "@/store/repository.ts";
|
import { useRepositoryStore } from "@/store/repository.ts";
|
||||||
@ -96,10 +86,13 @@ const page = reactive<Page>({
|
|||||||
index: 0,
|
index: 0,
|
||||||
size: 12
|
size: 12
|
||||||
});
|
});
|
||||||
|
const isLoading = ref(false);
|
||||||
const pageResult = ref<PageResult<Issue>>();
|
const pageResult = ref<PageResult<Issue>>();
|
||||||
|
const fetchList = Toolkit.debounce(async () => {
|
||||||
const fetchList = Toolkit.debounce(async () => pageResult.value = await IssueAPI.page(page));
|
isLoading.value = true;
|
||||||
|
pageResult.value = await IssueAPI.page(page);
|
||||||
|
isLoading.value = false;
|
||||||
|
});
|
||||||
watch(page, fetchList);
|
watch(page, fetchList);
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (repositoryStore.value) {
|
if (repositoryStore.value) {
|
||||||
@ -111,12 +104,15 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.issue-list {
|
.issue-list {
|
||||||
min-height: 480px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
top: calc(50px + 49px);
|
top: 96px;
|
||||||
z-index: 3;
|
height: 50px;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
z-index: 3;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
background: rgba(231, 234, 239, .8);
|
background: rgba(231, 234, 239, .8);
|
||||||
@ -125,22 +121,26 @@ onMounted(async () => {
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
|
||||||
.t-row {
|
.search {
|
||||||
width: 100%;
|
flex: 1;
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter {
|
.filter {
|
||||||
padding: 0 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.issues {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.issue {
|
||||||
|
|
||||||
|
:deep(.t-list-item-main) {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
|
|
||||||
@ -154,6 +154,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
flex: 1;
|
||||||
padding-left: .5rem;
|
padding-left: .5rem;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@ -165,6 +166,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
@ -176,10 +178,4 @@ onMounted(async () => {
|
|||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
|
||||||
.issue-list {
|
|
||||||
min-height: calc(100vh - 100px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,44 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<t-layout v-if="repositoryStore.value" class="merge-list">
|
<div v-if="repositoryStore.value" class="merge-list">
|
||||||
<t-header class="header">
|
<header class="header">
|
||||||
<t-row justify="space-between">
|
<div class="search">
|
||||||
<t-col flex="auto">
|
|
||||||
<t-input-adornment prepend="搜索">
|
<t-input-adornment prepend="搜索">
|
||||||
<t-input v-model="page.keyword" placeholder="请输入关键字" />
|
<t-input v-model="page.keyword" placeholder="请输入关键字" />
|
||||||
</t-input-adornment>
|
</t-input-adornment>
|
||||||
</t-col>
|
</div>
|
||||||
<t-col class="right">
|
<t-space class="filter">
|
||||||
<t-space>
|
<t-select v-model="page.type" label="类型" placeholder="全部" autoWidth clearable>
|
||||||
<t-select
|
|
||||||
v-model="page.type"
|
|
||||||
label="类型"
|
|
||||||
placeholder="全部"
|
|
||||||
autoWidth
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<t-option v-for="(value, key) in Type" :key="key" :value="key" :label="value" />
|
<t-option v-for="(value, key) in Type" :key="key" :value="key" :label="value" />
|
||||||
</t-select>
|
</t-select>
|
||||||
<t-select
|
<t-select v-model="page.status" label="状态" placeholder="全部" autoWidth clearable>
|
||||||
v-model="page.status"
|
|
||||||
label="状态"
|
|
||||||
placeholder="全部"
|
|
||||||
autoWidth
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<t-option v-for="(value, key) in Status" :key="key" :value="key" :label="value" />
|
<t-option v-for="(value, key) in Status" :key="key" :value="key" :label="value" />
|
||||||
</t-select>
|
</t-select>
|
||||||
<router-link :to="`/${repositoryStore.value.name}/merges/edit`">
|
<router-link :to="`/${repositoryStore.value.name}/merges/edit`">
|
||||||
<t-button theme="success">申请合并</t-button>
|
<t-button theme="success">申请合并</t-button>
|
||||||
</router-link>
|
</router-link>
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-col>
|
</header>
|
||||||
</t-row>
|
<t-list class="merges" v-if="pageResult" :split="true">
|
||||||
</t-header>
|
<loading :showOn="isLoading" margin="1rem 0" />
|
||||||
<t-content class="list">
|
<empty-tips v-if="!isLoading && pageResult?.total === 0" />
|
||||||
<t-list v-if="pageResult" :split="true">
|
<t-list-item class="merge" v-for="item in pageResult.list" :key="item.id">
|
||||||
<t-list-item class="action" v-for="item in pageResult.list" :key="item.id">
|
|
||||||
<t-layout>
|
|
||||||
<t-aside width="auto">
|
|
||||||
<t-space class="tags" :size="4">
|
<t-space class="tags" :size="4">
|
||||||
<div
|
<div
|
||||||
v-if="item.type"
|
v-if="item.type"
|
||||||
@ -53,38 +36,30 @@
|
|||||||
v-text="(<any>Status)[item.status]"
|
v-text="(<any>Status)[item.status]"
|
||||||
></div>
|
></div>
|
||||||
</t-space>
|
</t-space>
|
||||||
</t-aside>
|
<div class="content">
|
||||||
<t-content class="content">
|
|
||||||
<router-link :to="`/${repositoryStore.value.name}/merges/${item.id}`">
|
<router-link :to="`/${repositoryStore.value.name}/merges/${item.id}`">
|
||||||
<t-link theme="default" size="large" hover="color" :content="item.title" />
|
<t-link theme="default" size="large" hover="color" :content="item.title" />
|
||||||
</router-link>
|
</router-link>
|
||||||
<p class="time gray">
|
<p class="time gray">
|
||||||
<span
|
<span v-if="item.rejectedAt" v-text="`拒绝于 ${Time.toPassedDateTime(item.rejectedAt)}`"></span>
|
||||||
v-if="item.rejectedAt"
|
|
||||||
v-text="`拒绝于 ${Time.toPassedDateTime(item.rejectedAt)}`"
|
|
||||||
></span>
|
|
||||||
<span v-else v-text="`申请于 ${Time.toPassedDateTime(item.createdAt)}`"></span>
|
<span v-else v-text="`申请于 ${Time.toPassedDateTime(item.createdAt)}`"></span>
|
||||||
</p>
|
</p>
|
||||||
</t-content>
|
</div>
|
||||||
</t-layout>
|
|
||||||
</t-list-item>
|
</t-list-item>
|
||||||
</t-list>
|
</t-list>
|
||||||
<empty-tips :showOn="pageResult?.total === 0" />
|
<footer v-if="pageResult" class="footer">
|
||||||
</t-content>
|
|
||||||
<t-footer class="footer" height="auto">
|
|
||||||
<t-pagination
|
<t-pagination
|
||||||
v-if="pageResult"
|
|
||||||
:total="pageResult.total"
|
:total="pageResult.total"
|
||||||
:pageSize="16"
|
:pageSize="16"
|
||||||
:showPageSize="false"
|
:showPageSize="false"
|
||||||
:onCurrentChange="(current: number) => page.index = current - 1"
|
:onCurrentChange="(current: number) => page.index = current - 1"
|
||||||
/>
|
/>
|
||||||
</t-footer>
|
</footer>
|
||||||
</t-layout>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { EmptyTips, PageResult, Time, Toolkit } from "timi-web";
|
import { EmptyTips, Loading, PageResult, Time, Toolkit } from "timi-web";
|
||||||
import MergeAPI from "@/api/MergeAPI";
|
import MergeAPI from "@/api/MergeAPI";
|
||||||
import { Merge, Page, Status, Type } from "@/types/Merge";
|
import { Merge, Page, Status, Type } from "@/types/Merge";
|
||||||
import { useRepositoryStore } from "@/store/repository.ts";
|
import { useRepositoryStore } from "@/store/repository.ts";
|
||||||
@ -105,11 +80,13 @@ const colorStatus = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const repositoryStore = useRepositoryStore();
|
const repositoryStore = useRepositoryStore();
|
||||||
|
|
||||||
const page = reactive<Page>({
|
const page = reactive<Page>({
|
||||||
repositoryId: undefined,
|
repositoryId: undefined,
|
||||||
index: 0,
|
index: 0,
|
||||||
size: 12
|
size: 12
|
||||||
});
|
});
|
||||||
|
const isLoading = ref(false);
|
||||||
const pageResult = ref<PageResult<Merge>>();
|
const pageResult = ref<PageResult<Merge>>();
|
||||||
const fetchList = Toolkit.debounce(async () => pageResult.value = await MergeAPI.page(page));
|
const fetchList = Toolkit.debounce(async () => pageResult.value = await MergeAPI.page(page));
|
||||||
|
|
||||||
@ -124,11 +101,13 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.merge-list {
|
.merge-list {
|
||||||
min-height: 480px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
top: calc(50px + 49px);
|
top: 96px;
|
||||||
z-index: 3;
|
height: 50px;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
@ -138,22 +117,26 @@ onMounted(async () => {
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
|
||||||
.t-row {
|
.search {
|
||||||
width: 100%;
|
flex: 1;
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter {
|
.filter {
|
||||||
padding: 0 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.merges {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.merge {
|
||||||
|
|
||||||
|
:deep(.t-list-item-main) {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
|
|
||||||
@ -167,6 +150,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
flex: 1;
|
||||||
padding-left: .5rem;
|
padding-left: .5rem;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@ -178,6 +162,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
@ -185,15 +170,8 @@ onMounted(async () => {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
background: rgba(255, 255, 255, .8);
|
background: rgba(255, 255, 255, .8);
|
||||||
border-top: var(--tui-border);
|
border-top: var(--tui-border);
|
||||||
border-top: var(--tui-border);
|
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
-webkit-backdrop-filter: blur(10px);
|
-webkit-backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
|
||||||
.merge-list {
|
|
||||||
min-height: calc(100vh - 100px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -37,14 +37,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t-timeline-item>
|
</t-timeline-item>
|
||||||
|
<loading :showOn="isLoading" />
|
||||||
|
<empty-tips v-if="!isLoading && Toolkit.isEmpty(pageResult?.list)" />
|
||||||
</t-timeline>
|
</t-timeline>
|
||||||
<empty-tips :showOn="Toolkit.isEmpty(pageResult?.list)" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ReleaseAPI from "@/api/ReleaseAPI";
|
import ReleaseAPI from "@/api/ReleaseAPI";
|
||||||
import { Page, Release } from "@/types/Release";
|
import { Page, Release } from "@/types/Release";
|
||||||
import { CommonAPI, EmptyTips, Icon, IOSize, MarkdownView, PageResult, Time, Toolkit } from "timi-web";
|
import { CommonAPI, EmptyTips, Icon, IOSize, Loading, MarkdownView, PageResult, Time, Toolkit } from "timi-web";
|
||||||
import { useRepositoryStore } from "@/store/repository.ts";
|
import { useRepositoryStore } from "@/store/repository.ts";
|
||||||
|
|
||||||
const repositoryStore = useRepositoryStore();
|
const repositoryStore = useRepositoryStore();
|
||||||
@ -54,13 +55,14 @@ const page = reactive<Page>({
|
|||||||
index: 0,
|
index: 0,
|
||||||
size: 12
|
size: 12
|
||||||
});
|
});
|
||||||
|
const isLoading = ref(false);
|
||||||
const pageResult = ref<PageResult<Release>>();
|
const pageResult = ref<PageResult<Release>>();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (repositoryStore.value) {
|
isLoading.value = true;
|
||||||
page.repositoryId = repositoryStore.value.id;
|
page.repositoryId = repositoryStore.value!.id;
|
||||||
pageResult.value = await ReleaseAPI.page(page);
|
pageResult.value = await ReleaseAPI.page(page);
|
||||||
}
|
isLoading.value = false;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@ -121,10 +123,4 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
|
||||||
.release-list {
|
|
||||||
min-height: calc(100vh - 98px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user