congzc há 1 ano
ascendente
cometimento
db7ad43c50
16 ficheiros alterados com 285 adições e 53 eliminações
  1. +9
    -0
      .postcssrc.js
  2. +62
    -0
      index.html
  3. +2
    -0
      package.json
  4. BIN
      src/assets/img/aitoface.png
  5. BIN
      src/assets/img/gpttotext.png
  6. +5
    -0
      src/lang/package/en.ts
  7. +5
    -0
      src/lang/package/zh-cn.ts
  8. +5
    -0
      src/layout/components/Sidebar/Logo.vue
  9. +1
    -0
      src/main.ts
  10. +0
    -2
      src/types/auto-imports.d.ts
  11. +2
    -0
      src/types/components.d.ts
  12. +168
    -48
      src/views/createVideo/index.vue
  13. +3
    -2
      src/views/myAccount/index.vue
  14. +3
    -0
      src/views/myCreating/index.vue
  15. +10
    -1
      vite.config.ts
  16. +10
    -0
      yarn.lock

+ 9
- 0
.postcssrc.js Ver ficheiro

@@ -0,0 +1,9 @@
module.exports = {
plugins: {
autoprefixer: {},
'postcss-px2rem-exclude': {
remUnit: 192,//1rem = 75px(iphone6的设计稿如此设置)
// exclude: /node_modules/i //忽略node_modules目录下的文件
}
}
}

+ 62
- 0
index.html Ver ficheiro

@@ -5,6 +5,9 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0" /> -->
<!-- <meta name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"> -->

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Metavatar-PC-Admin</title>
@@ -15,4 +18,63 @@
<script type="module" src="/src/main.ts"></script>
</body>


<script>
//#region 禁用网页滚动
const keyCodeMap = {
// 91: true, // command
61: true,
107: true, // 数字键盘 +
109: true, // 数字键盘 -
173: true, // 火狐 - 号
187: true, // +
189: true, // -
};
// 覆盖ctrl||command + ‘+’/‘-’
document.onkeydown = function (event) {
const e = event || window.event;
const ctrlKey = e.ctrlKey || e.metaKey;
if (ctrlKey && keyCodeMap[e.keyCode]) {
e.preventDefault();
} else if (e.detail) { // Firefox
event.returnValue = false;
}
};
// 覆盖鼠标滑动
document.body.addEventListener('wheel', (e) => {
if (e.ctrlKey) {
if (e.deltaY < 0) {
e.preventDefault();
return false;
}
if (e.deltaY > 0) {
e.preventDefault();
return false;
}
}
}, { passive: false });
//#endregion -----------------------------------

//#region
// $(document).ready(function () {
// initdocument();
// });
// $(window).resize(function () {
// initdocument();
// });
// function initdocument() {
// var devicewidth = document.documentElement.clientWidth
// var deviceheight = document.documentElement.clientHeight
// var width = devicewidth / 1920
// var height = deviceheight / 1080
// document.getElementsByTagName("body")[0].style.transform = 'scale(' + width +
// ',' + height + ')'
// document.getElementsByTagName("body")[0].style.transformOrigin = '0 0'
// }
//#endregion -------------------------



</script>

</html>

+ 2
- 0
package.json Ver ficheiro

@@ -42,6 +42,7 @@
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"@vitejs/plugin-vue": "^4.0.0",
"amfe-flexible": "^2.2.1",
"autoprefixer": "^10.4.13",
"commitizen": "^4.3.0",
"cz-git": "^1.6.1",
@@ -53,6 +54,7 @@
"lint-staged": "^13.2.1",
"postcss": "^8.4.21",
"postcss-html": "^1.5.0",
"postcss-pxtorem": "^6.0.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.7",
"sass": "^1.58.3",


BIN
src/assets/img/aitoface.png Ver ficheiro

Antes Depois
Largura: 80  |  Altura: 80  |  Tamanho: 4.0 KiB

BIN
src/assets/img/gpttotext.png Ver ficheiro

Antes Depois
Largura: 80  |  Altura: 80  |  Tamanho: 9.3 KiB

+ 5
- 0
src/lang/package/en.ts Ver ficheiro

@@ -77,6 +77,8 @@ export default {
GeneratedText:'Generated Text',
SmartText:'Smart Text',
copy:'Copy to text',
tooltip1:'Click to listen',
tooltip2:'Add Pause',
},

// 我的视频
@@ -154,6 +156,9 @@ export default {
VideoResolution:'Video resolution',
DigitalPersonTemplate:'Digital person template',
},
API:{
title:'API Access',
},
signSucceed: {
title: "Confirm your email",
succeed: "Sign Succeed !",


+ 5
- 0
src/lang/package/zh-cn.ts Ver ficheiro

@@ -77,6 +77,8 @@ export default {
GeneratedText:'生成文本',
SmartText:'智能文本',
copy:'复制到文案',
tooltip1:'点击试听',
tooltip2:'添加停顿',
},

// 我的视频
@@ -154,6 +156,9 @@ export default {
VideoResolution:'视频分辨率',
DigitalPersonTemplate:'数字人模版',
},
API:{
title:'API 接口',
},
signSucceed: {
title: "确认邮箱",
succeed: "注册成功",


+ 5
- 0
src/layout/components/Sidebar/Logo.vue Ver ficheiro

@@ -51,11 +51,16 @@ const logo = ref(new URL(`../../../assets/logo.png`, import.meta.url).href);
// https://cn.vuejs.org/guide/built-ins/transition.html#the-transition-component

.left-top-box {
position: relative;
height: 80px;
background-color: #000;
}

.left-top-logo {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 180px;
height: 40px;
padding: 5px 0 0 10px;


+ 1
- 0
src/main.ts Ver ficheiro

@@ -16,6 +16,7 @@ import i18n from "@/lang/index";
import "element-plus/theme-chalk/dark/css-vars.css";
import "@/styles/index.scss";
import "uno.css";
import 'amfe-flexible'
import "@/styles/my.scss"; // 引入自己定义的样式
// 引入组件
import myLoading from "@/components/myLoading.vue";


+ 0
- 2
src/types/auto-imports.d.ts Ver ficheiro

@@ -2,7 +2,6 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
@@ -271,7 +270,6 @@ import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>


+ 2
- 0
src/types/components.d.ts Ver ficheiro

@@ -39,6 +39,8 @@ declare module '@vue/runtime-core' {
IEpDocumentAdd: typeof import('~icons/ep/document-add')['default']
IEpDownload: typeof import('~icons/ep/download')['default']
IEpEdit: typeof import('~icons/ep/edit')['default']
IEpFolder: typeof import('~icons/ep/folder')['default']
IEpFolderAdd: typeof import('~icons/ep/folder-add')['default']
IEpGoods: typeof import('~icons/ep/goods')['default']
IEpHeadset: typeof import('~icons/ep/headset')['default']
IEpLoading: typeof import('~icons/ep/loading')['default']


+ 168
- 48
src/views/createVideo/index.vue Ver ficheiro

@@ -151,7 +151,6 @@
{{ $t("createVideo.availableMould") }}
</div>
<div
v-if="AccessToken"
class="pointer"
:class="showFace == 1 ? 'tabAvtive' : ''"
@click="chooseMyImg"
@@ -159,14 +158,13 @@
{{ $t("createVideo.personalWarehouse") }}
</div>
<div
v-if="AccessToken"
class="pointer aiPicTab"
:class="showFace == 2 ? 'tabAvtive' : ''"
@click="chooseAiPic"
>
<div class="subscript subscript1">
<span>AI &nbsp;</span>
<img src="../../assets/img/star.png" alt="" />
<!-- <span>AI &nbsp;</span> -->
<img src="../../assets/img/aitoface.png" alt="" />
</div>
{{ $t("createVideo.Aipicture") }}
</div>
@@ -245,11 +243,11 @@
</div>
<!-- 右侧栏 -->
<div class="right">
<div v-if="AccessToken" class="subscript">
<span>GPT</span>
<img src="../../assets/img/star.png" alt="" />
<div class="subscript">
<!-- <span>GPT</span> -->
<img src="../../assets/img/gpttotext.png" alt="" />
</div>
<el-tabs type="border-card" class="tabs">
<el-tabs @tab-click="clickTab4" type="border-card" class="tabs">
<!-- ----------------------------- 1 -->
<el-tab-pane :label="$t('createVideo.typeScript')">
<div class="card1">
@@ -263,13 +261,32 @@
type="textarea"
:placeholder="$t('createVideo.aiText')"
/>
<span
class="pointer"
@click="getPreviewAudio"
style="margin-right: 10px; font-size: 20px"
>🔊</span
>
<span class="pointer" @click="insertIcon">🕗</span>
<div class="sundriesBox">
<span class="pointer" @click="getPreviewAudio">
<el-tooltip
class="box-item"
effect="dark"
:content="$t('createVideo.tooltip1')"
placement="top"
>
🔊
</el-tooltip></span
>
<my-Loading-Icon
class="previewAudioLoadingBox"
v-if="previewAudioLoading"
></my-Loading-Icon>
<span class="pointer" @click="insertIcon">
<el-tooltip
class="box-item"
effect="dark"
:content="$t('createVideo.tooltip2')"
placement="bottom"
>
🕗
</el-tooltip></span
>
</div>
</div>
<p>{{ $t("createVideo.languages") }}</p>
<!-- 语言 -->
@@ -309,7 +326,9 @@
<el-option
v-for="item in soundOptions"
:key="item.value"
:label="item.displayName"
:label="
item.displayName + `&nbsp; (${item.sex == 1 ? '男' : '女'})`
"
:value="item.id"
/>
</el-select>
@@ -362,7 +381,7 @@
{{ $t("createVideo.uploadAudio") }}
</p>
<div class="uploadVideo">
+
<el-icon><i-ep-FolderAdd /></el-icon>
<input
accept="audio/*"
type="file"
@@ -435,22 +454,21 @@
<div
class="musicTabItem"
:class="musicTabActive == 1 ? 'musicTabItemActive' : ''"
@click="musicTabActive = 1"
@click="musicTabActiveChange(1)"
>
{{ $t("createVideo.hotMusic") }}
</div>
<div
v-if="AccessToken"
class="musicTabItem"
:class="musicTabActive == 2 ? 'musicTabItemActive' : ''"
@click="musicTabActive = 2"
@click="musicTabActiveChange(2)"
>
{{ $t("createVideo.personalWarehouse") }}
</div>
</div>
<!-- 上传音乐 -->
<div v-if="musicTabActive == 2" class="uploadVideo">
+
<el-icon><i-ep-FolderAdd /></el-icon>
<input
accept="audio/*"
type="file"
@@ -552,7 +570,7 @@
</div>
</el-tab-pane>
<!-- ----------------------- 4 -->
<el-tab-pane v-if="AccessToken" :label="$t('createVideo.aiScript')">
<el-tab-pane :label="$t('createVideo.aiScript')">
<div class="card4">
<!-- 语言 -->
<div class="text">
@@ -566,12 +584,17 @@
:placeholder="$t('createVideo.inputRequirement')"
/>
</div>
<div class="card4Btn" @click="sendRequirement">
<el-button
type="primary"
:disabled="sendLoading"
@click="sendRequirement"
color="#000"
>
<my-Loading-Icon v-if="sendLoading"></my-Loading-Icon>
<span v-if="!sendLoading">
{{ $t("createVideo.GeneratedText") }}
</span>
</div>
</el-button>

<p>{{ $t("createVideo.SmartText") }}</p>
<!-- 语言 -->
@@ -585,9 +608,12 @@
disabled=""
/>
</div>
<div class="card4Btn" @click="copyAnswerContent">
<!-- <div class="card4Btn" @click="copyAnswerContent">
{{ $t("createVideo.copy") }}
</div>
</div> -->
<el-button color="#000" @click="copyAnswerContent">
{{ $t("createVideo.copy") }}
</el-button>
</div>
</el-tab-pane>
<!-- -------------------------脚标 -->
@@ -827,6 +853,10 @@ async function changeFile() {
}
// 点击个人仓库tab
function chooseMyImg() {
if (!AccessToken) {
router.push({ path: "/login" });
return;
}
showFace.value = 1;
showUploadBtn.value = 2;
}
@@ -839,6 +869,10 @@ function clickAddBtn() {

//#region AI生成图片
function chooseAiPic() {
if (!AccessToken) {
router.push({ path: "/login" });
return;
}
showFace.value = 2;
// showUploadBtn.value = 5;
}
@@ -903,13 +937,16 @@ async function chooseStyle() {

// 试听
const previewAudioUrl = ref(null);
const previewAudioLoading = ref(false);
async function getPreviewAudio() {
previewAudioLoading.value = true;
if (!textareaContent.value) {
ElMessage.error(
lanChange.value == "zh-cn"
? `您还没有输入文案`
: `You have not entered the copy yet`
);
previewAudioLoading.value = false;
return;
}
if (!sound.value) {
@@ -918,6 +955,7 @@ async function getPreviewAudio() {
? `您还没有选择声音`
: `You have not selected the sound`
);
previewAudioLoading.value = false;
return;
}

@@ -930,19 +968,27 @@ async function getPreviewAudio() {
if (!res.data.data) {
ElMessage.error(
lanChange.value == "zh-cn"
? `暂时无法试听,请稍后重试`
? `暂时无法试听,请稍后重试1`
: `Unable to listen, please try again later`
);
previewAudioLoading.value = false;
return;
}
previewAudioUrl.value = res.data.data;
let audioA = document.getElementById("audio").play();
audioA.play();
let audioA = document.getElementById("audio");
audioA.addEventListener("loadedmetadata", function () {
audioA.play();
});

previewAudioLoading.value = false;
} catch (error) {
ElMessage.error(
lanChange.value == "zh-cn"
? `暂时无法试听,请稍后重试`
? `暂时无法试听,请稍后重试2`
: `Unable to listen, please try again later`
);
previewAudioLoading.value = false;
return;
}
}
//#endregion
@@ -1025,11 +1071,35 @@ const handleFileChange = async () => {

if (file) {
const videoUrl = URL.createObjectURL(file);
audioUrl.value = videoUrl;
audioData.value = file;
const audio2 = new Audio();
audio2.src = videoUrl;
countAudioTime(audio2);
// 进行大小时长限制
await countAudioTime(audio2);
// 限制60秒
if (uploadAudioTime.value > 60) {
ElMessage.error(
lanChange.value == "zh-cn"
? `上传失败,您上传的文件时长与您的权益不匹配`
: `The upload failed because the duration of the file you uploaded did not match your entitlements`
);
audioUrl.value = null;
audioData.value = null;
return;
}
// 限制3mb
if (file.size / 1048576 > 3) {
ElMessage.error(
lanChange.value == "zh-cn"
? `上传失败,您上传的文件大小与您的权益不匹配`
: `Upload failed, the file size you uploaded does not match your entitlements`
);
audioUrl.value = null;
audioData.value = null;
return;
}
// 成功了
audioUrl.value = videoUrl;
audioData.value = file;
}
};
// 计算音频的时长
@@ -1265,9 +1335,9 @@ async function findById(findId) {
}
//#endregion ----------------------------

//#region 音乐tab
const musicListSystem = ref(null); //展示音乐列表
const musicListPerson = ref(null); //展示音乐列表
//#region card3
const musicListSystem = ref([]); //展示系统音乐列表
const musicListPerson = ref([]); //展示个人音乐列表
const audioMusicUrl = ref(null); //选中音乐Url回显
const musicItemAction = ref(null); //选中高亮
const musicListPageNumSystem = ref(1); //系统音乐页数
@@ -1278,6 +1348,16 @@ const musicListPageSize = ref(8); //
const musicTabActive = ref(1); //热门歌曲和个人仓库高亮
const musicData = ref(null); //上传歌曲的数据
const fileMusicInput = ref(null); // 上传组件的dom
// tab切换
function musicTabActiveChange(index) {
if (index == 2) {
if (!AccessToken) {
router.push({ path: "/login" });
return;
}
}
musicTabActive.value = index;
}
// 获取系统音乐列表
async function getmusicListSystem(pageNum, pageSize) {
try {
@@ -1404,6 +1484,16 @@ const problemContent = ref(null);
const answerContent = ref("");
let mySocket = null;
const sendLoading = ref(false);
// 没有登录时跳转登录页
function clickTab4(e) {
if (e.props.label == "AI生成文本" || e.props.label == "AI Script") {
if (!AccessToken) {
router.push({ path: "/login" });
return;
}
}
}
// 创建websocket
function createWS() {
mySocket = new WebSocket("wss://gptsocket.malls.iformall.com:8010");
mySocket.onopen = () => {
@@ -1441,11 +1531,11 @@ function createWS() {
// 点击发送需求
async function sendRequirement() {
// loading
if (sendLoading.value) {
return;
}
sendLoading.value = true;

// 无需求时
if (!problemContent.value) {
sendLoading.value = false;
mySocket.close();
return;
}
@@ -1455,12 +1545,12 @@ async function sendRequirement() {
content: problemContent.value,
},
];
// 如果处于链接状态

if (mySocket.readyState != WebSocket.OPEN) {
createWS();
} else {
answerContent.value = "";
sendLoading.value = true;
mySocket.send(JSON.stringify(sendMessage));
}
}
@@ -1528,9 +1618,9 @@ onUnmounted(() => {

<style lang="scss" scoped>
.page {
// height: 1200px;

// height: 1000px;
height: calc(100vh - 80px);
height: 1000px;
// padding: 20px 0 0 40px;
background-color: #fff;
border-radius: 25px 0 0;
@@ -1538,7 +1628,8 @@ onUnmounted(() => {

.left {
width: 68%;
height: 860px;
// height: 860px;
height: 1000px;
padding: 20px;
:deep(.el-input__wrapper) {
border: none;
@@ -1891,7 +1982,8 @@ onUnmounted(() => {
right: -20px;
width: 40px;
height: 40px;
z-index: 1;
z-index: 3;
background-color: #fff;
img {
position: absolute;
top: 0;
@@ -1918,7 +2010,8 @@ onUnmounted(() => {
right: -20px;
width: 40px;
height: 40px;
z-index: 1;
z-index: 3;
transform: rotate(45deg);
img {
position: absolute;
top: 0;
@@ -1945,7 +2038,8 @@ onUnmounted(() => {

.right {
width: 32%;
height: 860px;
// height: 860px;
height: 1000px;
padding: 30px 30px 20px 30px;
background-color: #f1f2f6;
border-radius: 30px 0 0 0;
@@ -1959,6 +2053,7 @@ onUnmounted(() => {
width: 40px;
height: 40px;
z-index: 3;
transform: rotate(45deg);
img {
position: absolute;
top: 0;
@@ -2013,7 +2108,28 @@ onUnmounted(() => {
height: 50px;
margin-top: 10px;
}

.sundriesBox {
width: 100%;
height: 30px;
line-height: 30px;
overflow: hidden;
span {
display: inline-block;
font-size: 20px;
height: 30px;
width: 30px;
text-align: center;
width: 40px;
}
.previewAudioLoadingBox {
display: inline-block;
margin-top: -20px;
width: 20px;
height: 33px;
transform: scale(1);
transition: all 0.3s;
}
}
:deep(.el-input .is-focus) {
// box-shadow: none !important;
// box-shadow: 0 0 0 1px #000 !important;
@@ -2230,7 +2346,6 @@ onUnmounted(() => {
width: 100%;
height: 50px;
margin-top: 10px;
// background-color: #000;
}
:deep(.el-input__wrapper) {
border: none;
@@ -2283,6 +2398,11 @@ onUnmounted(() => {
line-height: 50px;
cursor: pointer;
}
.el-button {
width: 100%;
height: 50px;
margin-top: 10px;
}
}
:deep(.el-tabs__item.is-active) {
color: #909393;


+ 3
- 2
src/views/myAccount/index.vue Ver ficheiro

@@ -486,6 +486,7 @@ function routerTo(url) {
&-two {
position: relative;
height: 80px;
text-align: center;
overflow: hidden;

.number {
@@ -494,8 +495,8 @@ function routerTo(url) {
}

.time {
position: absolute;
right: 90px;
// position: absolute;
// right: 90px;
}

.getMore {


+ 3
- 0
src/views/myCreating/index.vue Ver ficheiro

@@ -371,6 +371,8 @@ onMounted(() => {
padding: 15px 130px;
background-color: #fff;
border-radius: 25px 0 0;
width: 100%;
overflow: hidden;
.top {
margin-bottom: 35px;
}
@@ -379,6 +381,7 @@ onMounted(() => {
line-height: 100px;
text-align: center;
transform: scale(2);

.loadingText {
position: relative;
top: -2px;


+ 10
- 1
vite.config.ts Ver ficheiro

@@ -10,7 +10,7 @@ import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";

import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import postCssPxToRem from 'postcss-pxtorem'
import UnoCSS from "unocss/vite";

import path from "path";
@@ -36,6 +36,15 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
`,
},
},
postcss: {
plugins: [
postCssPxToRem({
rootValue: 192, // 1rem 的大小
propList: ['*'], // 需要转换的属性,*(全部转换)
unitPrecision: 6 // 转换精度,保留的小数位数
})
]
}
},
server: {
host: "0.0.0.0",


+ 10
- 0
yarn.lock Ver ficheiro

@@ -1492,6 +1492,11 @@ ajv@^8.0.1, ajv@^8.11.0:
require-from-string "^2.0.2"
uri-js "^4.2.2"

amfe-flexible@^2.2.1:
version "2.2.1"
resolved "https://registry.npmmirror.com/amfe-flexible/-/amfe-flexible-2.2.1.tgz#353f00289e4d38ca88a21eb3854420308af0b559"
integrity sha512-L2VfvDzoETBjhRptg5u/IUuzHSuxm22JpSRb404p/TBGeRfwWmmNEbB+TFPIP/sS/+pbM18bCFH9QnMojLuPNw==

ansi-escapes@^4.2.1, ansi-escapes@^4.3.0:
version "4.3.2"
resolved "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
@@ -4799,6 +4804,11 @@ postcss-prefix-selector@^1.6.0:
resolved "https://registry.npmmirror.com/postcss-prefix-selector/-/postcss-prefix-selector-1.16.0.tgz"
integrity sha512-rdVMIi7Q4B0XbXqNUEI+Z4E+pueiu/CS5E6vRCQommzdQ/sgsS4dK42U7GX8oJR+TJOtT+Qv3GkNo6iijUMp3Q==

postcss-pxtorem@^6.0.0:
version "6.0.0"
resolved "https://registry.npmmirror.com/postcss-pxtorem/-/postcss-pxtorem-6.0.0.tgz#f228a4d05d8a73f0642eabae950e2b19836366d7"
integrity sha512-ZRXrD7MLLjLk2RNGV6UA4f5Y7gy+a/j1EqjAfp9NdcNYVjUMvg5HTYduTjSkKBkRkfqbg/iKrjMO70V4g1LZeg==

postcss-resolve-nested-selector@^0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz"


Carregando…
Cancelar
Guardar