Merge branch 'master' of http://git.luyuan.tk/luyuan/beelink into zj

This commit is contained in:
asd 2020-09-27 10:56:38 +08:00
commit 92d255683c
14 changed files with 14645 additions and 11 deletions

13709
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
"ant-design-vue": "^2.0.0-beta.9", "ant-design-vue": "^2.0.0-beta.9",
"axios": "^0.20.0", "axios": "^0.20.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"postcss-pxtorem": "^5.1.1",
"vue": "^3.0.0-0", "vue": "^3.0.0-0",
"vue-router": "^4.0.0-0", "vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0" "vuex": "^4.0.0-0"

View File

@ -6,6 +6,60 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
<script>
//designWidth:设计稿的实际宽度值,需要根据实际设置
//maxWidth:制作稿的最大宽度值,需要根据实际设置
//这段js的最后面有两个参数记得要设置一个为设计稿实际宽度一个为制作稿最大宽度例如设计稿为750最大宽度为750则为(750,750)
(function (designWidth, maxWidth) {
var doc = document,
win = window,
docEl = doc.documentElement,
remStyle = document.createElement("style"),
tid;
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
// maxWidth = maxWidth || 540; //不需要判断最大宽度
// width > maxWidth && (width = maxWidth);
var rem = width * 100 / designWidth;
console.log(rem)
remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
}
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(remStyle);
} else {
var wrap = doc.createElement("div");
wrap.appendChild(remStyle);
doc.write(wrap.innerHTML);
wrap = null;
}
//要等 wiewport 设置好后才能执行 refreshRem不然 refreshRem 会执行2次
refreshRem();
win.addEventListener("resize", function () {
clearTimeout(tid); //防止执行两次
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener("pageshow", function (e) {
if (e.persisted) { // 浏览器后退的时候重新计算
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === "complete") {
doc.body.style.fontSize = "16px";
} else {
doc.addEventListener("DOMContentLoaded", function (e) {
doc.body.style.fontSize = "16px";
}, false);
}
})(1366, 1024);
</script>
</head> </head>
<body> <body>
<noscript> <noscript>

View File

@ -1,13 +1,16 @@
<template> <template>
<!-- <div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div> -->
<router-view/> <router-view/>
</template> </template>
<script lang="ts"> <style lang="scss">
import { defineComponent } from 'vue'; .one-line-hide {
export default defineComponent({ overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
})
</script>
<style lang="scss" scoped>
</style> </style>

View File

@ -35,7 +35,7 @@
.menu{ .menu{
user-select: none; user-select: none;
width: 171px; width: 171px;
height: 100vh; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: linear-gradient(0deg, #0EDCC2, #50DF98, #7EE278, #A2E562); background: linear-gradient(0deg, #0EDCC2, #50DF98, #7EE278, #A2E562);
@ -43,6 +43,7 @@
width: 100%; width: 100%;
height: 150px; height: 150px;
display: flex; display: flex;
flex-shrink: 0;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -127,6 +128,7 @@ export default defineComponent({
name: string; name: string;
route: string; route: string;
} }
//
const list: Array<MenuItem> = [ const list: Array<MenuItem> = [
{ {
icon: "", icon: "",
@ -159,8 +161,13 @@ export default defineComponent({
route: "" route: ""
} }
] ]
// index
const selnum = ref(0); const selnum = ref(0);
const routeto = (index: number) => { /**
* 跳转路由与赋值对应的下标
* @param index 选中的下标 方便赋值与跳转
*/
function routeto(index: number): void {
console.log(index) console.log(index)
selnum.value = index; selnum.value = index;

View File

@ -0,0 +1,80 @@
<template>
<div class="nav-bottom">
<div class="nav-container">
<div v-for="(item, index) in navArray" :key="index" class="nav-item">{{ item.name }}</div>
</div>
<div class="copyright">Beelink公司版权所有 20192022</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NavBottom',
setup(){
interface Nav{
name: string;
route: string;
}
const navArray: Array<Nav> = [
{
name: "直播管理",
route: ""
},
{
name: "视频管理",
route: ""
},
{
name: "订阅者管理",
route: ""
},
{
name: "个人中心",
route: ""
}
]
return {
navArray
}
}
})
</script>
<style lang="scss" scoped>
.nav-bottom {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.nav-container {
display: flex;
align-items: center;
margin-bottom: 10px;
font-size: 10px;
font-weight: 500;
color: #404040;
.nav-item {
padding: 0 14px;
position: relative;
&:not(:last-child)::after {
content: "";
position: absolute;
right: 0px;
top: 50%;
width: 1px;
height: 10px;
background: #404040;
transform: translate(0, -50%);
}
}
}
.copyright {
font-size: 9px;
font-weight: 500;
color: #808080;
}
}
</style>

151
src/components/NavTop.vue Normal file
View File

@ -0,0 +1,151 @@
<template>
<div class="nav">
<div class="logo">
<img src="" alt="" class="img">
<div class="title">Beelink</div>
</div>
<div class="navigation">
<div class="item" v-for="(i,j) in nav" :key="j">
{{i.name}}
</div>
</div>
<div style="width: 100%"></div>
<div class="setting">
<div class="item">
<img src="" alt="" class="icon">
<div class="name">北京 GMT +08:00</div>
<img src="" alt="" class="down">
</div>
<div class="item">
<img src="" alt="" class="icon">
<div class="name">人民币</div>
<img src="" alt="" class="down">
</div>
<div class="item">
<img src="" alt="" class="icon">
<div class="name">中文</div>
<img src="" alt="" class="down">
</div>
<div class="item">
<img src="" alt="" class="icon">
<div class="name">日历</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.nav{
display: flex;
background-color: #fff;
min-width: 1366px;
user-select: none;
.logo{
width: 171px;
height: 57px;
background-color: #06C7AE;
display: flex;
align-items: center;
flex-shrink: 0;
.img{
width: 38px;
height: 38px;
background-color: #0f0;
margin-left: 14px;
border-radius: 50%;
}
.title{
margin-left: 9px;
font-size: 17px;
color: #fff;
}
}
.navigation{
display: flex;
align-items: center;
flex-shrink: 0;
margin-left: 28px;
.item{
padding: 0 28px;
height: 18px;
border-right: 1px solid #eee;
font-size: 11px;
color: #111;
font-weight: bold;
&:last-child{
border-right: none;
}
}
}
.setting{
display: flex;
align-items: center;
flex-shrink: 0;
padding: 0 16px;
.item{
display: flex;
align-items: center;
border-right: 1px solid #eee;
padding: 0 23px;
height: 18rpx;
&:last-child{
border-right: none;
}
.icon{
width: 16px;
height: 16px;
background-color: #0f0;
}
.name{
margin-left: 6px;
font-size: 11px;
color: #111;
font-weight: bold;
}
.down{
width: 9px;
height: 5px;
margin-left: 20px;
background-color: #0f0;
}
}
}
}
</style>
<script lang="ts">
import { defineComponent } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
setup(){
// console.log(useRoute().currentRoute.value.name)
const routes = useRoute();
console.log(routes.path);
interface Nav{
name: string;
route: string;
}
const nav: Array<Nav> = [
{
name: "直播管理",
route: ""
},
{
name: "视频管理",
route: ""
},
{
name: "订阅者管理",
route: ""
},
{
name: "个人中心",
route: ""
}
]
return {
nav
}
}
})
</script>

55
src/layout/Mine.vue Normal file
View File

@ -0,0 +1,55 @@
<template>
<div class="mine" :style="{height:height + 'px'}">
<NavTop style="flex-shrink:0"></NavTop>
<div class="body">
<Menu></Menu>
<div class="container">
<router-view/>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.mine{
display: flex;
flex-direction: column;
.body{
display: flex;
width: 100%;
min-width: 1366px;
height: calc(100% - 57px);
.container{
width: calc(100% - 171px);
height: 100%;
overflow: auto;
background-color: #F5F5F5;
padding: 23px;
}
}
}
</style>
<script lang="ts">
import { defineComponent, onMounted, ref } from 'vue';
import Menu from "@/components/Menu.vue";
import NavTop from "@/components/NavTop.vue"
export default defineComponent({
components:{
Menu,
NavTop
},
setup(){
console.log(1)
const height = ref(0);
onMounted(() => {
height.value = document.documentElement.clientHeight;
})
window.onresize=function(){
height.value = document.documentElement.clientHeight;
}
return {
height
}
}
})
</script>

View File

@ -3,10 +3,21 @@ import Home from '../views/Home.vue'
import Login from "../views/login/Login.vue" import Login from "../views/login/Login.vue"
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
{
path:"/mine",
name:"Mine",
component: () => import("../layout/Mine.vue"),
children: [
{
path:"Archives",
component: () => import("../views/mine/Archives.vue")
}
]
},
{ {
path: '/', path: '/',
name: 'Home', name: 'Home',
component: () => import(/* webpackChunkName: "about" */ '../components/Menu.vue') component: () => import(/* webpackChunkName: "about" */ '../components/NavTop.vue')
}, },
// { // {
@ -17,11 +28,16 @@ const routes: Array<RouteRecordRaw> = [
// // which is lazy-loaded when the route is visited. // // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// } // }
{
path: '/archives',
name: 'Archives',
component: () => import('../views/mine/Archives.vue')
},
{ {
path: '/login', path: '/login',
name: 'Login', name: 'Login',
component:Login component:Login
}, }
] ]
const router = createRouter({ const router = createRouter({

437
src/views/mine/Archives.vue Normal file
View File

@ -0,0 +1,437 @@
<template>
<div class="archives">
<div class="user-info">
<div class="avatar">
<a-avatar :size="85" shape="circle" src="https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_40c4f13.svg">
<template v-slot:icon><UserOutlined /></template>
</a-avatar>
<div class="user-name">
<div class="value">{{ formData.name }}</div>
<div class="update-btn" @click="updateUserName">修改</div>
</div>
</div>
<div class="form-box basic">
<div class="title">基本信息</div>
<div class="main-container">
<div class="input-box country">
<div class="label">来自国家</div>
<a-select
v-model:value="formData.country"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['美国', '英国']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
<div class="input-box address">
<div class="label">居住地</div>
<a-input size="small" v-model:value="formData.address" placeholder="请输入居住地" />
</div>
<div class="input-box teach-lang">
<div class="label">授课语言</div>
<a-select
v-model:value="formData.teachingLang"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['英语', '法语']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
<div class="input-box speak-lang">
<div class="label">我还会说</div>
<div class="speak-array">
<div class="lang-items">
<div class="speak-item" v-for="(lang, index) in formData.speakLang" :key="index">
<a-select
v-model:value="lang.lang"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['英语', '法语']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
<div class="proficiency">
<div class="p-title">熟练度</div>
<div class="value">
<a-rate v-model:value="lang.proficiency" style="fontSize: 15px">
<template v-slot:character><SmileOutlined /></template>
</a-rate>
</div>
</div>
</div>
</div>
<div class="update-btn" @click="addSpeakLang">继续添加</div>
</div>
</div>
<div class="input-box native-lang">
<div class="label">母语</div>
<a-select
v-model:value="formData.nativeLang"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['英语', '法语']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
<div class="input-box video-lang">
<div class="label">短视频</div>
<a-upload
list-type="picture"
action="//jsonplaceholder.typicode.com/posts/"
>
<div class="upload-image">
<PlaySquareOutlined style="fontSize: 22px;" />
</div>
</a-upload>
<div class="demand">
<p class="one-line-hide">视频要求</p>
<p class="one-line-hide"> 1.上传视频时间要求为30s之内</p>
<p class="one-line-hide">2.支持文件大小100M</p>
<p class="one-line-hide">3.文件扩展名fivmp4文件扩展名fivmp4</p>
</div>
</div>
<div class="input-box introduce">
<div class="label">自我介绍</div>
<a-textarea v-model:value="formData.introduce" />
</div>
</div>
</div>
<div class="form-box contact">
<div class="title">联系方式</div>
<div class="main-container">
<div class="input-box mailbox">
<div class="label">邮箱</div>
<a-input size="small" v-model:value="formData.mail" placeholder="请输入邮箱" />
</div>
<div class="input-box phone-box">
<div class="label">手机号</div>
<div class="phone">{{ formData.phone }}</div>
<div class="update-btn" @click="updatePhoneNumber">更换手机号</div>
</div>
</div>
</div>
<div class="form-box system-setting">
<div class="title">系统设置</div>
<div class="main-container">
<div class="input-box password-box">
<div class="label">密码</div>
<div class="password">{{ formData.password }}</div>
<div class="update-btn" @click="updateUserPassword">修改密码</div>
</div>
<div class="input-box time-zone-box">
<div class="label">时区</div>
<a-select
v-model:value="formData.timeZone"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['北京 GMT +08:00']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
<div class="input-box currency-box">
<div class="label">货币</div>
<a-select
v-model:value="formData.currency"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['人民币']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
<div class="input-box time-zone">
<div class="label">语言</div>
<a-select
v-model:value="formData.language"
style="width: 171px"
size="small"
ref="select"
:getPopupContainer="triggerNode => triggerNode.parentNode"
>
<a-select-option v-for="(item, index) in ['英语', '中文']" :key="index" :value="item">
{{ item }}
</a-select-option>
</a-select>
</div>
</div>
</div>
<div class="submit-btn" @click="submitInfo">保存信息</div>
</div>
<nav-bottom></nav-bottom>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
import { UserOutlined, SmileOutlined, PlaySquareOutlined } from '@ant-design/icons-vue';
import NavBottom from '@/components/NavBottom.vue';
export default defineComponent({
name: "Archives",
components: {
UserOutlined,
SmileOutlined,
PlaySquareOutlined,
NavBottom
},
setup(){
interface SpeakItem{
lang: string;
proficiency: number;
}
const otherSpeak: Array<SpeakItem> = [{
lang: '请选择',
proficiency: 0,
}];
const formBasic = {
name: 'Lorem Sum',
country: '美国',
address: '',
teachingLang: '英语',
speakLang: otherSpeak,
nativeLang: '英语',
shortVideo: '',
introduce: '',
mail: '',
phone: '136 **** 6111',
password: '***********',
timeZone: '北京 GMT +08:00',
currency: '人民币',
language: '中文',
}
//
const formData = reactive(formBasic);
/**
* 修改用户名
* @return { void }
*/
function updateUserName (): void {
console.log('修改');
}
/**
* 添加我还会说语言
* @return { void }
*/
function addSpeakLang (): void {
formData.speakLang.push({
lang: '请选择',
proficiency: 0,
});
}
/**
* 修改手机号
* @return { void }
*/
function updatePhoneNumber (): void {
console.log('修改手机号');
}
/**
* 修改密码
* @return { void }
*/
function updateUserPassword(): void {
console.log('修改密码');
}
/**
* 提交表单
* @return { void }
*/
function submitInfo (): void {
console.log('12');
}
return {
formData,
updateUserName,
addSpeakLang,
updatePhoneNumber,
updateUserPassword,
submitInfo,
}
}
});
</script>
<style lang="scss" scoped>
.archives {
width: 100%;
min-width: 700px;
background-color: #ffffff;
padding: 46px;
border-radius: 17px;
position: relative;
.update-btn {
font-size: 11px;
color: #08AE98;
font-weight: 500;
cursor: pointer;
user-select: none;
}
.user-info {
margin-bottom: 42px;
.avatar {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 30px;
.user-name {
display: flex;
align-items: flex-end;
margin-top: 11px;
font-weight: bold;
.value {
font-size: 17px;
color: #111111;
margin-right: 10px;
}
}
}
.form-box {
margin-bottom: 20px;
.title {
font-size: 11px;
font-weight: bold;
color: #111111;
margin-bottom: 28px;
}
.main-container {
margin-left: 17px;
.input-box {
display: flex;
align-items: center;
margin-bottom: 28px;
.label {
width: 60px;
font-size: 11px;
font-weight: 500;
color: #808080;
margin-right: 30px;
line-height: 23px;
align-self: flex-start;
}
.ant-input {
width: 171px;
padding: 6px 11px;
border-radius: 3px;
border: 1px solid #DCDFE0;
font-size: 11px;
}
.ant-select {
font-size: 12px;
}
.select-down {
font-size: 12px;
}
}
.speak-lang {
.speak-array {
display: flex;
.lang-items {
.speak-item {
display: flex;
align-items: center;
&:not(:last-child) {
margin-bottom: 28px;
}
.proficiency {
margin: 0 107px 0 17px;
display: flex;
align-items: center;
.p-title {
font-size: 11px;
font-weight: 500;
color: #808080;
margin-right: 14px;
}
}
}
}
.update-btn {
align-self: flex-end;
}
}
}
.video-lang {
.upload-image {
width: 171px;
height: 96px;
border: 1px solid #DCDFE0;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 17px;
}
.demand {
line-height: 17px;
font-size: 10px;
font-weight: 500;
color: #808080;
width: 134px;
p {
margin: 0;
}
}
}
.introduce {
.ant-input {
width: 359px;
}
}
.phone-box {
.phone {
font-size: 11px;
font-weight: bold;
color: #404040;
margin-right: 112px;
}
}
.password-box {
.password {
margin-right: 123px;
}
}
}
}
.submit-btn {
width: 63px;
height: 23px;
background: #08AE98;
border-radius: 3px;
font-size: 10px;
font-weight: 500;
color: #FFFFFF;
text-align: center;
line-height: 23px;
cursor: pointer;
user-select: none;
}
}
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<div class="webcast">
<a-form :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="Activity name">
<a-input v-model:value="form.name" />
</a-form-item>
<a-form-item label="Activity zone">
<a-select v-model:value="form.region" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Activity time">
<a-date-picker
v-model:value="form.date1"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-item>
<a-form-item label="Instant delivery">
<a-switch v-model:checked="form.delivery" />
</a-form-item>
<a-form-item label="Activity type">
<a-checkbox-group v-model:value="form.type">
<a-checkbox value="1" name="type">
Online
</a-checkbox>
<a-checkbox value="2" name="type">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-item>
<a-form-item label="Resources">
<a-radio-group v-model:value="form.resource">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="Activity form">
<a-input v-model:value="form.desc" type="textarea" />
</a-form-item>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="onSubmit">
Create
</a-button>
<a-button style="margin-left: 10px;">
Cancel
</a-button>
</a-form-item>
</a-form>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'ReleaseWebcast',
setup() {
function onSubmit(): void {
}
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
form: {
name: '',
region: undefined,
date1: undefined,
delivery: false,
type: [],
resource: '',
desc: '',
},
onSubmit
}
}
})
</script>
<style lang="scss" scoped>
</style>

0
static/js/common.ts Normal file
View File

22
vue.config.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-pxtorem')({ // 把px单位换算成rem单位
rootValue: 100, // 换算的基数(设计图750的根字体为32)
selectorBlackList: ['weui', 'mu'], // 忽略转换正则匹配项
propList: ['*']
})
]
}
}
},
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
}
}

View File

@ -7235,6 +7235,13 @@ postcss-ordered-values@^4.1.2:
postcss "^7.0.0" postcss "^7.0.0"
postcss-value-parser "^3.0.0" postcss-value-parser "^3.0.0"
postcss-pxtorem@^5.1.1:
version "5.1.1"
resolved "https://registry.npm.taobao.org/postcss-pxtorem/download/postcss-pxtorem-5.1.1.tgz#198a68c10f9ad2d42370ef66299d7b3168f8cffa"
integrity sha1-GYpowQ+a0tQjcO9mKZ17MWj4z/o=
dependencies:
postcss "^7.0.27"
postcss-reduce-initial@^4.0.3: postcss-reduce-initial@^4.0.3:
version "4.0.3" version "4.0.3"
resolved "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" resolved "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df"