Skip to content

Commit

Permalink
Merge branch 'dev' into casdoor-user
Browse files Browse the repository at this point in the history
  • Loading branch information
aofei committed Oct 17, 2024
2 parents b34dbe6 + 3d93c30 commit a0eec46
Show file tree
Hide file tree
Showing 30 changed files with 635 additions and 344 deletions.
22 changes: 21 additions & 1 deletion spx-gui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion spx-gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@
"@vue/runtime-dom": "^3.4.10",
"@vue/test-utils": "^2.4.5",
"@vue/tsconfig": "^0.5.1",
"casdoor-js-sdk": "^0.15.0",
"dayjs": "^1.11.10",
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.20.1",
"file-saver": "^2.0.5",
"happy-dom": "^14.3.6",
"install": "^0.13.0",
"js-pkce": "^1.4.0",
"jszip": "^3.10.1",
"jwt-decode": "^4.0.0",
"konva": "^9.3.1",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
Expand Down
31 changes: 31 additions & 0 deletions spx-gui/src/apis/project-release.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { client, type FileCollection } from './common'

export type ProjectRelease = {
/** Unique identifier */
id: string
/** Creation timestamp */
createdAt: string
/** Last update timestamp */
updatedAt: string
/** Full name of the project, in the format `owner/project`. */
projectFullName: string
/** Unique name of the project release, adhering to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). */
name: string
/** rief description of the release. */
description: string
/** File paths and their corresponding universal URLs associated with the release. */
files: FileCollection
/** Universal URL of the release's thumbnail image. */
thumbnail: string
/** Number of times the release has been remixed. */
remixCount: number
}

export type CreateReleaseParams = Pick<
ProjectRelease,
'projectFullName' | 'name' | 'description' | 'thumbnail'
>

export function createRelease(params: CreateReleaseParams) {
return client.post('/project-release', params) as Promise<ProjectRelease>
}
5 changes: 3 additions & 2 deletions spx-gui/src/apis/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export type ProjectData = {
description: string
/** Instructions on how to interact with the project */
instructions: string
/** URL of the project's thumbnail image */
/** Universal URL of the project's thumbnail image */
thumbnail: string
/** Number of times the project has been viewed */
viewCount: number
Expand All @@ -52,7 +52,8 @@ export async function addProject(params: AddProjectParams, signal?: AbortSignal)
return client.post('/project', params, { signal }) as Promise<ProjectData>
}

export type UpdateProjectParams = Pick<ProjectData, 'files' | 'visibility'>
export type UpdateProjectParams = Pick<ProjectData, 'files' | 'visibility'> &
Partial<Pick<ProjectData, 'description' | 'instructions' | 'thumbnail'>>

function encode(owner: string, name: string) {
return `${encodeURIComponent(owner)}/${encodeURIComponent(name)}`
Expand Down
1 change: 1 addition & 0 deletions spx-gui/src/components/community/CommunityNavbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function handleSearch() {

<style lang="scss" scoped>
.search {
margin-right: 8px;
width: 340px;
display: flex;
align-items: center;
Expand Down
1 change: 0 additions & 1 deletion spx-gui/src/components/community/user/EditProfileModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const handleSubmit = useMessageHandle(
>
<div class="cover"></div>
<UIImg class="avatar" :src="user.avatar" />
<!-- TODO: header & avatar -->
<UIForm :form="form" has-success-feedback @submit="handleSubmit.fn">
<UIFormItem :label="$t({ en: 'Name', zh: '名字' })">
<UITextInput :value="user.displayName" disabled />
Expand Down
71 changes: 52 additions & 19 deletions spx-gui/src/components/editor/navbar/EditorNavbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@
</UIMenuItem>
</UIMenuGroup>
<UIMenuGroup :disabled="project == null || !isOnline">
<UIMenuItem @click="handleShareProject">
<template #icon><img :src="shareSvg" /></template>
{{ $t({ en: 'Share project', zh: '分享项目' }) }}
<UIMenuItem @click="handlePublishProject">
<template #icon><img :src="publishSvg" /></template>
{{ $t({ en: 'Publish project', zh: '发布项目' }) }}
</UIMenuItem>
<UIMenuItem
v-if="project?.visibility === Visibility.Public"
@click="handleStopSharingProject"
@click="handleUnpublishProject"
>
<template #icon><img :src="stopSharingSvg" /></template>
{{ $t({ en: 'Stop sharing', zh: '停止分享' }) }}
<template #icon><img :src="unpublishSvg" /></template>
{{ $t({ en: 'Unpublish project', zh: '取消发布' }) }}
</UIMenuItem>
<UIMenuItem @click="handleOpenProjectPage">
<template #icon><img :src="projectPageSvg" /></template>
{{ $t({ en: 'Open project page', zh: '打开项目主页' }) }}
</UIMenuItem>
</UIMenuGroup>
<UIMenuGroup :disabled="project == null">
Expand Down Expand Up @@ -80,6 +84,13 @@
</div>
</template>
</template>
<template #right>
<div v-show="project != null" class="publish">
<UIButton type="secondary" :disabled="!isOnline" @click="handlePublishProject">
{{ $t({ en: 'Publish', zh: '发布' }) }}
</UIButton>
</div>
</template>
</NavbarWrapper>
</template>
Expand All @@ -93,15 +104,17 @@ import {
UIMenuItem,
UIIcon,
UITooltip,
useConfirmDialog
useConfirmDialog,
UIButton
} from '@/components/ui'
import { useMessageHandle } from '@/utils/exception'
import { useI18n, type LocaleMessage } from '@/utils/i18n'
import { useNetwork } from '@/utils/network'
import { selectFile } from '@/utils/file'
import { AutoSaveToCloudState, type Project } from '@/models/project'
import { Visibility } from '@/apis/common'
import { useRemoveProject, useShareProject, useStopSharingProject } from '@/components/project'
import { getProjectPageRoute } from '@/router'
import { usePublishProject, useRemoveProject, useUnpublishProject } from '@/components/project'
import { useLoadFromScratchModal } from '@/components/asset'
import NavbarWrapper from '@/components/navbar/NavbarWrapper.vue'
import NavbarDropdown from '@/components/navbar/NavbarDropdown.vue'
Expand All @@ -113,8 +126,9 @@ import importProjectSvg from './icons/import-project.svg'
import exportProjectSvg from './icons/export-project.svg'
import removeProjectSvg from './icons/remove-project.svg'
import importScratchSvg from './icons/import-scratch.svg'
import shareSvg from './icons/share.svg'
import stopSharingSvg from './icons/stop-sharing.svg'
import publishSvg from './icons/publish.svg'
import unpublishSvg from './icons/unpublish.svg'
import projectPageSvg from './icons/project-page.svg'
import offlineSvg from './icons/offline.svg?raw'
import savingSvg from './icons/saving.svg?raw'
import failedToSaveSvg from './icons/failed-to-save.svg?raw'
Expand Down Expand Up @@ -163,19 +177,31 @@ const handleImportFromScratch = useMessageHandle(() => loadFromScratchModal(prop
zh: '从 Scratch 项目文件导入失败'
}).fn
const shareProject = useShareProject()
const handleShareProject = useMessageHandle(() => shareProject(props.project!), {
en: 'Failed to share project',
zh: '分享项目失败'
const publishProject = usePublishProject()
const handlePublishProject = useMessageHandle(() => publishProject(props.project!), {
en: 'Failed to publish project',
zh: '发布项目失败'
}).fn
const stopSharingProject = useStopSharingProject()
const handleStopSharingProject = useMessageHandle(
() => stopSharingProject(props.project!),
{ en: 'Failed to stop sharing project', zh: '停止分享项目失败' },
{ en: 'Project sharing is now stopped', zh: '项目已停止分享' }
const unpublishProject = useUnpublishProject()
const handleUnpublishProject = useMessageHandle(
() => unpublishProject(props.project!),
{
en: 'Failed to unpublish project',
zh: '取消发布失败'
},
{
en: 'Project unpublished',
zh: '已取消发布'
}
).fn
function handleOpenProjectPage() {
const { owner, name } = props.project!
if (owner == null || name == null) throw new Error('project owner or name is null')
window.open(getProjectPageRoute(owner, name))
}
const removeProject = useRemoveProject()
const handleRemoveProject = useMessageHandle(
async () => {
Expand Down Expand Up @@ -273,4 +299,11 @@ const autoSaveStateIcon = computed<AutoSaveStateIcon>(() => {
}
}
}
.publish {
margin-right: 2px;
height: 100%;
display: flex;
align-items: center;
}
</style>
4 changes: 4 additions & 0 deletions spx-gui/src/components/editor/navbar/icons/project-page.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion spx-gui/src/components/editor/preview/EditorPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</UICardHeader>

<UIFullScreenModal v-model:show="show" class="project-runner-modal">
<RunnerContainer mode="debug" :project="editorCtx.project" @close="show = false" />
<RunnerContainer :project="editorCtx.project" @close="show = false" />
</UIFullScreenModal>
<div class="stage-viewer-container">
<StageViewer />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ async function moveZorder(direction: 'up' | 'down' | 'top' | 'bottom') {
menuVisible.value = false
}
async function takeScreenshot(name: string) {
const stage = await untilNotNull(stageRef)
const nodeTransformer = await untilNotNull(nodeTransformerRef)
await until(() => !loading.value)
async function takeScreenshot(name: string, signal?: AbortSignal) {
const stage = await untilNotNull(stageRef, signal)
const nodeTransformer = await untilNotNull(nodeTransformerRef, signal)
await until(() => !loading.value, signal)
// Omit transform control when taking screenshot
const dataUrl = nodeTransformer.withHidden(() =>
stage.getStage().toDataURL({
Expand Down
4 changes: 2 additions & 2 deletions spx-gui/src/components/navbar/NavbarProfile.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div v-if="!userStore.userInfo" class="sign-in">
<UIButton type="secondary" :disabled="!isOnline" @click="userStore.signInWithRedirection()">{{
<UIButton type="secondary" :disabled="!isOnline" @click="userStore.initiateSignIn()">{{
$t({ en: 'Sign in', zh: '登录' })
}}</UIButton>
</div>
Expand Down Expand Up @@ -56,7 +56,7 @@ function handleProjects() {
<style lang="scss" scoped>
.sign-in,
.avatar {
margin: 0 4px 0 8px;
margin: 0 4px 0 0;
height: 100%;
display: flex;
align-items: center;
Expand Down
8 changes: 7 additions & 1 deletion spx-gui/src/components/project/ProjectItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<li class="project-item">
<RouterLink class="link" :to="to" @click="emit('selected')">
<div class="thumbnail-wrapper">
<UIImg class="thumbnail" :src="project.thumbnail" />
<UIImg class="thumbnail" :src="thumbnailUrl" />
<UIDropdown v-if="context === 'mine'" trigger="click" placement="bottom-end">
<template #trigger>
<div class="options" @click.stop.prevent>
Expand Down Expand Up @@ -59,6 +59,7 @@ import {
} from '@/utils/utils'
import { getProjectEditorRoute, getProjectPageRoute } from '@/router'
import { Visibility, isLiking, type ProjectData } from '@/apis/project'
import { universalUrlToWebUrl } from '@/models/common/cloud'
import { UIImg, UIDropdown, UIIcon, UIMenu, UIMenuItem } from '@/components/ui'
import UserAvatar from '@/components/community/user/UserAvatar.vue'
import { useRemoveProject } from '.'
Expand Down Expand Up @@ -94,6 +95,11 @@ const to = computed(() => {
return props.context === 'edit' ? getProjectEditorRoute(name) : getProjectPageRoute(owner, name)
})
const thumbnailUrl = useAsyncComputed(async () => {
if (props.project.thumbnail === '') return null
return universalUrlToWebUrl(props.project.thumbnail)
})
const liking = useAsyncComputed(() => isLiking(props.project.owner, props.project.name))
const likesTitle = computed(() => {
Expand Down
Loading

0 comments on commit a0eec46

Please sign in to comment.