init
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
bin/
|
||||
node_modules/
|
||||
obj/
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
FROM node:18-alpine as install
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./frontend/package*.json ./
|
||||
RUN ls -la
|
||||
RUN npm install
|
||||
|
||||
FROM install as run
|
||||
COPY ./frontend .
|
||||
RUN ["npm", "run", "build"]
|
||||
|
||||
ENTRYPOINT ["npm", "run", "production"]
|
||||
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
+1
@@ -0,0 +1 @@
|
||||
@font-face{font-family:Buran;src:local("Buran USSR"),url(/assets/Buran\ USSR-4a5dccb7.ttf) format("truetype")}@font-face{font-family:Mustica;src:local("MusticaPro-SemiBold"),url(/assets/MusticaPro-SemiBold-7bb0a7cb.otf) format("opentype")}html{height:100%;color:#fff;font-family:Mustica;font-size:14px}h1,h2,h3,h5,h6{font-family:Buran,Arial}h1,h2{text-align:center}h1{font-size:30px}h2{font-size:28px}h4{font-size:26px}h5{font-size:22px}h6{font-size:20px}hr{color:#fff}body{margin:0;padding:0;height:100%;background-color:#826c55}a{color:#5e4226}a:visited{color:#2f2014}div#app{min-height:100%;display:flex;flex-direction:column;height:100%}header{width:100%;height:40px;background-color:#5e4226;font-family:Buran;font-size:24px}header .left-menu,header .right-menu{width:calc((100% - 40px)/2);display:inline-flex}header .right-menu{flex-direction:row-reverse}header .middle-menu{width:40px;display:inline-block}header a,header a:visited{color:#fff;text-decoration:none;margin-left:7px;margin-right:7px;text-shadow:0px 0px 6px #2f2014}header a.router-link-active{text-shadow:0px 0px 6px white;color:#2f2014}.column{margin-left:150px;margin-right:150px}.background{background-color:#baa48f;padding-top:2px;padding-bottom:10px;margin-left:5px;margin-right:5px;color:#2f2014}footer{display:flex;padding-top:5px;padding-bottom:5px;margin-top:auto;align-self:flex-end;width:100%;height:min-content;background-color:#5e4226}.addbtn[data-v-3a1e7e07]{font-size:24px}thead[data-v-3a1e7e07]{background-color:#2f2014;color:#fff}tr[data-v-3a1e7e07],td[data-v-3a1e7e07]{border:dotted 1px #2f2014}.admin-dashboard[data-v-e19aee3b]{margin:0 auto;padding:15px}button.tab[data-v-e19aee3b]{background-color:#baa48f;border:none;padding:4px;cursor:pointer}button.tab.active[data-v-e19aee3b]{border-top:solid 2px #2f2014;font-weight:700}.shown-container[data-v-e19aee3b]{background-color:#baa48f;color:#2f2014;padding:5px}h2[data-v-aad8fcac]{color:#2f2014}.list[data-v-aad8fcac]{display:flex;flex-direction:row}.list-container[data-v-aad8fcac]{margin-left:-5px;margin-right:-5px}.list-elem[data-v-aad8fcac]{width:25%;padding:2px 4px 2px 2px}.label[data-v-d6ae499b],.input[data-v-d6ae499b]{display:inline-block}.label[data-v-d6ae499b]{margin-right:5px;min-width:39%}.input[data-v-d6ae499b]{width:60%}.input>input[data-v-d6ae499b]{width:100%}.editor-line[data-v-d6ae499b]{margin-top:15px;margin-bottom:10px;width:100%;border-top:dashed 1px #2f2014}.label[data-v-d1d12cd2],.input[data-v-d1d12cd2]{display:inline-block}.label[data-v-d1d12cd2]{margin-right:5px;min-width:39%;vertical-align:top}.input[data-v-d1d12cd2]{width:60%}.input>textarea[data-v-d1d12cd2]{width:100%}.editor-line[data-v-d1d12cd2]{margin-top:15px;margin-bottom:10px;width:100%;border-top:dashed 1px #2f2014}.label[data-v-b8a707c3],.input[data-v-b8a707c3]{display:inline-block}.label[data-v-b8a707c3]{margin-right:5px;min-width:39%}.input[data-v-b8a707c3]{width:60%}.input>input[data-v-b8a707c3]{width:100%}.editor-line[data-v-b8a707c3]{margin-top:15px;margin-bottom:10px;width:100%;border-top:dashed 1px #2f2014}.savebtn[data-v-ce0e1569]{margin:15px;font-size:24px;color:#2f2014;background-color:#c3ffa8;border:none}.cancelbtn[data-v-ce0e1569]{margin:6px;font-size:15px;color:#2f2014;background-color:#ffa8a9;border:none}.error[data-v-ce0e1569]{overflow:auto;max-width:50%;max-height:150px;color:red}
|
||||
Vendored
+9
File diff suppressed because one or more lines are too long
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDuEEAg7hBAIO4QSWDuEEgg7hBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg7hBAIO4QQiDuEGlg7hBmIO4QQSDuEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg7hBAIO4QQCDuEFQg7hB9IO4Qe6DuEFDg7hBAIO4QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIO4QQCDuEEUg7hBwYO4Qf+DuEH/g7hBtIO4QQ2DuEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIO4QQCDuEEAg7hBb4O4QfyDuUH/g7lB/4O4QfmDuEFgg7hBAIO4QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDuEEAg7hBJoO4QdmDuUH/f6tA/3+tQP+DuUH/g7hBzoO4QR2DuEEAAAAAAAAAAAAAAAAAAAAAAAAAAACDuEEAg7hBA4O4QY+DuEH/grZB/2xzOv9ueTr/g7dB/4O4Qf+DuEGAg7hBAIO4QQAAAAAAAAAAAAAAAACDuEEAg7hBAIO4QT6DuEHrhLpB/3mYPv9gTjb/YVE2/3qePv+DuUH/g7hB44O4QTKDuEEAg7hBAAAAAAAAAAAAg7hBAIO4QQuDuEGvg7lB/4GxQP9oZjj/XUc1/11HNf9qbDn/grRB/4O4Qf+DuEGhg7hBB4O4QQAAAAAAg7hBAIO4QQCDuEFbg7hB94O5Qf90izz/Xko1/15JNf5eSTX+X0w1/3aRPf+DuUH/g7hB8oO4QU2DuEEAg7hBAIO4QQCDuEEZg7hByoO5Qf9+qkD/ZFs3/15INf9eSjW/Xko1xl5INf9mYDj/gK5A/4O5Qf+DuEG+g7hBEoO4QQCDuEEAg7hBe4O4Qf6Dt0H/b3w7/15INf9eSTXtX0s1P19LNUxeSTXzXkk1/3GDO/+DuEH/g7hB/IO4QWyDuEEAg7hBKIO4QciDuUHpfKM/52JUNudeSDXqXko1jmFRNgNgTjYHXko1m15INepjWDfnfqg/54O5QeqDuEG+g7hBHoO4QQ6DuEEmhLpBJnWNPCZdRzUmXkk1Jl9KNQ9eSTUAXUc1AF9KNRFeSTUnXkk1JneUPSaEukEmg7hBJoO4QQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP5/AAD8PwAA/D8AAPgfAAD4HwAA8A8AAOAPAADgBwAAwAMAAMADAACAAQAAgAEAAAAAAAABgAAA//8AAA==">
|
||||
<title>Notrocketscience</title>
|
||||
<script type="module" crossorigin src="/assets/index-6a80e0e5.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-2570ef72.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>javascript not enabled</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,158 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>a14c5984-6907-420a-900f-ec6f55275e21</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>npm</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
|
||||
<NodejsPort>5173</NodejsPort>
|
||||
<StartWebBrowser>True</StartWebBrowser>
|
||||
<ScriptArguments>run dev</ScriptArguments>
|
||||
<SaveNodeJsSettingsInProjectFile>False</SaveNodeJsSettingsInProjectFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="dist\index.html" />
|
||||
<Content Include="Dockerfile" />
|
||||
<Content Include="index.html">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="package-lock.json" />
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="src\App.vue" />
|
||||
<Content Include="src\assets\fonts\Buran USSR.ttf" />
|
||||
<Content Include="src\assets\fonts\MusticaPro-SemiBold.otf" />
|
||||
<Content Include="src\assets\fonts\README.txt" />
|
||||
<Content Include="src\components\About.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\ComicEdit.vue" />
|
||||
<Content Include="src\components\admin\Dashboard.vue" />
|
||||
<Content Include="src\components\admin\Admin.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\FileUpload.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\ComicEditor.vue" />
|
||||
<Content Include="src\components\admin\elements\GameEditor.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\ImageUploader.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\LinkEdit.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\NumberEdit.vue" />
|
||||
<Content Include="src\components\admin\ComicAdd.vue" />
|
||||
<Content Include="src\components\admin\GameAdd.vue" />
|
||||
<Content Include="src\components\admin\GameEdit.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\MultiLineEdit.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\elements\SingleLineEdit.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\admin\ComicTable.vue" />
|
||||
<Content Include="src\components\elements\CarouselGallery.vue" />
|
||||
<Content Include="src\components\admin\GameTable.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\elements\games\GameLinks.vue" />
|
||||
<Content Include="src\components\elements\Greeter.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\Game.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\elements\games\GameDescription.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\elements\games\GamePreview.vue">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\components\Games.vue" />
|
||||
<Content Include="src\components\Home.vue" />
|
||||
<Content Include="package.json" />
|
||||
<Content Include="README.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="dist\" />
|
||||
<Folder Include="src\" />
|
||||
<Folder Include="src\assets\" />
|
||||
<Folder Include="src\assets\fonts\" />
|
||||
<Folder Include="src\assets\js\" />
|
||||
<Folder Include="src\components\" />
|
||||
<Folder Include="src\components\admin\elements\" />
|
||||
<Folder Include="src\components\elements\games\" />
|
||||
<Folder Include="src\components\elements\" />
|
||||
<Folder Include="src\components\admin\" />
|
||||
<Folder Include="src\infrastructure\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="src\config.js" />
|
||||
<Content Include="src\infrastructure\config.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\main.js" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
npm run build
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsToolsV2.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>0</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:48022/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>False</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>False</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
|
||||
<NodeExePath>D:\Program Files\nodejs\node.exe</NodeExePath>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>Notrocketscience</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>javascript not enabled</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+2960
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "3",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"production": "vite preview --host 0.0.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "^1.44.0",
|
||||
"vue": "^3.2.47",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-ace-editor": "^2.2.4",
|
||||
"vue3-carousel": "^0.2.16",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"vite": "^4.1.4"
|
||||
}
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<header>
|
||||
<div class="column">
|
||||
<span class="left-menu">
|
||||
</span>
|
||||
<span class="middle-menu">
|
||||
</span>
|
||||
<span class="right-menu">
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<router-view></router-view>
|
||||
<footer>
|
||||
<div class="column">
|
||||
<div class="footer-left">
|
||||
d.kollerov
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@font-face{
|
||||
font-family: "Buran";
|
||||
src: local("Buran USSR"), url('./assets/fonts/Buran USSR.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Mustica";
|
||||
src: local("MusticaPro-SemiBold"), url('./assets/fonts/MusticaPro-SemiBold.otf') format('opentype');
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
color: white;
|
||||
font-family: Mustica;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h5, h6 {
|
||||
font-family: Buran, Arial;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 20px
|
||||
}
|
||||
|
||||
hr {
|
||||
color: white;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
background-color: #826c55;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #5e4226;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #2f2014;
|
||||
}
|
||||
|
||||
div#app {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction:column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: #5e4226;
|
||||
font-family: Buran;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
header .left-menu, header .right-menu {
|
||||
width: calc((100% - 40px) / 2);
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
header .right-menu {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
header .middle-menu {
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
header a, header a:visited {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 7px;
|
||||
margin-right: 7px;
|
||||
text-shadow: 0px 0px 6px #2f2014;
|
||||
}
|
||||
|
||||
header a:hover {
|
||||
|
||||
}
|
||||
|
||||
header a.router-link-active {
|
||||
text-shadow: 0px 0px 6px white;
|
||||
color: #2f2014;
|
||||
}
|
||||
|
||||
.column {
|
||||
margin-left: 150px;
|
||||
margin-right: 150px;
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: #baa48f;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 10px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
color: #2f2014;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-top: auto;
|
||||
align-self: flex-end;
|
||||
width: 100%;
|
||||
height: min-content;
|
||||
background-color: #5e4226;
|
||||
}
|
||||
|
||||
footer .footer-left {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
|
||||
::: Buy Premium Version & Full Package, please visit :::
|
||||
|
||||
--> https://www.myfonts.com/fonts/alifinart-studio/mustica-pro/
|
||||
|
||||
|
||||
::: My Portfolio :::
|
||||
|
||||
--> www.behance.net/alifinart/
|
||||
|
||||
|
||||
::: Join our circle or subscribe now to get an extra-special offers :::
|
||||
|
||||
--> https://gumroad.com/alifinart
|
||||
|
||||
--------------------
|
||||
|
||||
Any questions or request please feel free to email:
|
||||
|
||||
alifinart@gmail.com
|
||||
|
||||
Thank's.
|
||||
|
||||
Copyright © 2021 Alifinart
|
||||
|
||||
--------------------
|
||||
|
||||
If you distribute my work, MUST include the name of the foundry “Alifinart Studio”
|
||||
and include a link to my portfolio (behance.net/alifinart), unless you have received
|
||||
permission from us.
|
||||
|
||||
Thank you.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<div class="background">
|
||||
<div class="list-container">
|
||||
<h2>Books</h2>
|
||||
<div class="column">
|
||||
<Dashboard />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dashboard from "./admin/Dashboard.vue";
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
data() {
|
||||
},
|
||||
components: {
|
||||
Dashboard: Dashboard
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted() {
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h2 {
|
||||
color: #2f2014;
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.list-container {
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
.list-elem {
|
||||
width: 25%;
|
||||
padding: 2px 4px 2px 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="game">
|
||||
<div class="background">
|
||||
<form @submit.prevent="uploadBook">
|
||||
<BookEditor v-bind:entry="entry"
|
||||
v-bind:error="error"
|
||||
editorTitle="Add book"
|
||||
:is_edit="false"
|
||||
@modelEdit="data => onInput(data)"
|
||||
@error="this.error = $event.message"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
import BookEditor from './elements/BookEditor.vue'
|
||||
|
||||
export default {
|
||||
name: "BookAdd",
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
entry: {
|
||||
id: '',
|
||||
title: '',
|
||||
author: '',
|
||||
yearPublished: new Date,
|
||||
bookIndex: '<root>\n\t<chapter>\n\t\t<name></name><page></page>\n\t</chapter>\n</root>'
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BookEditor
|
||||
},
|
||||
computed: mapState({
|
||||
//token: state => "Bearer " + state.token,
|
||||
}),
|
||||
methods: {
|
||||
uploadBook: function () {
|
||||
var self = this;
|
||||
var data = {
|
||||
"author": self.entry.author,
|
||||
"title": self.entry.title,
|
||||
"yearPublished": self.entry.yearPublished,
|
||||
"bookIndex": self.entry.bookIndex
|
||||
};
|
||||
fetch(self.$store.state.config.API_URL + '/Book/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
// "Authorization": self.token,
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(function (response) {
|
||||
if (response.status == 401 || response.status == 403) {
|
||||
// this.$store.commit('purgeToken');
|
||||
// this.$router.push("/admin");
|
||||
}else{
|
||||
return response.json();
|
||||
}
|
||||
}).then((response) => {
|
||||
if(response.isSuccess == true)
|
||||
{
|
||||
self.$router.push("/");
|
||||
}else{
|
||||
self.error = JSON.stringify(response);
|
||||
}
|
||||
}).catch(error => {
|
||||
if (error.status == 401 || error.status == 403) {
|
||||
// self.$store.commit('purgeToken');
|
||||
// self.$router.push("/admin");
|
||||
}
|
||||
self.error = error;
|
||||
});
|
||||
},
|
||||
onInput(data) {
|
||||
this.entry = data;
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="game">
|
||||
<div class="background">
|
||||
<form @submit.prevent="saveBook">
|
||||
<BookEditor v-bind:entry="entry"
|
||||
:error="error"
|
||||
editorTitle="Edit game"
|
||||
:is_edit="true"
|
||||
@modelEdit="data => onInput(data)"
|
||||
@error="this.error = $event.message"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import BookEditor from './elements/BookEditor.vue'
|
||||
|
||||
export default {
|
||||
name: "BookEdit",
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
entry: {
|
||||
id: '',
|
||||
title: '',
|
||||
author: '',
|
||||
yearPublished: new Date,
|
||||
bookIndex: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BookEditor: BookEditor
|
||||
},
|
||||
computed: mapState({
|
||||
// token: state => "Bearer " + state.token,
|
||||
}),
|
||||
mounted() {
|
||||
this.getBook()
|
||||
},
|
||||
methods: {
|
||||
getBook() {
|
||||
var bookId = this.$route.params.id;
|
||||
fetch(this.$store.state.config.API_URL + '/Book/' + bookId, {
|
||||
headers: {
|
||||
// "Authorization": this.token,
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response.status == 401 || response.status == 403) {
|
||||
// this.$store.commit('purgeToken');
|
||||
// this.$router.push("/admin");
|
||||
}else{
|
||||
return response.json();
|
||||
}
|
||||
}).then(response => {
|
||||
this.entry.id = response.book.id;
|
||||
this.entry.title = response.book.title;
|
||||
this.entry.author = response.book.author;
|
||||
this.entry.yearPublished = new Date(response.book.yearPublished);
|
||||
this.entry.bookIndex = response.book.bookIndex;
|
||||
});
|
||||
},
|
||||
saveBook() {
|
||||
var self = this;
|
||||
var data = {
|
||||
"id": self.entry.id,
|
||||
"author": self.entry.author,
|
||||
"title": self.entry.title,
|
||||
"yearPublished": self.entry.yearPublished,
|
||||
"bookIndex": self.entry.bookIndex
|
||||
};
|
||||
fetch(self.$store.state.config.API_URL + '/Book/', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
// "Authorization": self.token,
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(function (response) {
|
||||
if (response.status == 401 || response.status == 403) {
|
||||
// this.$store.commit('purgeToken');
|
||||
// this.$router.push("/admin");
|
||||
}else{
|
||||
return response.json();
|
||||
}
|
||||
}).then((response) => {
|
||||
if(response.isSuccess == true)
|
||||
{
|
||||
self.$router.push("/");
|
||||
}else{
|
||||
self.error = JSON.stringify(response);
|
||||
}
|
||||
}).catch(error => {
|
||||
if (error.status == 401 || error.status == 403) {
|
||||
// self.$store.commit('purgeToken');
|
||||
// self.$router.push("/admin");
|
||||
}
|
||||
self.error = error;
|
||||
});
|
||||
},
|
||||
onInput(data) {
|
||||
this.entry = data;
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="table-wrapper">
|
||||
<router-link class="addbtn" :to="{ path: '/add-book' }">Add</router-link>
|
||||
<table>
|
||||
<thead> <tr> <td>Id</td> <td>Title</td> <td>Author</td> <td>Year published</td> <td>Index</td> <td>Actions</td> </tr> </thead>
|
||||
<tbody>
|
||||
<tr v-for="item of bookEntries" v-bind:key="item.id">
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.title}}</td>
|
||||
<td>{{item.author}}</td>
|
||||
<td>{{item.yearPublished}}</td>
|
||||
<td>{{item.bookIndex}}</td>
|
||||
<td><router-link :to="{ path: '/edit-book/' + item.id }">Edit</router-link> <button v-on:click="deleteBook(item.id)">Delete</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "BookTable",
|
||||
data() {
|
||||
return {
|
||||
bookEntries: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getBookList();
|
||||
},
|
||||
computed: mapState({
|
||||
}),
|
||||
methods: {
|
||||
getBookList: function () {
|
||||
var self = this;
|
||||
fetch(this.$store.state.config.API_URL + '/Book')
|
||||
.then(function (response) {
|
||||
return response.json()
|
||||
}).then(response => {
|
||||
self.bookEntries = response.books;
|
||||
});
|
||||
},
|
||||
deleteBook(id) {
|
||||
fetch(this.$store.state.config.API_URL + '/Book/' + id, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response.status == 401 || response.status == 403) {
|
||||
// this.$store.commit('purgeToken');
|
||||
// this.$router.push("/admin");
|
||||
}else{
|
||||
return response.json()
|
||||
}
|
||||
}).then(() => {
|
||||
this.getBookList();
|
||||
}).error((error) => {
|
||||
if (error.status == 401 || error.status == 403) {
|
||||
// this.$store.commit('purgeToken');
|
||||
// this.$router.push("/admin");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.addbtn {
|
||||
font-size: 24px;
|
||||
}
|
||||
thead {
|
||||
background-color: #2f2014;
|
||||
color: white;
|
||||
}
|
||||
tr {
|
||||
border: dotted 1px #2f2014;
|
||||
}
|
||||
td {
|
||||
border: dotted 1px #2f2014;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="admin-dashboard">
|
||||
<div class="admin-dashboard">
|
||||
<button :class="{tab: true, active: tabs.indexOf(tab) == selectedTab}" v-bind:key="tab.name" v-for="tab of tabs" v-html="tab.name" v-on:click="selectTab(tabs.indexOf(tab))"></button>
|
||||
<div class="shown-container">
|
||||
<keep-alive>
|
||||
<component v-bind:is="this.tabs[this.selectedTab].component"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BookTable from './BookTable.vue';
|
||||
import { shallowRef } from 'vue'
|
||||
|
||||
export default {
|
||||
name: "Dashboard",
|
||||
data() {
|
||||
return {
|
||||
selectedTab: 0,
|
||||
tabs: [
|
||||
{
|
||||
name: "Books",
|
||||
component: shallowRef(BookTable)
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BookTable: BookTable
|
||||
},
|
||||
mounted() {
|
||||
// if (this.$store.state.token === undefined || this.$store.state.token === null || this.$store.state.token === '') {
|
||||
// this.$router.push("/admin")
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
selectTab(index) {
|
||||
this.selectedTab = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.admin-dashboard{
|
||||
margin:0 auto;
|
||||
padding: 15px;
|
||||
}
|
||||
button.tab {
|
||||
background-color: #baa48f;
|
||||
border:none;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.tab.active {
|
||||
border-top: solid 2px #2f2014;
|
||||
font-weight: bold;
|
||||
}
|
||||
.shown-container {
|
||||
background-color: #baa48f;
|
||||
color: #2f2014;
|
||||
padding:5px
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="editor">
|
||||
<div class="column">
|
||||
<h2>{{editorTitle}}</h2>
|
||||
<div class="error" v-if="this.error != null"><p v-html="this.error"></p></div>
|
||||
|
||||
<input class="savebtn" type="submit" value="Save" />
|
||||
<router-link class="cancelbtn" :to="{ path: '/' }">Cancel</router-link>
|
||||
|
||||
<SingleLineEdit name="title"
|
||||
label="Title"
|
||||
v-bind:value="entry.title"
|
||||
@valueChanged="v => onTitle(v)" />
|
||||
|
||||
<SingleLineEdit name="author"
|
||||
label="Author"
|
||||
v-bind:value="entry.author"
|
||||
@valueChanged="v => onAuthor(v)" />
|
||||
|
||||
<DateEdit name="yearPublished"
|
||||
label="Year published"
|
||||
v-bind:value="entry.yearPublished"
|
||||
@valueChanged="v => onYear(v)" />
|
||||
|
||||
<MultiLineEdit name="bookIndex"
|
||||
label="Book index"
|
||||
v-bind:value="entry.bookIndex"
|
||||
@valueChanged="v => onIndex(v)" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleLineEdit from './SingleLineEdit.vue';
|
||||
import MultiLineEdit from './MultiLineEdit.vue';
|
||||
import DateEdit from './DateEdit.vue';
|
||||
|
||||
export default {
|
||||
name: "BookEditor",
|
||||
model: {
|
||||
prop: 'entry',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
error: "AAAAAA",
|
||||
is_edit: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
editorTitle: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'Title';
|
||||
}
|
||||
},
|
||||
entry: {
|
||||
id: {
|
||||
type: String,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
author: {
|
||||
type: String,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
yearPublished: {
|
||||
type: Date,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
bookIndex: {
|
||||
type: String,
|
||||
default() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SingleLineEdit,
|
||||
MultiLineEdit,
|
||||
DateEdit
|
||||
},
|
||||
methods: {
|
||||
onIndex(x) {
|
||||
this.$emit('modelEdit', {
|
||||
id: this.entry.id,
|
||||
yearPublished: this.entry.yearPublished,
|
||||
title: this.entry.title,
|
||||
author: this.entry.author,
|
||||
bookIndex: x
|
||||
});
|
||||
},
|
||||
onAuthor(x) {
|
||||
this.$emit('modelEdit', {
|
||||
id: this.entry.id,
|
||||
yearPublished: this.entry.yearPublished,
|
||||
title: this.entry.title,
|
||||
author: x,
|
||||
bookIndex: this.entry.bookIndex
|
||||
});
|
||||
},
|
||||
onTitle(x) {
|
||||
this.$emit('modelEdit', {
|
||||
id: this.entry.id,
|
||||
yearPublished: this.entry.yearPublished,
|
||||
title: x,
|
||||
author: this.entry.author,
|
||||
bookIndex: this.entry.bookIndex
|
||||
});
|
||||
},
|
||||
onYear(x) {
|
||||
this.$emit('modelEdit', {
|
||||
id: this.entry.id,
|
||||
yearPublished: x,
|
||||
title: this.entry.title,
|
||||
author: this.entry.author,
|
||||
bookIndex: this.entry.bookIndex
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.savebtn {
|
||||
margin: 15px;
|
||||
font-size: 24px;
|
||||
color: #2f2014;
|
||||
background-color: #c3ffa8;
|
||||
border: none;
|
||||
}
|
||||
.cancelbtn {
|
||||
margin: 6px;
|
||||
font-size: 15px;
|
||||
color: #2f2014;
|
||||
background-color: #ffa8a9;
|
||||
border: none;
|
||||
}
|
||||
.error {
|
||||
overflow: auto;
|
||||
max-width: 50%;
|
||||
max-height: 150px;
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="editor-line">
|
||||
<div class="label">
|
||||
<label v-if="this.label != null">{{label}}</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
<input
|
||||
:name="name"
|
||||
type="date"
|
||||
v-model="innerValue"
|
||||
:disabled="is_disabled" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "DateEdit",
|
||||
props: {
|
||||
label: null,
|
||||
name: null,
|
||||
value: {
|
||||
type: Date,
|
||||
default() {
|
||||
return new Date();
|
||||
}
|
||||
},
|
||||
is_disabled: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: new Date()
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
innerValue: {
|
||||
handler: function (x) {
|
||||
this.$emit('valueChanged', x);
|
||||
},
|
||||
immediate: false
|
||||
},
|
||||
value: {
|
||||
handler: function(x) {
|
||||
this.innerValue = x.toISOString().slice(0, 10);
|
||||
},
|
||||
immediate: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.label, .input {
|
||||
display: inline-block;
|
||||
}
|
||||
.label {
|
||||
margin-right: 5px;
|
||||
min-width: 39%;
|
||||
}
|
||||
.input {
|
||||
width: 60%;
|
||||
}
|
||||
.input > input {
|
||||
width: 100%;
|
||||
}
|
||||
.editor-line {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
border-top: dashed 1px #2f2014;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="editor-line">
|
||||
<div class="label">
|
||||
<label v-if="this.label != null">{{label}}</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
<!-- <textarea :name="name" v-model="message_slug" :disabled="is_disabled" /> -->
|
||||
<VAceEditor
|
||||
ref="aceRef"
|
||||
v-model:value="message_slug"
|
||||
style="height: 300px"
|
||||
:options="{ useWorker: false }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
import { VAceEditor } from 'vue3-ace-editor';
|
||||
|
||||
export default {
|
||||
name: "MultiLineEdit",
|
||||
data() {
|
||||
return {
|
||||
message_slug: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
VAceEditor: VAceEditor
|
||||
},
|
||||
props: {
|
||||
label: null,
|
||||
name: null,
|
||||
value: '',
|
||||
is_disabled: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
message_slug: {
|
||||
handler: function (x) {
|
||||
this.$emit('valueChanged', x);
|
||||
},
|
||||
immediate: false
|
||||
},
|
||||
value: {
|
||||
handler: function (x) {
|
||||
this.message_slug = x;
|
||||
},
|
||||
immediate: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.message_slug = this.value;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.label, .input {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-right: 5px;
|
||||
min-width: 39%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.input > textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.editor-line {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
border-top: dashed 1px #2f2014;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="editor-line">
|
||||
<div class="label">
|
||||
<label v-if="this.label != null">{{label}}</label>
|
||||
</div>
|
||||
<div class="input">
|
||||
<input
|
||||
:name="name"
|
||||
type="text"
|
||||
v-model="innerValue"
|
||||
:disabled="is_disabled" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "SingleLineEdit",
|
||||
props: {
|
||||
label: null,
|
||||
name: null,
|
||||
value: {
|
||||
type: String,
|
||||
default() {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
is_disabled: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
innerValue: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
innerValue: {
|
||||
handler: function (x) {
|
||||
this.$emit('valueChanged', x);
|
||||
},
|
||||
immediate: false
|
||||
},
|
||||
value: {
|
||||
handler: function(x) {
|
||||
this.innerValue = x;
|
||||
},
|
||||
immediate: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.innerValue = this.value;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.label, .input {
|
||||
display: inline-block;
|
||||
}
|
||||
.label {
|
||||
margin-right: 5px;
|
||||
min-width: 39%;
|
||||
}
|
||||
.input {
|
||||
width: 60%;
|
||||
}
|
||||
.input > input {
|
||||
width: 100%;
|
||||
}
|
||||
.editor-line {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
border-top: dashed 1px #2f2014;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,2 @@
|
||||
import config from './infrastructure/config.js';
|
||||
export default config;
|
||||
@@ -0,0 +1,4 @@
|
||||
export default {
|
||||
API_URL: 'http://localhost:5222/api',
|
||||
DEFAULT_TITLE: 'Books'
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { createWebHistory, createRouter } from 'vue-router';
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
import Home from './components/Home.vue';
|
||||
import BookAdd from './components/admin/BookAdd.vue';
|
||||
import BookEdit from './components/admin/BookEdit.vue';
|
||||
|
||||
import config from './config.js'
|
||||
|
||||
import ace from 'ace-builds';
|
||||
|
||||
import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url';
|
||||
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl);
|
||||
|
||||
import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url';
|
||||
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl);
|
||||
|
||||
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'; // For vite
|
||||
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl);
|
||||
|
||||
let siteName = 'Not rocket science';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
component: Home,
|
||||
meta: { title: siteName }
|
||||
},
|
||||
{
|
||||
path: '/add-book',
|
||||
component: BookAdd,
|
||||
meta: { title: siteName + " EDIT" }
|
||||
},
|
||||
{
|
||||
path: '/edit-book/:id',
|
||||
component: BookEdit,
|
||||
meta: { title: siteName + " EDIT" }
|
||||
},
|
||||
];
|
||||
|
||||
const store = new createStore({
|
||||
state: {
|
||||
token: null,
|
||||
config: {
|
||||
API_URL: config.API_URL
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setToken(state, token) {
|
||||
state.token = token
|
||||
},
|
||||
purgeToken(state) {
|
||||
state.token = null
|
||||
},
|
||||
initialiseStore(state) {
|
||||
var tokenInStorage = localStorage.getItem('token');
|
||||
if (tokenInStorage) {
|
||||
state.token = JSON.parse(tokenInStorage);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
store.subscribe((mutation, state) => {
|
||||
localStorage.setItem('token', JSON.stringify(state.token));
|
||||
});
|
||||
|
||||
const router = new createRouter({
|
||||
routes: routes,
|
||||
history: createWebHistory()
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
document.title = to.meta.title || config.DEFAULT_TITLE;
|
||||
});
|
||||
|
||||
const app = createApp({
|
||||
extends: App,
|
||||
beforeCreate() {
|
||||
this.$store.commit('initialiseStore')
|
||||
}
|
||||
})
|
||||
.use(router)
|
||||
.use(store)
|
||||
.mount('#app')
|
||||
@@ -0,0 +1,14 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user