This commit is contained in:
lightings 2023-02-15 14:37:28 +08:00
parent 7e89c9dadb
commit 5e1cec03e6
37 changed files with 5955 additions and 217 deletions

37
.gitignore vendored
View File

@ -4,4 +4,39 @@
node_modules
logs/
dist/
tests_output/
tests_output/
node_modules
.env
coverage
coverage.json
typechain
typechain-types
# Hardhat files
cache
artifacts
node_modules
.env
coverage
coverage.json
typechain
typechain-types
# Hardhat files
cache
artifacts
node_modules
.env
coverage
coverage.json
typechain
typechain-types
# Hardhat files
cache
artifacts

View File

@ -1,24 +1,13 @@
# gamesns
# Sample Hardhat Project
## Project setup
```
npm install
```
This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract.
### Compiles and hot-reloads for development
```
npm run serve
```
Try running some of the following tasks:
### Compiles and minifies for production
```shell
npx hardhat help
npx hardhat test
REPORT_GAS=true npx hardhat test
npx hardhat node
npx hardhat run scripts/deploy.js
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

2
components.d.ts vendored
View File

@ -14,6 +14,8 @@ declare module '@vue/runtime-core' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SmallTag: typeof import('./src/components/SmallTag.vue')['default']
TestView: typeof import('./src/components/TestView.vue')['default']
TestViewO: typeof import('./src/components/TestViewO.vue')['default']
UserCard: typeof import('./src/components/UserCard.vue')['default']
}
}

34
contracts/Lock.sol Normal file
View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
// Uncomment this line to use console.log
// import "hardhat/console.sol";
contract Lock {
uint public unlockTime;
address payable public owner;
event Withdrawal(uint amount, uint when);
constructor(uint _unlockTime) payable {
require(
block.timestamp < _unlockTime,
"Unlock time should be in the future"
);
unlockTime = _unlockTime;
owner = payable(msg.sender);
}
function withdraw() public {
// Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
// console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);
require(block.timestamp >= unlockTime, "You can't withdraw yet");
require(msg.sender == owner, "You aren't the owner");
emit Withdrawal(address(this).balance, block.timestamp);
owner.transfer(address(this).balance);
}
}

0
docs/test.drawio Normal file
View File

6
hardhat.config.js Normal file
View File

@ -0,0 +1,6 @@
require("@nomicfoundation/hardhat-toolbox");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.17",
};

3529
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
"pinia": "^2.0.23",
"process": "^0.11.10",
"style-resources-loader": "^1.5.0",
"swiper": "^9.0.3",
"util": "^0.12.5",
"vue": "^3.2.13",
"vue-router": "^4.1.6",
@ -42,6 +43,7 @@
"@emotion/is-prop-valid": "^1.2.0",
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"@nightwatch/vue": "^0.4.1",
"@nomicfoundation/hardhat-toolbox": "^2.0.1",
"@rollup/plugin-alias": "^4.0.2",
"@vitejs/plugin-vue": "^3.2.0",
"browserify-zlib": "^0.2.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/images/hero_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
public/images/service1.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

31
scripts/deploy.js Normal file
View File

@ -0,0 +1,31 @@
// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat
// will compile your contracts, add the Hardhat Runtime Environment's members to the
// global scope, and execute the script.
const hre = require("hardhat");
async function main() {
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const unlockTime = currentTimestampInSeconds + ONE_YEAR_IN_SECS;
const lockedAmount = hre.ethers.utils.parseEther("1");
const Lock = await hre.ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
await lock.deployed();
console.log(
`Lock with 1 ETH and unlock timestamp ${unlockTime} deployed to ${lock.address}`
);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

View File

@ -10,12 +10,14 @@
<a-menu-item key="/users">Users</a-menu-item>
</a-menu>
</a-col>
<a-button type="primary" @click="login">{{ chain.logined ? "Logout" : "Login" }}</a-button>
<a-avatar v-if="chain.logined" class="headpic" :src="getMyUserInfo().headpic" shape="circle" @click="showUserProfile"/>
<a-button v-else type="primary" @click="login">Login</a-button>
</a-row>
<chain-model></chain-model>
</a-layout-header>
<a-layout-content :style="{ padding: '0px', marginTop: '64px' }">
<router-view/>
<a-drawer placement="right" :closable="false" :visible="visableDrawer" @close="onCloseDrawer"></a-drawer>
</a-layout-content>
<a-layout-footer>
footer
@ -26,12 +28,17 @@
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useChainStore } from '@/store/chain';
import { useAppStore } from '@/store/app';
import ChainModel from '@/components/ChainModel'
const router = useRouter();
const chain = useChainStore();
const app = useAppStore();
const visableDrawer = ref(false);
function click(event) {
router.push(event.key);
@ -53,6 +60,25 @@ async function login(event) {
}
}
function getMyUserInfo() {
const info = app.get(app.accountId);
if (!info) {
return {
head_pic: ""
}
}
return info;
}
async function showUserProfile(event) {
visableDrawer.value = true;
}
function onCloseDrawer(event) {
visableDrawer.value = false;
}
</script>
<style lang=less>
@ -60,11 +86,6 @@ async function login(event) {
@import 'ant-design-vue/dist/antd.dark.less';
@import './css/main.less';
@font-face {
font-family: Poppins;
src: url(./assets/fonts/Poppins-Bold.ttf);
}
.ant-menu {
font-size: 1.5vmax;
}

View File

@ -1,9 +1,34 @@
<template>
<div>
GPalMenuItem<br/>
ffaa
</div>
<div class="main">
<img src="/images/service1.webp"/>
<div class="content">
League of Legends<br/>
10% OFF<br/>
1.80 2.00/Game
</div>
</div>
</template>
<script setup>
</script>
</script>
<style lang="less" scoped>
.main {
padding: 0.8vmax;
display: flex;
font-size: 1.2vmax;
line-height: 2vmax;
}
.content {
padding-left: 1vmax;
display: block;
}
img {
width: 4vmax;
height: 4vmax;
border-radius: 0.8vmax;
display: block;
}
</style>

131
src/components/TestView.vue Normal file
View File

@ -0,0 +1,131 @@
<template>
<div class="big_hero">
<swiper
@swiper="setHeroSwiper"
:slides-per-view="1"
:thumbs="{ swiper: heroThumbsSwiper }"
:modules="modules"
:navigation="{ nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }"
@slideChange="onSlideChange"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<img class="hero_big_image" :src="slideContent.img"/>
</SwiperSlide>
</swiper>
</div>
<div class="thumbs_hero_container">
<Swiper
@swiper="setHeroThumbsSwiper"
:slides-per-view="4"
:modules="modules"
class="HeroThumbs"
:slideToClickedSlide="true"
:centeredSlidesBounds="true"
:multipleActiveThumbs="false"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<div class="hero_thumb">
<img class="hero_thumb_img" :src="slideContent.img"/>
<img v-if="test(index, slideContent)" class="hero_thumb_bg" src="/images/hero_bg.png"/>
</div>
</SwiperSlide>
</Swiper>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { Thumbs, FreeMode, Navigation } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/thumbs';
import 'swiper/css/free-mode';
const heroList = ref([
{ id:1, img:location.origin+'/images/v1.jpg' },
{ id:2, img:location.origin+'/images/v2.jpg' },
{ id:3, img:location.origin+'/images/v3.jpg' },
{ id:4, img:location.origin+'/images/v4.jpg' },
{ id:5, img:location.origin+'/images/v5.jpg' },
{ id:6, img:location.origin+'/images/v1.jpg' },
]);
const modules = [FreeMode, Navigation, Thumbs];
const heroSwiper = ref(null);
const heroThumbsSwiper = ref(null);
const activeIndex = ref(0);
const setHeroThumbsSwiper = (swiper) => {
heroThumbsSwiper.value = swiper;
console.log("setHeroThumbsSwiper ", swiper);
// swiper.on('slideChange', function() {
// console.log('slide changed', swiper);
// activeIndex.value = swiper.activeIndex;
// })
}
const setHeroSwiper = (swiper) => {
heroSwiper.value = swiper;
}
const onSlideChange = () => {
activeIndex.value = heroSwiper.value.activeIndex;
}
function test(index, sc) {
console.log(index,'oo');
return activeIndex.value == index;
}
</script>
<style lang="less" scoped>
.big_hero {
width:400px;
height:400px;
}
.hero_big_image {
width:400px;
height:400px;
}
.thumbs_hero_container {
user-select: none;
position: relative;
padding: 0 40px;
width: 820px;
height: 200px;
}
.hero_thumb {
width: 200px;
height:200px;
}
.hero_thumb_img {
display: block;
position: absolute;
left: 100px;
top: 100px;
width:160px;
height:160px;
transform: translate(-50%, -50%);
}
.hero_thumb_bg {
display: block;
position: absolute;
width:200px;
height:200px;
}
.HeroThumbs {
.swiper-button-prev {
}
.swiper-button-next {
}
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<div class="big_hero">
<swiper
@swiper="setHeroSwiper"
:slides-per-view="1"
:thumbs="{ swiper: heroThumbsSwiper }"
:modules="modules"
:navigation="{ nextEl: '.swiper-button-nexto', prevEl: '.swiper-button-prevo', }"
@slideChange="onSlideChange"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<img class="hero_big_image" :src="slideContent.img"/>
</SwiperSlide>
</swiper>
</div>
<div class="thumbs_hero_container">
<Swiper
@swiper="setHeroThumbsSwiper"
:slides-per-view="4"
:modules="modules"
class="HeroThumbs"
:slideToClickedSlide="true"
:centeredSlidesBounds="true"
:multipleActiveThumbs="false"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<div class="hero_thumb">
<img class="hero_thumb_img" :src="slideContent.img"/>
<img v-if="test(index, slideContent)" class="hero_thumb_bg" src="/images/hero_bg.png"/>
</div>
</SwiperSlide>
</Swiper>
<div class="swiper-button-prevo">&le</div>
<div class="swiper-button-nexto">&lg</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { Thumbs, FreeMode, Navigation } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/thumbs';
import 'swiper/css/free-mode';
const heroList = ref([
{ id:1, img:location.origin+'/images/v1.jpg' },
{ id:2, img:location.origin+'/images/v2.jpg' },
{ id:3, img:location.origin+'/images/v3.jpg' },
{ id:4, img:location.origin+'/images/v4.jpg' },
{ id:5, img:location.origin+'/images/v5.jpg' },
{ id:6, img:location.origin+'/images/v1.jpg' },
]);
const modules = [FreeMode, Navigation, Thumbs];
const heroSwiper = ref(null);
const heroThumbsSwiper = ref(null);
const activeIndex = ref(0);
const setHeroThumbsSwiper = (swiper) => {
heroThumbsSwiper.value = swiper;
console.log("setHeroThumbsSwiper ", swiper);
// swiper.on('slideChange', function() {
// console.log('slide changed', swiper);
// activeIndex.value = swiper.activeIndex;
// })
}
const setHeroSwiper = (swiper) => {
heroSwiper.value = swiper;
}
const onSlideChange = () => {
activeIndex.value = heroSwiper.value.activeIndex;
}
function test(index, sc) {
console.log(index,'oo');
return activeIndex.value == index;
}
</script>
<style lang="less" scoped>
.big_hero {
width:400px;
height:400px;
}
.hero_big_image {
width:400px;
height:400px;
}
.thumbs_hero_container {
user-select: none;
position: relative;
padding: 0 40px;
width: 820px;
height: 200px;
}
.hero_thumb {
width: 200px;
height:200px;
}
.hero_thumb_img {
display: block;
position: absolute;
left: 100px;
top: 100px;
width:160px;
height:160px;
transform: translate(-50%, -50%);
}
.hero_thumb_bg {
display: block;
position: absolute;
width:200px;
height:200px;
}
.HeroThumbs {
.swiper-button-prevo {
}
.swiper-button-nexto {
}
}
</style>

View File

@ -1,3 +0,0 @@
.ant-menu-dark .ant-menu-item-selected {
color: #FFF;
}

View File

@ -350,7 +350,7 @@
@font-face {
font-family: Poppins;
src: url(./assets/fonts/Poppins-Bold.ttf);
src: url(../assets/fonts/Poppins-Bold.ttf);
}
.ant-layout-sider {
@ -376,7 +376,8 @@
.gpal-menu-item {
height: auto !important;
color:white;
border-radius: 12px;
border-radius: 1vmax;
padding: 0.2vmax !important;
}
.gpal-menu-item:hover {
background-color:var(--color-surface-nest-hover);

View File

@ -1,7 +1,7 @@
import { createApp } from 'vue';
import Antd from 'ant-design-vue'
// import 'ant-design-vue/dist/antd.less'
import 'ant-design-vue/dist/antd.dark.less';
import 'ant-design-vue/dist/antd.less'
// import 'ant-design-vue/dist/antd.dark.less';
// import 'ant-design-vue/dist/antd.variable.less';
import 'animate.css';
import './css/main.less';
@ -19,8 +19,8 @@ window.Buffer = Buffer;
gsap.registerPlugin(ScrollTrigger);
// eslint-disable-next-line no-unused-vars
const app = createApp(App)
.use(pinia)
.use(router)
.use(pinia)
.use(Antd)
.use(MotionPlugin)
.mount('#app');

View File

@ -9,7 +9,8 @@ const routes = [
},
{
path: '/users',
component: () => import(/* webpackChunkName "users" */ '../views/UserView.vue'),
name: 'users',
component: () => import('@/views/UserView.vue'),
},
{
path: '/about',
@ -18,6 +19,14 @@ const routes = [
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue'),
},
{
path: '/test',
component: () => import('@/views/TestView.vue'),
},
{
path: '/test2',
component: () => import('@/views/TestView2.vue'),
},
{
path: '/user/:id',
name: 'user',

View File

@ -4,7 +4,7 @@ import { ref } from 'vue';
export const useAppStore = defineStore('app', () => {
const list = ref([
{userId: "1", headpic: "/images/1667520250923113.webp"},
{userId: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", headpic: "/images/1667520250923113.webp"},
{userId: "2", headpic: "/images/16555781459976085.webp"},
{userId: "3", headpic: "/images/16595363622946259.webp"},
{userId: "4", headpic: "/images/16620693455819353.webp"},

246
src/views/TestView.vue Normal file
View File

@ -0,0 +1,246 @@
<template>
<div class="box" ref="box" style="perspective:400px">
<div>{{tilt}}x{{roll}}:{{boxStyle}}</div>
<div class="thumbs_hero_container" :style="boxStyle1">
<Swiper
@swiper="setHeroThumbsSwiper"
:slides-per-view="4"
:modules="modules"
class="HeroThumbs"
:slideToClickedSlide="true"
:centeredSlidesBounds="true"
:multipleActiveThumbs="false"
:loop="true"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<div class="hero_thumb">
<img class="hero_thumb_img" :src="slideContent.img"/>
<img v-if="test(index, slideContent)" class="hero_thumb_bg" src="/images/hero_bg.png"/>
</div>
</SwiperSlide>
</Swiper>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<button>
<span>PLAY NOW</span>
</button>
</div>
<div class="big_hero" :style="boxStyle4">
<swiper
@swiper="setHeroSwiper"
:effect="'coverflow'"
:slides-per-view="'2'"
:thumbs="{ swiper: heroThumbsSwiper }"
:modules="modules"
:navigation="{ nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }"
@slideChange="onSlideChange"
:pagination="true"
:loop="true"
:centeredSlides="true"
:coverflowEffect="{
rotate: 0,
stretch: 60,
depth: 100,
modifier: 3,
slideShadows: true,
scale: 0.80
}"
>
<SwiperSlide v-for="(slideContent, index) in heroList" :key="index">
<img class="hero_big_image" :src="slideContent.img"/>
</SwiperSlide>
</swiper>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { EffectCoverflow, Thumbs, FreeMode, Navigation } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { useParallax } from '@vueuse/core';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/thumbs';
import 'swiper/css/free-mode';
import 'swiper/css/effect-coverflow';
const heroList = ref([
{ id:1, img:location.origin+'/images/swiper/desktop/5-kv1.jpg' },
{ id:2, img:location.origin+'/images/swiper/desktop/5-1.jpg' },
{ id:3, img:location.origin+'/images/swiper/desktop/5-2.jpg' },
{ id:4, img:location.origin+'/images/swiper/desktop/5-3.jpg' },
{ id:5, img:location.origin+'/images/swiper/desktop/5-4.jpg' },
]);
const modules = [FreeMode, Navigation, Thumbs, EffectCoverflow];
const heroSwiper = ref(null);
const heroThumbsSwiper = ref(null);
const activeIndex = ref(0);
const box = ref(null);
const { tilt, roll, source } = useParallax(box);
console.log(tilt, 'tilt');
console.log(roll, 'roll');
const boxStyle1 = computed(()=>({
perspective: '300px',
transition: '.2s',
transform: `translateX(${tilt.value * 10}px) translateY(${-roll.value * 10}px) rotateY(${tilt.value*5}deg) rotateX(${roll.value*5}deg)`
}));
const boxStyle2 = computed(()=>({
perspective: '300px',
transition: '.2s',
transform: `translateX(${tilt.value * 20}px) translateY(${-roll.value * 20}px) rotateY(${tilt.value*5}deg) rotateX(${roll.value*5}deg)`
}));
const boxStyle3 = computed(()=>({
perspective: '300px',
transition: '.2s',
transform: `translateX(${tilt.value * 30}px) translateY(${-roll.value * 30}px) rotateY(${tilt.value*5}deg) rotateX(${roll.value*5}deg)`
}));
const boxStyle4 = computed(()=>({
perspective: '300px',
transition: '.2s',
transform: `translateX(${tilt.value * 40}px) translateY(${-roll.value * 40}px) rotateY(${tilt.value*5}deg) rotateX(${roll.value*5}deg)`
}));
const setHeroThumbsSwiper = (swiper) => {
heroThumbsSwiper.value = swiper;
console.log("setHeroThumbsSwiper ", swiper);
// swiper.on('slideChange', function() {
// console.log('slide changed', swiper);
// activeIndex.value = swiper.activeIndex;
// })
}
const setHeroSwiper = (swiper) => {
heroSwiper.value = swiper;
}
const onSlideChange = () => {
activeIndex.value = heroSwiper.value?.activeIndex;
}
function test(index, sc) {
console.log(index,'oo');
return activeIndex.value == index;
}
</script>
<style lang="less" scoped>
.big_hero {
width:100%;
height:400px;
}
.hero_big_image {
width:970px;
height:545px;
}
.thumbs_hero_container {
user-select: none;
position: relative;
padding: 0 40px;
width: 820px;
height: 200px;
}
.hero_thumb {
width: 200px;
height:200px;
}
.hero_thumb_img {
display: block;
position: absolute;
left: 100px;
top: 100px;
width:160px;
height:160px;
transform: translate(-50%, -50%);
}
.hero_thumb_bg {
display: block;
position: absolute;
width:200px;
height:200px;
}
.HeroThumbs {
.swiper-button-prev {
}
.swiper-button-next {
}
}
button {
border: none;
position: relative;
width: 200px;
height: 73px;
padding: 0;
z-index: 2;
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='868' width='2500' viewBox='0 0 726 252.17'%3E%3Cpath d='M483.92 0S481.38 24.71 466 40.11c-11.74 11.74-24.09 12.66-40.26 15.07-9.42 1.41-29.7 3.77-34.81-.79-2.37-2.11-3-21-3.22-27.62-.21-6.92-1.36-16.52-2.82-18-.75 3.06-2.49 11.53-3.09 13.61S378.49 34.3 378 36a85.13 85.13 0 0 0-30.09 0c-.46-1.67-3.17-11.48-3.77-13.56s-2.34-10.55-3.09-13.61c-1.45 1.45-2.61 11.05-2.82 18-.21 6.67-.84 25.51-3.22 27.62-5.11 4.56-25.38 2.2-34.8.79-16.16-2.47-28.51-3.39-40.21-15.13C244.57 24.71 242 0 242 0H0s69.52 22.74 97.52 68.59c16.56 27.11 14.14 58.49 9.92 74.73C170 140 221.46 140 273 158.57c69.23 24.93 83.2 76.19 90 93.6 6.77-17.41 20.75-68.67 90-93.6 51.54-18.56 103-18.59 165.56-15.25-4.21-16.24-6.63-47.62 9.93-74.73C656.43 22.74 726 0 726 0z'/%3E%3C/svg%3E") no-repeat 50% 50%;
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='868' width='2500' viewBox='0 0 726 252.17'%3E%3Cpath d='M483.92 0S481.38 24.71 466 40.11c-11.74 11.74-24.09 12.66-40.26 15.07-9.42 1.41-29.7 3.77-34.81-.79-2.37-2.11-3-21-3.22-27.62-.21-6.92-1.36-16.52-2.82-18-.75 3.06-2.49 11.53-3.09 13.61S378.49 34.3 378 36a85.13 85.13 0 0 0-30.09 0c-.46-1.67-3.17-11.48-3.77-13.56s-2.34-10.55-3.09-13.61c-1.45 1.45-2.61 11.05-2.82 18-.21 6.67-.84 25.51-3.22 27.62-5.11 4.56-25.38 2.2-34.8.79-16.16-2.47-28.51-3.39-40.21-15.13C244.57 24.71 242 0 242 0H0s69.52 22.74 97.52 68.59c16.56 27.11 14.14 58.49 9.92 74.73C170 140 221.46 140 273 158.57c69.23 24.93 83.2 76.19 90 93.6 6.77-17.41 20.75-68.67 90-93.6 51.54-18.56 103-18.59 165.56-15.25-4.21-16.24-6.63-47.62 9.93-74.73C656.43 22.74 726 0 726 0z'/%3E%3C/svg%3E") no-repeat 50% 50%;
-webkit-mask-size: 100%;
cursor: pointer;
background-color: transparent;
transform: translateY(8px)
}
button:after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0px 0 0 0 white;
transition: all 2s ease;
}
button:hover:after {
box-shadow: 0px -13px 56px 12px #ffffffa6;
}
button span {
position: absolute;
width: 100%;
font-size: 15px;
font-weight: 100;
left: 50%;
top: 39%;
letter-spacing: 3px;
text-align: center;
transform: translate(-50%,-50%);
color: rgb(222, 13, 13);
transition: all 2s ease;
}
button:hover span {
color: white;
}
button:before {
content: '';
position: absolute;
width: 0;
height: 100%;
background-color: black;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: all 1s ease;
}
button:hover:before {
width: 100%;
}
</style>

8
src/views/TestView2.vue Normal file
View File

@ -0,0 +1,8 @@
<template>
<TestView></TestView>
<TestViewO></TestViewO>
</template>
<script>
import TestView from '@/components/TestView.vue'
import TestViewO from '@/components/TestViewO.vue'
</script>

View File

@ -1,8 +1,8 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<a-layout>
<a-layout style="padding: 1vw">
<a-layout-sider width="30vw">
<a-layout style="padding: 1vmax">
<a-layout-sider width="22vmax">
<a-menu
id="services_list"
class="gpal-menu"

126
test/Lock.js Normal file
View File

@ -0,0 +1,126 @@
const {
time,
loadFixture,
} = require("@nomicfoundation/hardhat-network-helpers");
const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
const { expect } = require("chai");
describe("Lock", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployOneYearLockFixture() {
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const ONE_GWEI = 1_000_000_000;
const lockedAmount = ONE_GWEI;
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const Lock = await ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
return { lock, unlockTime, lockedAmount, owner, otherAccount };
}
describe("Deployment", function () {
it("Should set the right unlockTime", async function () {
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
expect(await lock.unlockTime()).to.equal(unlockTime);
});
it("Should set the right owner", async function () {
const { lock, owner } = await loadFixture(deployOneYearLockFixture);
expect(await lock.owner()).to.equal(owner.address);
});
it("Should receive and store the funds to lock", async function () {
const { lock, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
expect(await ethers.provider.getBalance(lock.address)).to.equal(
lockedAmount
);
});
it("Should fail if the unlockTime is not in the future", async function () {
// We don't use the fixture here because we want a different deployment
const latestTime = await time.latest();
const Lock = await ethers.getContractFactory("Lock");
await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
"Unlock time should be in the future"
);
});
});
describe("Withdrawals", function () {
describe("Validations", function () {
it("Should revert with the right error if called too soon", async function () {
const { lock } = await loadFixture(deployOneYearLockFixture);
await expect(lock.withdraw()).to.be.revertedWith(
"You can't withdraw yet"
);
});
it("Should revert with the right error if called from another account", async function () {
const { lock, unlockTime, otherAccount } = await loadFixture(
deployOneYearLockFixture
);
// We can increase the time in Hardhat Network
await time.increaseTo(unlockTime);
// We use lock.connect() to send a transaction from another account
await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
"You aren't the owner"
);
});
it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
const { lock, unlockTime } = await loadFixture(
deployOneYearLockFixture
);
// Transactions are sent using the first signer by default
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).not.to.be.reverted;
});
});
describe("Events", function () {
it("Should emit an event on withdrawals", async function () {
const { lock, unlockTime, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw())
.to.emit(lock, "Withdrawal")
.withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
});
});
describe("Transfers", function () {
it("Should transfer the funds to the owner", async function () {
const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).to.changeEtherBalances(
[owner, lock],
[lockedAmount, -lockedAmount]
);
});
});
});
});

1761
yarn.lock

File diff suppressed because it is too large Load Diff