このコミットが含まれているのは:
ElCastra 2024-04-04 00:00:55 +07:00
コミット eb6f52379d
11個のファイルの変更362行の追加0行の削除

3
.vscode/settings.json vendored ノーマルファイル
ファイルの表示

@ -0,0 +1,3 @@
{
"deepscan.enable": true
}

0
README.md ノーマルファイル
ファイルの表示

6
components/App.js ノーマルファイル
ファイルの表示

@ -0,0 +1,6 @@
import Assignments from "./Assignments.js";
export default {
components: { Assignments },
template: `<assignments/>`,
};

17
components/Assignment.js ノーマルファイル
ファイルの表示

@ -0,0 +1,17 @@
export default {
template: `
<li class="flex gap-5 justify-between items-center my-2">
<p class="ml-2">{{ assignment.name }}</p>
<div class="">
<label class="checkBox">
<input type="checkbox" v-model="assignment.complete" />
<div class="transition"></div>
</label>
</div>
</li>
`,
props: {
assignment: Object,
},
};

51
components/AssignmentCreate.js ノーマルファイル
ファイルの表示

@ -0,0 +1,51 @@
export default {
template: `
<form @submit.prevent="add" class="inputData">
<input
required=""
placeholder="Message..."
type="text"
id="messageInput"
v-model="newAssignment"
/>
<button id="sendButton" target="#">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 664 663"
>
<path
fill="none"
d="M646.293 331.888L17.7538 17.6187L155.245 331.888M646.293 331.888L17.753 646.157L155.245 331.888M646.293 331.888L318.735 330.228L155.245 331.888"
></path>
<path
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="33.67"
stroke="#6c6c6c"
d="M646.293 331.888L17.7538 17.6187L155.245 331.888M646.293 331.888L17.753 646.157L155.245 331.888M646.293 331.888L318.735 330. 228L155.245 331.888"
></path>
</svg>
</button>
</form>
`,
data() {
return {
newAssignment: "",
};
},
methods: {
add() {
document.getElementById("messageInput").value = "";
Swal.fire({
title: "Good job!",
text: "Assignment Dibuat",
icon: "success",
});
this.$emit("add", this.newAssignment);
},
},
};

45
components/AssignmentList.js ノーマルファイル
ファイルの表示

@ -0,0 +1,45 @@
import Assignment from "./Assignment.js";
import AssignmentTags from "./AssignmentTags.js";
export default {
components: { Assignment, AssignmentTags },
template: `
<section id="section-1" v-show="assignments.length">
<h2 class="font-bold mb-2">{{ title }} <span>({{ assignments.length }})</span> </h2>
<assignment-tags
:initTags = "assignments.map(a => a.tag)"
:current-tag = "currentTag"
@change="currentTag = $event"
/>
<ul class="mt-6">
<assignment v-for="assignment in assignments" :key="assignment.id" :assignment="assignment"/>
</ul>
</section>
`,
props: {
assignments: Array,
title: String,
},
data() {
return {
currentTag: "all",
};
},
computed: {
filteredAssignments() {
return this.assignments.filter(
(a) => a.tag === this.currentTag || this.currentTag === "all"
);
},
tags() {
return new Set(this.assignments.map((a) => a.tag));
},
},
};

25
components/AssignmentTags.js ノーマルファイル
ファイルの表示

@ -0,0 +1,25 @@
export default {
template: `
<div class="flex gap-2">
<button
class="border rounded p-1 text-xs"
@click="$emit('change', tag)"
v-for="tag in tags"
:class="{ 'border-blue-500 text-blue-400': tag === currentTag}"
>
{{ tag }}
</button>
</div>
`,
props: {
initTags: Array,
currentTag: String,
},
computed: {
tags() {
return ["all", ...new Set(this.initTags)];
},
},
};

51
components/Assignments.js ノーマルファイル
ファイルの表示

@ -0,0 +1,51 @@
import AssignmentList from "./AssignmentList.js";
import AssignmentCreate from "./AssignmentCreate.js";
export default {
components: { AssignmentList, AssignmentCreate },
template: `
<section class="space-y-6 border rounded-lg p-5 grid">
<assignment-list
:assignments="filters.inProgress"
title="Masih Berjalan"
/>
<assignment-list
:assignments="filters.completed"
title="Sudah Selesai!"
/>
<assignment-create @add="add" />
</section>
`,
data() {
return {
assignments: [
{ name: "Check Project", complete: true, id: 1, tag: "math" },
{ name: "Read Books", complete: false, id: 2, tag: "science" },
{ name: "Learn Vue", complete: false, id: 3, tag: "programming" },
],
};
},
computed: {
filters() {
return {
inProgress: this.assignments.filter(
(assignment) => !assignment.complete
),
completed: this.assignments.filter((assignment) => assignment.complete),
};
},
},
methods: {
add(name) {
this.assignments.push({
name: name,
completed: false,
id: this.assignments.length + 1,
});
},
},
};

9
dummy.html ノーマルファイル
ファイルの表示

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
</html>

23
index.html ノーマルファイル
ファイルの表示

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learn Vue</title>
<!-- Style -->
<link href="style.css" rel="stylesheet" />
<!-- Script -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="app"></div>
<script type="module">
import App from "./components/App.js";
Vue.createApp(App).mount("#app");
</script>
</body>
</html>

132
style.css ノーマルファイル
ファイルの表示

@ -0,0 +1,132 @@
html,
body {
width: 100vw;
height: 100vh;
background: #00a08a;
color: whitesmoke;
}
#app {
display: grid;
place-items: center;
height: 100vh;
}
#btn {
scale: 200%;
border-radius: 15px;
outline: none;
border: 1px solid blue;
transition: all 0.2s;
}
#btn:hover {
background: #87ceeb;
color: whitesmoke;
}
#btn:active {
scale: 185%;
}
label,
input[type="checkbox"] {
display: inline-block;
vertical-align: middle;
}
.checkBox {
display: block;
cursor: pointer;
width: 30px;
height: 30px;
border: 3px solid rgba(255, 255, 255, 0);
border-radius: 10px;
position: relative;
overflow: hidden;
box-shadow: 0px 0px 0px 2px #fff;
}
.checkBox div {
width: 60px;
height: 60px;
background-color: #fff;
top: -52px;
left: -52px;
position: absolute;
transform: rotateZ(45deg);
z-index: 100;
}
.checkBox input[type="checkbox"]:checked + div {
left: -10px;
top: -10px;
}
.checkBox input[type="checkbox"] {
position: absolute;
left: 50px;
visibility: hidden;
vertical-align: middle;
}
.transition {
transition: 300ms ease;
}
.inputData {
width: fit-content;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(45, 45, 45, 0.9);
padding: 0 15px;
border-radius: 10px;
border: 2px solid rgb(63, 63, 63);
}
.inputData:focus-within {
border: 2px solid rgb(110, 110, 110);
}
#messageInput {
width: 200px;
height: 100%;
background-color: transparent;
outline: none;
border: none;
padding-left: 10px;
color: white;
}
#messageInput:focus ~ #sendButton svg path,
#messageInput:valid ~ #sendButton svg path {
fill: #3c3c3c;
stroke: white;
}
#sendButton {
width: fit-content;
height: 100%;
background-color: transparent;
outline: none;
border: none;
cursor: pointer;
transition: all 0.3s;
}
#sendButton svg {
height: 18px;
transition: all 0.3s;
}
#sendButton svg path {
transition: all 0.3s;
}
#sendButton:hover svg path {
fill: #3c3c3c;
stroke: white;
scale: 110%;
}
#sendButton:active svg path {
scale: 90%;
}