Initial commit
This commit is contained in:
commit
3ea52e4b54
|
@ -0,0 +1,21 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
<IfModule mod_negotiation.c>
|
||||
Options -MultiViews -Indexes
|
||||
</IfModule>
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
# Handle Authorization Header
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
|
@ -0,0 +1,555 @@
|
|||
/*===== GOOGLE FONTS =====*/
|
||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap");
|
||||
/*===== VARIABLES CSS =====*/
|
||||
:root {
|
||||
--header-height: 3rem;
|
||||
--font-semi: 600;
|
||||
/*===== Colores =====*/
|
||||
/*Purple 260 - Red 355 - Blue 224 - Pink 340*/
|
||||
/* HSL color mode */
|
||||
--hue-color: 199;
|
||||
--first-color: hsl(var(--hue-color), 92%, 83%);
|
||||
--second-color: hsl(var(--hue-color), 56%, 12%);
|
||||
/*===== Fuente y tipografia =====*/
|
||||
--body-font: "Poppins", sans-serif;
|
||||
--big-font-size: 2rem;
|
||||
--h2-font-size: 1.25rem;
|
||||
--normal-font-size: .938rem;
|
||||
--smaller-font-size: .75rem;
|
||||
/*===== Margenes =====*/
|
||||
--mb-2: 1rem;
|
||||
--mb-4: 2rem;
|
||||
--mb-5: 2.5rem;
|
||||
--mb-6: 3rem;
|
||||
/*===== z index =====*/
|
||||
--z-back: -10;
|
||||
--z-fixed: 100;
|
||||
}
|
||||
@media screen and (min-width: 968px) {
|
||||
:root {
|
||||
--big-font-size: 3.5rem;
|
||||
--h2-font-size: 2rem;
|
||||
--normal-font-size: 1rem;
|
||||
--smaller-font-size: .875rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*===== BASE =====*/
|
||||
*, ::before, ::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: var(--header-height) 0 0 0;
|
||||
font-family: var(--body-font);
|
||||
font-size: var(--normal-font-size);
|
||||
color: var(--second-color);
|
||||
}
|
||||
|
||||
h1, h2, p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tutor__video {
|
||||
width: 100%;
|
||||
max-width: 300px; /* Atur ukuran maksimal */
|
||||
border-radius: 10px;
|
||||
border: 2px solid #333;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.video-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 70vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
#video-webcam {
|
||||
width: 100%;
|
||||
max-width: 600px; /* Maksimal ukuran video */
|
||||
border-radius: 5px;
|
||||
border: 3px solid #9191e2;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/*===== CLASS CSS ===== */
|
||||
.section-title {
|
||||
position: relative;
|
||||
font-size: var(--h2-font-size);
|
||||
color: #001f3f;
|
||||
margin-top: var(--mb-5);
|
||||
margin-bottom: var(--mb-1);
|
||||
text-align: center;
|
||||
}
|
||||
.section-title::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 64px;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
|
||||
.section {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
/*===== LAYOUT =====*/
|
||||
.bd-grid {
|
||||
max-width: 1024px;
|
||||
display: grid;
|
||||
margin-left: var(--mb-2);
|
||||
margin-right: var(--mb-2);
|
||||
}
|
||||
|
||||
.l-header {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: var(--z-fixed);
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 4px rgba(146, 161, 176, 0.15);
|
||||
}
|
||||
|
||||
/*===== NAV =====*/
|
||||
.nav {
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: var(--font-semi);
|
||||
}
|
||||
@media screen and (max-width: 767px) {
|
||||
.nav__menu {
|
||||
position: fixed;
|
||||
top: var(--header-height);
|
||||
right: -100%;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
padding: 2rem;
|
||||
background-color: var(--second-color);
|
||||
transition: 0.5s;
|
||||
}
|
||||
}
|
||||
.nav__item {
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
.nav__link {
|
||||
position: relative;
|
||||
color: #fff;
|
||||
}
|
||||
.nav__link:hover {
|
||||
position: relative;
|
||||
}
|
||||
.nav__link:hover::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
.nav__logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--second-color);
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
height: 40px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.nav__toggle {
|
||||
color: var(--second-color);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*Active menu*/
|
||||
.active-link::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
|
||||
/*=== Show menu ===*/
|
||||
.show {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/*===== HOME =====*/
|
||||
.home {
|
||||
position: relative;
|
||||
row-gap: 5rem;
|
||||
padding: 4rem 0 5rem;
|
||||
}
|
||||
.home__data {
|
||||
align-self: center;
|
||||
}
|
||||
.home__title {
|
||||
font-size: var(--big-font-size);
|
||||
margin-bottom: var(--mb-5);
|
||||
}
|
||||
.home__title-color {
|
||||
color: var(--first-color);
|
||||
}
|
||||
.home__social {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.home__social-icon {
|
||||
width: max-content;
|
||||
margin-bottom: var(--mb-2);
|
||||
font-size: 1.5rem;
|
||||
color: var(--second-color);
|
||||
}
|
||||
.home__social-icon:hover {
|
||||
color: var(--first-color);
|
||||
}
|
||||
.home__img {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 260px;
|
||||
}
|
||||
.home__blob {
|
||||
fill: var(--first-color);
|
||||
}
|
||||
.home__blob-img {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
/*BUTTONS*/
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: #001f3f;;
|
||||
color: #fff;
|
||||
padding: 0.75rem 2.5rem;
|
||||
font-weight: var(--font-semi);
|
||||
border-radius: 0.5rem;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.button:hover {
|
||||
box-shadow: 0px 10px 36px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.nav__dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown__menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background-color: white;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: none;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.nav__dropdown:hover .dropdown__menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown__link {
|
||||
display: block;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dropdown__link:hover {
|
||||
background-color: #90c7fb;
|
||||
}
|
||||
|
||||
|
||||
/* ===== ABOUT =====*/
|
||||
.about__container {
|
||||
row-gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.about__subtitle {
|
||||
margin-bottom: var(--mb-2);
|
||||
}
|
||||
.about__img {
|
||||
justify-self: center;
|
||||
}
|
||||
.about__img img {
|
||||
width: 200px;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* ===== SKILLS =====*/
|
||||
.skills__container {
|
||||
row-gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.skills__subtitle {
|
||||
margin-bottom: var(--mb-2);
|
||||
}
|
||||
.skills__text {
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
.skills__data {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
font-weight: var(--font-semi);
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: var(--mb-4);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15);
|
||||
}
|
||||
.skills__icon {
|
||||
font-size: 2rem;
|
||||
margin-right: var(--mb-2);
|
||||
color: var(--first-color);
|
||||
}
|
||||
.skills__names {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.skills__bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--first-color);
|
||||
height: 0.25rem;
|
||||
border-radius: 0.5rem;
|
||||
z-index: var(--z-back);
|
||||
}
|
||||
.skills__html {
|
||||
width: 95%;
|
||||
}
|
||||
.skills__css {
|
||||
width: 85%;
|
||||
}
|
||||
.skills__js {
|
||||
width: 65%;
|
||||
}
|
||||
.skills__ux {
|
||||
width: 85%;
|
||||
}
|
||||
.skills__img {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* ===== WORK =====*/
|
||||
.work__container {
|
||||
row-gap: 2rem;
|
||||
}
|
||||
.work__img {
|
||||
box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
.work__img img {
|
||||
transition: 1s;
|
||||
}
|
||||
.work__img img:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* ===== CONTACT =====*/
|
||||
.contact__input {
|
||||
width: 100%;
|
||||
font-size: var(--normal-font-size);
|
||||
font-weight: var(--font-semi);
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1.5px solid var(--second-color);
|
||||
outline: none;
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
.contact__button {
|
||||
display: block;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: var(--normal-font-size);
|
||||
cursor: pointer;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* ===== FOOTER =====*/
|
||||
.footer {
|
||||
background-color: var(--second-color);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: var(--font-semi);
|
||||
padding: 2rem 0;
|
||||
}
|
||||
.footer__title {
|
||||
font-size: 2rem;
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
.footer__social {
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
.footer__icon {
|
||||
font-size: 1.5rem;
|
||||
color: #fff;
|
||||
margin: 0 var(--mb-2);
|
||||
}
|
||||
.footer__copy {
|
||||
font-size: var(--smaller-font-size);
|
||||
}
|
||||
|
||||
/* ===== MEDIA QUERIES=====*/
|
||||
@media screen and (max-width: 320px) {
|
||||
.home {
|
||||
row-gap: 2rem;
|
||||
}
|
||||
.home__img {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 576px) {
|
||||
.home {
|
||||
padding: 4rem 0 2rem;
|
||||
}
|
||||
.home__social {
|
||||
padding-top: 0;
|
||||
padding-bottom: 2.5rem;
|
||||
flex-direction: row;
|
||||
align-self: flex-end;
|
||||
}
|
||||
.home__social-icon {
|
||||
margin-bottom: 0;
|
||||
margin-right: var(--mb-4);
|
||||
}
|
||||
.home__img {
|
||||
width: 300px;
|
||||
bottom: 25%;
|
||||
}
|
||||
.about__container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
align-items: center;
|
||||
text-align: initial;
|
||||
}
|
||||
.skills__container {
|
||||
grid-template-columns: 0.7fr;
|
||||
justify-content: center;
|
||||
column-gap: 1rem;
|
||||
}
|
||||
.work__container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
column-gap: 2rem;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
.contact__form {
|
||||
width: 360px;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
.contact__container {
|
||||
justify-items: center;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 768px) {
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
.section {
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
.section-title {
|
||||
margin-bottom: var(--mb-6);
|
||||
}
|
||||
.section-title::after {
|
||||
width: 80px;
|
||||
top: 3rem;
|
||||
}
|
||||
.nav {
|
||||
height: calc(var(--header-height) + 1.5rem);
|
||||
}
|
||||
.nav__list {
|
||||
display: flex;
|
||||
padding-top: 0;
|
||||
}
|
||||
.nav__item {
|
||||
margin-left: var(--mb-6);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.nav__toggle {
|
||||
display: none;
|
||||
}
|
||||
.nav__link {
|
||||
color: var(--second-color);
|
||||
}
|
||||
.home {
|
||||
padding: 8rem 0 2rem;
|
||||
}
|
||||
.home__img {
|
||||
width: 400px;
|
||||
bottom: 10%;
|
||||
}
|
||||
.about__container {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
.about__img img {
|
||||
width: 300px;
|
||||
}
|
||||
.skills__container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
column-gap: 2rem;
|
||||
align-items: center;
|
||||
text-align: initial;
|
||||
}
|
||||
.work__container {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
column-gap: 2rem;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 992px) {
|
||||
.bd-grid {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.home {
|
||||
padding: 10rem 0 2rem;
|
||||
}
|
||||
.home__img {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 266 KiB |
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
|
@ -0,0 +1,57 @@
|
|||
/*===== MENU SHOW =====*/
|
||||
const showMenu = (toggleId, navId) =>{
|
||||
const toggle = document.getElementById(toggleId),
|
||||
nav = document.getElementById(navId)
|
||||
|
||||
if(toggle && nav){
|
||||
toggle.addEventListener('click', ()=>{
|
||||
nav.classList.toggle('show')
|
||||
})
|
||||
}
|
||||
}
|
||||
showMenu('nav-toggle','nav-menu')
|
||||
|
||||
/*==================== REMOVE MENU MOBILE ====================*/
|
||||
const navLink = document.querySelectorAll('.nav__link')
|
||||
|
||||
function linkAction(){
|
||||
const navMenu = document.getElementById('nav-menu')
|
||||
// When we click on each nav__link, we remove the show-menu class
|
||||
navMenu.classList.remove('show')
|
||||
}
|
||||
navLink.forEach(n => n.addEventListener('click', linkAction))
|
||||
|
||||
/*==================== SCROLL SECTIONS ACTIVE LINK ====================*/
|
||||
const sections = document.querySelectorAll('section[id]')
|
||||
|
||||
const scrollActive = () =>{
|
||||
const scrollDown = window.scrollY
|
||||
|
||||
sections.forEach(current =>{
|
||||
const sectionHeight = current.offsetHeight,
|
||||
sectionTop = current.offsetTop - 58,
|
||||
sectionId = current.getAttribute('id'),
|
||||
sectionsClass = document.querySelector('.nav__menu a[href*=' + sectionId + ']')
|
||||
|
||||
if(scrollDown > sectionTop && scrollDown <= sectionTop + sectionHeight){
|
||||
sectionsClass.classList.add('active-link')
|
||||
}else{
|
||||
sectionsClass.classList.remove('active-link')
|
||||
}
|
||||
})
|
||||
}
|
||||
window.addEventListener('scroll', scrollActive)
|
||||
|
||||
/*===== SCROLL REVEAL ANIMATION =====*/
|
||||
const sr = ScrollReveal({
|
||||
origin: 'top',
|
||||
distance: '60px',
|
||||
duration: 2000,
|
||||
delay: 200,
|
||||
// reset: true
|
||||
});
|
||||
|
||||
sr.reveal('.home__data, .about__img, .skills__subtitle, .skills__text',{});
|
||||
sr.reveal('.home__img, .about__subtitle, .about__text, .skills__img',{delay: 400});
|
||||
sr.reveal('.home__social-icon',{ interval: 200});
|
||||
sr.reveal('.skills__data, .work__img, .contact__input',{interval: 200});
|
|
@ -0,0 +1,525 @@
|
|||
/*===== GOOGLE FONTS =====*/
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
|
||||
|
||||
/*===== VARIABLES CSS =====*/
|
||||
:root{
|
||||
--header-height: 3rem;
|
||||
--font-semi: 600;
|
||||
|
||||
/*===== Colores =====*/
|
||||
/*Purple 260 - Red 355 - Blue 224 - Pink 340*/
|
||||
/* HSL color mode */
|
||||
--hue-color: 224;
|
||||
--first-color: hsl(var(--hue-color), 89%, 60%);
|
||||
--second-color: hsl(var(--hue-color), 56%, 12%);
|
||||
|
||||
/*===== Fuente y tipografia =====*/
|
||||
--body-font: 'Poppins', sans-serif;
|
||||
|
||||
--big-font-size: 2rem;
|
||||
--h2-font-size: 1.25rem;
|
||||
--normal-font-size: .938rem;
|
||||
--smaller-font-size: .75rem;
|
||||
|
||||
/*===== Margenes =====*/
|
||||
--mb-2: 1rem;
|
||||
--mb-4: 2rem;
|
||||
--mb-5: 2.5rem;
|
||||
--mb-6: 3rem;
|
||||
|
||||
/*===== z index =====*/
|
||||
--z-back: -10;
|
||||
--z-fixed: 100;
|
||||
|
||||
@media screen and (min-width: 968px){
|
||||
--big-font-size: 3.5rem;
|
||||
--h2-font-size: 2rem;
|
||||
--normal-font-size: 1rem;
|
||||
--smaller-font-size: .875rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*===== BASE =====*/
|
||||
*,::before,::after{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html{
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
body{
|
||||
margin: var(--header-height) 0 0 0;
|
||||
font-family: var(--body-font);
|
||||
font-size: var(--normal-font-size);
|
||||
color: var(--second-color);
|
||||
}
|
||||
h1,h2,p{
|
||||
margin: 0;
|
||||
}
|
||||
ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
a{
|
||||
text-decoration: none;
|
||||
}
|
||||
img{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*===== CLASS CSS ===== */
|
||||
.section-title{
|
||||
position: relative;
|
||||
font-size: var(--h2-font-size);
|
||||
color: var(--first-color);
|
||||
margin-top: var(--mb-2);
|
||||
margin-bottom: var(--mb-4);
|
||||
text-align: center;
|
||||
|
||||
&::after{
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 64px;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
}
|
||||
.section{
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
/*===== LAYOUT =====*/
|
||||
.bd-grid{
|
||||
max-width: 1024px;
|
||||
display: grid;
|
||||
margin-left: var(--mb-2);
|
||||
margin-right: var(--mb-2);
|
||||
}
|
||||
.l-header{
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: var(--z-fixed);
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 4px rgba(146,161,176,.15);
|
||||
}
|
||||
|
||||
/*===== NAV =====*/
|
||||
.nav{
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: var(--font-semi);
|
||||
|
||||
&__menu{
|
||||
@media screen and (max-width: 767px){
|
||||
position: fixed;
|
||||
top: var(--header-height);
|
||||
right: -100%;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
padding: 2rem;
|
||||
background-color: var(--second-color);
|
||||
transition: .5s;
|
||||
}
|
||||
}
|
||||
&__item{
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
&__link{
|
||||
position: relative;
|
||||
color: #fff;
|
||||
|
||||
&:hover{
|
||||
position: relative;
|
||||
|
||||
&::after{
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&__logo{
|
||||
color: var(--second-color);
|
||||
}
|
||||
&__toggle{
|
||||
color: var(--second-color);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
/*Active menu*/
|
||||
.active-link::after{
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0.18rem;
|
||||
left: 0;
|
||||
top: 2rem;
|
||||
background-color: var(--first-color);
|
||||
}
|
||||
|
||||
/*=== Show menu ===*/
|
||||
.show{
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/*===== HOME =====*/
|
||||
.home{
|
||||
position: relative;
|
||||
row-gap: 5rem;
|
||||
padding: 4rem 0 5rem;
|
||||
|
||||
&__data{
|
||||
align-self: center;
|
||||
}
|
||||
&__title{
|
||||
font-size: var(--big-font-size);
|
||||
margin-bottom: var(--mb-5);
|
||||
|
||||
&-color{
|
||||
color: var(--first-color);
|
||||
}
|
||||
}
|
||||
&__social{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&-icon{
|
||||
width: max-content;
|
||||
margin-bottom: var(--mb-2);
|
||||
font-size: 1.5rem;
|
||||
color: var(--second-color);
|
||||
|
||||
&:hover{
|
||||
color: var(--first-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__img{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 260px;
|
||||
}
|
||||
&__blob{
|
||||
fill: var(--first-color);
|
||||
|
||||
&-img{
|
||||
width: 360px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*BUTTONS*/
|
||||
.button{
|
||||
display: inline-block;
|
||||
background-color: var(--first-color);
|
||||
color: #fff;
|
||||
padding: .75rem 2.5rem;
|
||||
font-weight: var(--font-semi);
|
||||
border-radius: .5rem;
|
||||
transition: .3s;
|
||||
|
||||
&:hover{
|
||||
box-shadow: 0px 10px 36px rgba(0,0,0,.15);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== ABOUT =====*/
|
||||
.about{
|
||||
&__container{
|
||||
row-gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
&__subtitle{
|
||||
margin-bottom: var(--mb-2);
|
||||
}
|
||||
|
||||
&__img{
|
||||
justify-self: center;
|
||||
|
||||
& img{
|
||||
width: 200px;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== SKILLS =====*/
|
||||
.skills{
|
||||
&__container{
|
||||
row-gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
&__subtitle{
|
||||
margin-bottom: var(--mb-2);
|
||||
}
|
||||
&__text{
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
&__data{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
font-weight: var(--font-semi);
|
||||
padding: .5rem 1rem;
|
||||
margin-bottom: var(--mb-4);
|
||||
border-radius: .5rem;
|
||||
box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15);
|
||||
}
|
||||
&__icon{
|
||||
font-size: 2rem;
|
||||
margin-right: var(--mb-2);
|
||||
color: var(--first-color);
|
||||
}
|
||||
&__names{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
&__bar{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--first-color);
|
||||
height: .25rem;
|
||||
border-radius: .5rem;
|
||||
z-index: var(--z-back);
|
||||
}
|
||||
&__html{
|
||||
width: 95%;
|
||||
}
|
||||
&__css{
|
||||
width: 85%;
|
||||
}
|
||||
&__js{
|
||||
width: 65%;
|
||||
}
|
||||
&__ux{
|
||||
width: 85%;
|
||||
}
|
||||
&__img{
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
/* ===== WORK =====*/
|
||||
.work{
|
||||
&__container{
|
||||
row-gap: 2rem;
|
||||
}
|
||||
&__img{
|
||||
box-shadow: 0px 4px 25px rgba(14, 36, 49, 0.15);
|
||||
border-radius: .5rem;
|
||||
overflow: hidden;
|
||||
|
||||
& img{
|
||||
transition: 1s;
|
||||
|
||||
&:hover{
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== CONTACT =====*/
|
||||
.contact{
|
||||
&__input{
|
||||
width: 100%;
|
||||
font-size: var(--normal-font-size);
|
||||
font-weight: var(--font-semi);
|
||||
padding: 1rem;
|
||||
border-radius: .5rem;
|
||||
border: 1.5px solid var(--second-color);
|
||||
outline: none;
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
&__button{
|
||||
display: block;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: var(--normal-font-size);
|
||||
cursor: pointer;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== FOOTER =====*/
|
||||
.footer{
|
||||
background-color: var(--second-color);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: var(--font-semi);
|
||||
padding: 2rem 0;
|
||||
|
||||
&__title{
|
||||
font-size: 2rem;
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
&__social{
|
||||
margin-bottom: var(--mb-4);
|
||||
}
|
||||
&__icon{
|
||||
font-size: 1.5rem;
|
||||
color: #fff;
|
||||
margin: 0 var(--mb-2);
|
||||
}
|
||||
&__copy{
|
||||
font-size: var(--smaller-font-size);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== MEDIA QUERIES=====*/
|
||||
@media screen and (max-width: 320px){
|
||||
.home{
|
||||
row-gap: 2rem;
|
||||
|
||||
&__img{
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 576px){
|
||||
.home{
|
||||
padding: 4rem 0 2rem;
|
||||
&__social{
|
||||
padding-top: 0;
|
||||
padding-bottom: 2.5rem;
|
||||
flex-direction: row;
|
||||
align-self: flex-end;
|
||||
|
||||
&-icon{
|
||||
margin-bottom: 0;
|
||||
margin-right: var(--mb-4);
|
||||
}
|
||||
}
|
||||
&__img{
|
||||
width: 300px;
|
||||
bottom: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.about__container{
|
||||
grid-template-columns: repeat(2,1fr);
|
||||
align-items: center;
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
.skills__container{
|
||||
grid-template-columns: .7fr;
|
||||
justify-content: center;
|
||||
column-gap: 1rem;
|
||||
}
|
||||
|
||||
.work__container{
|
||||
grid-template-columns: repeat(2,1fr);
|
||||
column-gap: 2rem;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.contact{
|
||||
&__form{
|
||||
width: 360px;
|
||||
padding-top: 2rem ;
|
||||
}
|
||||
&__container{
|
||||
justify-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px){
|
||||
body{
|
||||
margin: 0;
|
||||
}
|
||||
.section{
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.section-title{
|
||||
margin-bottom: var(--mb-6);
|
||||
|
||||
&::after{
|
||||
width: 80px;
|
||||
top: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.nav{
|
||||
height: calc(var(--header-height) + 1.5rem);
|
||||
&__list{
|
||||
display: flex;
|
||||
padding-top: 0;
|
||||
}
|
||||
&__item{
|
||||
margin-left: var(--mb-6);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&__toggle{
|
||||
display: none;
|
||||
}
|
||||
&__link{
|
||||
color: var(--second-color);
|
||||
}
|
||||
}
|
||||
.home{
|
||||
padding: 8rem 0 2rem;
|
||||
|
||||
&__img{
|
||||
width: 400px;
|
||||
bottom: 10%;
|
||||
}
|
||||
}
|
||||
|
||||
.about{
|
||||
&__container{
|
||||
padding-top: 2rem;
|
||||
}
|
||||
&__img{
|
||||
& img{
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.skills__container{
|
||||
grid-template-columns: repeat(2,1fr);
|
||||
column-gap: 2rem;
|
||||
align-items: center;
|
||||
text-align: initial;
|
||||
}
|
||||
.work__container{
|
||||
grid-template-columns: repeat(3,1fr);
|
||||
column-gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px){
|
||||
.bd-grid{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.home{
|
||||
padding: 10rem 0 2rem;
|
||||
|
||||
&__img{
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Contracts\Http\Kernel;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Check If The Application Is Under Maintenance
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If the application is in maintenance / demo mode via the "down" command
|
||||
| we will load this file so that any pre-rendered content can be shown
|
||||
| instead of starting the framework, which could cause an exception.
|
||||
|
|
||||
*/
|
||||
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
require $maintenance;
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register The Auto Loader
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Composer provides a convenient, automatically generated class loader for
|
||||
| this application. We just need to utilize it! We'll simply require it
|
||||
| into the script here so we don't need to manually load our classes.
|
||||
|
|
||||
*/
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Run The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Once we have the application, we can handle the incoming request using
|
||||
| the application's HTTP kernel. Then, we will send the response back
|
||||
| to this client's browser, allowing them to enjoy our application.
|
||||
|
|
||||
*/
|
||||
|
||||
$app = require_once __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
$kernel = $app->make(Kernel::class);
|
||||
|
||||
$response = $kernel->handle(
|
||||
$request = Request::capture()
|
||||
)->send();
|
||||
|
||||
$kernel->terminate($request, $response);
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
{"format": "layers-model", "generatedBy": "keras v2.14.0", "convertedBy": "TensorFlow.js Converter v4.22.0", "modelTopology": {"keras_version": "2.14.0", "backend": "tensorflow", "model_config": {"class_name": "Sequential", "config": {"name": "sequential", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": [null, 99], "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}}, {"class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 14, "activation": "softmax", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}}, "training_config": {"loss": "categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "categorical_accuracy", "dtype": "float32", "fn": "categorical_accuracy"}}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Custom>Adam", "config": {"name": "Adam", "weight_decay": null, "clipnorm": null, "global_clipnorm": null, "clipvalue": null, "use_ema": false, "ema_momentum": 0.99, "ema_overwrite_frequency": null, "jit_compile": false, "is_legacy_optimizer": false, "learning_rate": 0.0010000000474974513, "beta_1": 0.9, "beta_2": 0.999, "epsilon": 1e-07, "amsgrad": false}}}}, "weightsManifest": [{"paths": ["group1-shard1of1.bin"], "weights": [{"name": "dense/kernel", "shape": [99, 32], "dtype": "float32"}, {"name": "dense/bias", "shape": [32], "dtype": "float32"}, {"name": "dense_1/kernel", "shape": [32, 64], "dtype": "float32"}, {"name": "dense_1/bias", "shape": [64], "dtype": "float32"}, {"name": "dense_2/kernel", "shape": [64, 128], "dtype": "float32"}, {"name": "dense_2/bias", "shape": [128], "dtype": "float32"}, {"name": "dense_3/kernel", "shape": [128, 14], "dtype": "float32"}, {"name": "dense_3/bias", "shape": [14], "dtype": "float32"}]}]}
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
{"format": "layers-model", "generatedBy": "keras v2.14.0", "convertedBy": "TensorFlow.js Converter v4.22.0", "modelTopology": {"keras_version": "2.14.0", "backend": "tensorflow", "model_config": {"class_name": "Sequential", "config": {"name": "sequential", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": [null, 99], "dtype": "float32", "sparse": false, "ragged": false, "name": "input_1"}}, {"class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 14, "activation": "softmax", "use_bias": true, "kernel_initializer": {"module": "keras.initializers", "class_name": "GlorotUniform", "config": {"seed": null}, "registered_name": null}, "bias_initializer": {"module": "keras.initializers", "class_name": "Zeros", "config": {}, "registered_name": null}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}}, "training_config": {"loss": "categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "categorical_accuracy", "dtype": "float32", "fn": "categorical_accuracy"}}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Custom>Adam", "config": {"name": "Adam", "weight_decay": null, "clipnorm": null, "global_clipnorm": null, "clipvalue": null, "use_ema": false, "ema_momentum": 0.99, "ema_overwrite_frequency": null, "jit_compile": false, "is_legacy_optimizer": false, "learning_rate": 0.0010000000474974513, "beta_1": 0.9, "beta_2": 0.999, "epsilon": 1e-07, "amsgrad": false}}}}, "weightsManifest": [{"paths": ["group1-shard1of1.bin"], "weights": [{"name": "dense/kernel", "shape": [99, 32], "dtype": "float32"}, {"name": "dense/bias", "shape": [32], "dtype": "float32"}, {"name": "dense_1/kernel", "shape": [32, 64], "dtype": "float32"}, {"name": "dense_1/bias", "shape": [64], "dtype": "float32"}, {"name": "dense_2/kernel", "shape": [64, 128], "dtype": "float32"}, {"name": "dense_2/bias", "shape": [128], "dtype": "float32"}, {"name": "dense_3/kernel", "shape": [128, 14], "dtype": "float32"}, {"name": "dense_3/bias", "shape": [14], "dtype": "float32"}]}]}
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow:
|
|
@ -0,0 +1 @@
|
|||
import './bootstrap';
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// import Pusher from 'pusher-js';
|
||||
// window.Pusher = Pusher;
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
||||
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
|
||||
// wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
||||
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
||||
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
||||
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
||||
// enabledTransports: ['ws', 'wss'],
|
||||
// });
|
|
@ -0,0 +1,202 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Deteksi Real-Time')
|
||||
|
||||
@section('contents')
|
||||
<section class="about section" id="about">
|
||||
<h2 class="section-title text-center">Deteksi Pose Jurus 1 Tangan Kosong IPSI</h2>
|
||||
<div class="about__container" style="display: flex; flex-wrap: wrap; justify-content: center; gap: 20px;">
|
||||
<div class="video-container" style="position: relative;">
|
||||
<video id="webcam" width="640" height="480" autoplay playsinline muted></video>
|
||||
<canvas id="output-canvas" width="640" height="480"
|
||||
style="position: absolute; top: 0; left: 0;"></canvas>
|
||||
</div>
|
||||
<div id="prediction-result" class="prediction-box">
|
||||
<p>Prediksi: <span id="pose-label">-</span></p>
|
||||
<p>Probability: <span id="pose-accuracy">-</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/pose"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils"></script>
|
||||
|
||||
<script>
|
||||
const poseClasses = [
|
||||
'A1_benar', 'A1_salah','A2_benar', 'A2_salah', 'A3_benar', 'A3_salah',
|
||||
'A4_benar', 'A4_salah', 'A5_benar', 'A5_salah', 'A6_benar', 'A6_salah',
|
||||
'A7_benar', 'A7_salah'
|
||||
];
|
||||
|
||||
const videoElement = document.getElementById('webcam');
|
||||
const canvasElement = document.getElementById('output-canvas');
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
const poseLabelElement = document.getElementById('pose-label');
|
||||
const poseAccuracyElement = document.getElementById('pose-accuracy');
|
||||
|
||||
let model = null;
|
||||
let poseDetector = null;
|
||||
let camera = null;
|
||||
|
||||
async function loadModel() {
|
||||
try {
|
||||
model = await tf.loadLayersModel('/models/model.json');
|
||||
console.log('✅ Model loaded');
|
||||
} catch (err) {
|
||||
console.error('❌ Gagal load model:', err);
|
||||
alert('Model gagal dimuat');
|
||||
}
|
||||
}
|
||||
|
||||
function setupPose() {
|
||||
poseDetector = new Pose({
|
||||
locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`
|
||||
});
|
||||
|
||||
poseDetector.setOptions({
|
||||
modelComplexity: 1,
|
||||
smoothLandmarks: true,
|
||||
enableSegmentation: false,
|
||||
minDetectionConfidence: 0.5,
|
||||
minTrackingConfidence: 0.5
|
||||
});
|
||||
|
||||
poseDetector.onResults(onPoseResults);
|
||||
}
|
||||
|
||||
function onPoseResults(results) {
|
||||
if (!results.poseLandmarks) return;
|
||||
|
||||
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
ctx.drawImage(results.image, 0, 0, canvasElement.width, canvasElement.height);
|
||||
|
||||
drawLandmarks(results.poseLandmarks);
|
||||
|
||||
const landmarks = results.poseLandmarks.map(landmark => [
|
||||
landmark.x * canvasElement.height,
|
||||
landmark.y * canvasElement.height,
|
||||
landmark.z * canvasElement.width
|
||||
]).flat();
|
||||
|
||||
predictPose(landmarks);
|
||||
}
|
||||
|
||||
function drawLandmarks(landmarks) {
|
||||
drawConnections(landmarks);
|
||||
ctx.fillStyle = '#FF0000';
|
||||
landmarks.forEach(landmark => {
|
||||
ctx.beginPath();
|
||||
ctx.arc(landmark.x * canvasElement.width, landmark.y * canvasElement.height, 4, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
});
|
||||
}
|
||||
|
||||
function drawConnections(landmarks) {
|
||||
const connections = [
|
||||
[0, 1], [1, 2], [2, 3], [3, 7], [0, 4], [4, 5], [5, 6], [6, 8],
|
||||
[11, 13], [13, 15], [15, 17], [15, 19], [15, 21],
|
||||
[12, 14], [14, 16], [16, 18], [16, 20], [16, 22],
|
||||
[11, 12], [11, 23], [12, 24], [23, 24],
|
||||
[23, 25], [25, 27], [27, 29], [27, 31],
|
||||
[24, 26], [26, 28], [28, 30], [28, 32]
|
||||
];
|
||||
|
||||
ctx.strokeStyle = '#00FF00';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
connections.forEach(([i, j]) => {
|
||||
if (landmarks[i] && landmarks[j]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(landmarks[i].x * canvasElement.width, landmarks[i].y * canvasElement.height);
|
||||
ctx.lineTo(landmarks[j].x * canvasElement.width, landmarks[j].y * canvasElement.height);
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function predictPose(landmarks) {
|
||||
if (!model) return;
|
||||
|
||||
const inputTensor = tf.tensor2d([landmarks]);
|
||||
const prediction = model.predict(inputTensor);
|
||||
const [predictedClass] = await prediction.argMax(1).data();
|
||||
const confidence = await prediction.max(1).data();
|
||||
|
||||
poseLabelElement.textContent = poseClasses[predictedClass] || 'Unknown';
|
||||
poseAccuracyElement.textContent = `${(confidence[0]).toFixed(4)}`;
|
||||
|
||||
inputTensor.dispose();
|
||||
prediction.dispose();
|
||||
}
|
||||
|
||||
function startCamera() {
|
||||
camera = new Camera(videoElement, {
|
||||
onFrame: async () => {
|
||||
await poseDetector.send({ image: videoElement });
|
||||
},
|
||||
width: 640,
|
||||
height: 480
|
||||
});
|
||||
camera.start();
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await loadModel();
|
||||
setupPose();
|
||||
startCamera();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.section-title {
|
||||
text-align: center;
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 20px;
|
||||
color: #001f3f; /* biru dongker */
|
||||
}
|
||||
|
||||
.about__container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.prediction-box {
|
||||
flex-shrink: 0;
|
||||
width: 280px;
|
||||
height: fit-content;
|
||||
padding: 20px;
|
||||
background: #f4f4f4;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
font-size: 1.2rem;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
#pose-label {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
#pose-accuracy {
|
||||
font-weight: bold;
|
||||
color: #27ae60;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
|
@ -0,0 +1,289 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Deteksi Video')
|
||||
|
||||
@section('contents')
|
||||
<section class="about section" id="about">
|
||||
<h2 class="section-title text-center">Deteksi Pose Jurus 1 Tangan Kosong IPSI</h2>
|
||||
<div class="about__container">
|
||||
<div style="display: flex; gap: 20px; flex-wrap: wrap; justify-content: center;">
|
||||
<div class="video-container">
|
||||
<video id="video-upload" controls></video>
|
||||
<canvas id="output-canvas"></canvas>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-center mt-4 flex gap-3 justify-center">
|
||||
<label class="cursor-pointer inline-block px-6 py-3 bg-blue-600 text-white rounded-xl shadow hover:bg-blue-700 transition">
|
||||
Upload Video
|
||||
<input type="file" accept="video/*" onchange="handleVideoUpload(event)" class="hidden" id="video-input">
|
||||
</label>
|
||||
<button onclick="resetVideo()" class="inline-block px-6 py-3 bg-red-600 text-white rounded-xl shadow hover:bg-red-700 transition">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
<div id="prediction-result" class="prediction-box mt-4">
|
||||
<p>Prediksi: <span id="pose-label">-</span></p>
|
||||
<p>Probability: <span id="pose-accuracy">-</span></p>
|
||||
<ul id="all-probabilities" class="text-left mt-2"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/pose"></script>
|
||||
|
||||
<script>
|
||||
const poseClasses = [
|
||||
'A1_benar', 'A1_salah','A2_benar', 'A2_salah', 'A3_benar', 'A3_salah',
|
||||
'A4_benar', 'A4_salah', 'A5_benar', 'A5_salah', 'A6_benar', 'A6_salah',
|
||||
'A7_benar', 'A7_salah'
|
||||
];
|
||||
|
||||
const videoElement = document.getElementById('video-upload');
|
||||
const canvasElement = document.getElementById('output-canvas');
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
const poseLabelElement = document.getElementById('pose-label');
|
||||
const poseAccuracyElement = document.getElementById('pose-accuracy');
|
||||
const fileInput = document.getElementById('video-input');
|
||||
const probList = document.getElementById('all-probabilities');
|
||||
|
||||
let model = null;
|
||||
let poseDetector = null;
|
||||
let animationFrameId = null;
|
||||
|
||||
async function loadTFModel() {
|
||||
try {
|
||||
model = await tf.loadLayersModel('/models/model.json');
|
||||
console.log('✅ Model loaded');
|
||||
} catch (error) {
|
||||
alert('Model gagal dimuat');
|
||||
}
|
||||
}
|
||||
|
||||
function setupPoseDetection() {
|
||||
poseDetector = new Pose({
|
||||
locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`
|
||||
});
|
||||
|
||||
poseDetector.setOptions({
|
||||
modelComplexity: 1,
|
||||
smoothLandmarks: true,
|
||||
enableSegmentation: false,
|
||||
minDetectionConfidence: 0.5,
|
||||
minTrackingConfidence: 0.5
|
||||
});
|
||||
|
||||
poseDetector.onResults(onPoseResults);
|
||||
}
|
||||
|
||||
function onPoseResults(results) {
|
||||
if (!results.poseLandmarks) return;
|
||||
|
||||
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
ctx.drawImage(results.image, 0, 0, canvasElement.width, canvasElement.height);
|
||||
|
||||
drawLandmarks(results.poseLandmarks);
|
||||
|
||||
const landmarks = results.poseLandmarks.map(landmark => [
|
||||
landmark.x * canvasElement.height,
|
||||
landmark.y * canvasElement.height,
|
||||
landmark.z * canvasElement.width
|
||||
]).flat();
|
||||
|
||||
predictPose(landmarks);
|
||||
}
|
||||
|
||||
function drawLandmarks(landmarks) {
|
||||
drawConnections(landmarks);
|
||||
|
||||
ctx.fillStyle = '#FF0000';
|
||||
landmarks.forEach(landmark => {
|
||||
ctx.beginPath();
|
||||
ctx.arc(landmark.x * canvasElement.width, landmark.y * canvasElement.height, 5, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
});
|
||||
}
|
||||
|
||||
function drawConnections(landmarks) {
|
||||
const connections = [
|
||||
[0, 1], [1, 2], [2, 3], [3, 7], [0, 4], [4, 5], [5, 6], [6, 8],
|
||||
[11, 13], [13, 15], [15, 17], [15, 19], [15, 21],
|
||||
[12, 14], [14, 16], [16, 18], [16, 20], [16, 22],
|
||||
[11, 12], [11, 23], [12, 24], [23, 24],
|
||||
[23, 25], [25, 27], [27, 29], [27, 31],
|
||||
[24, 26], [26, 28], [28, 30], [28, 32]
|
||||
];
|
||||
|
||||
ctx.strokeStyle = '#00FF00';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
connections.forEach(([i, j]) => {
|
||||
if (landmarks[i] && landmarks[j]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(landmarks[i].x * canvasElement.width, landmarks[i].y * canvasElement.height);
|
||||
ctx.lineTo(landmarks[j].x * canvasElement.width, landmarks[j].y * canvasElement.height);
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function predictPose(landmarks) {
|
||||
if (!model) return;
|
||||
|
||||
const inputTensor = tf.tensor2d([landmarks]);
|
||||
const prediction = model.predict(inputTensor);
|
||||
|
||||
const predictionData = await prediction.data();
|
||||
const [predictedClass] = await prediction.argMax(1).data();
|
||||
const confidence = predictionData[predictedClass];
|
||||
|
||||
poseLabelElement.textContent = poseClasses[predictedClass] || 'Unknown';
|
||||
poseAccuracyElement.textContent = `${confidence.toFixed(4)}`;
|
||||
|
||||
// Tampilkan semua probabilitas
|
||||
probList.innerHTML = '';
|
||||
predictionData.forEach((prob, idx) => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = `${poseClasses[idx] || 'Label-' + idx}: ${prob.toFixed(4)}`;
|
||||
probList.appendChild(li);
|
||||
});
|
||||
|
||||
inputTensor.dispose();
|
||||
prediction.dispose();
|
||||
}
|
||||
|
||||
function handleVideoUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const url = URL.createObjectURL(file);
|
||||
videoElement.src = url;
|
||||
videoElement.load();
|
||||
|
||||
videoElement.onloadedmetadata = () => {
|
||||
canvasElement.width = videoElement.videoWidth;
|
||||
canvasElement.height = videoElement.videoHeight;
|
||||
};
|
||||
}
|
||||
|
||||
function analyzeVideoFrame() {
|
||||
if (!poseDetector || !videoElement) return;
|
||||
|
||||
const process = async () => {
|
||||
if (videoElement.paused || videoElement.ended) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
return;
|
||||
}
|
||||
await poseDetector.send({ image: videoElement });
|
||||
animationFrameId = requestAnimationFrame(process);
|
||||
};
|
||||
|
||||
animationFrameId = requestAnimationFrame(process);
|
||||
}
|
||||
|
||||
function resetVideo() {
|
||||
videoElement.pause();
|
||||
videoElement.currentTime = 0;
|
||||
videoElement.removeAttribute('src');
|
||||
videoElement.load();
|
||||
|
||||
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||
|
||||
poseLabelElement.textContent = '-';
|
||||
poseAccuracyElement.textContent = '-';
|
||||
probList.innerHTML = '';
|
||||
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
|
||||
fileInput.value = '';
|
||||
}
|
||||
|
||||
videoElement.addEventListener('play', () => {
|
||||
analyzeVideoFrame();
|
||||
});
|
||||
videoElement.addEventListener('pause', () => {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
});
|
||||
videoElement.addEventListener('ended', () => {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
});
|
||||
|
||||
async function initializeApp() {
|
||||
await loadTFModel();
|
||||
setupPoseDetection();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initializeApp);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.section-title {
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
video, canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.prediction-box {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
#pose-label {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
#pose-accuracy {
|
||||
font-weight: bold;
|
||||
color: #27ae60;
|
||||
}
|
||||
|
||||
#all-probabilities {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
margin-top: 10px;
|
||||
font-size: 0.95rem;
|
||||
text-align: left;
|
||||
}
|
||||
#all-probabilities li {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
canvas {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
|
@ -0,0 +1,43 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Home')
|
||||
|
||||
@section('contents')
|
||||
<section class="home bd-grid" id="home">
|
||||
<div class="home__data">
|
||||
<h1 class="home__title">Welcome,<br>Pose<span class="home__title-color"> Detection</span><br> Website</h1>
|
||||
|
||||
<a href="{{ route('realtime') }}" class="button">Coba Deteksi</a>
|
||||
</div>
|
||||
|
||||
<div class="home__social">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="home__img">
|
||||
<svg class="home__blob" viewBox="0 0 479 467" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<mask id="mask0" mask-type="alpha">
|
||||
<path d="M9.19024 145.964C34.0253 76.5814 114.865 54.7299 184.111 29.4823C245.804 6.98884 311.86 -14.9503 370.735 14.143C431.207 44.026 467.948 107.508 477.191 174.311C485.897 237.229 454.931 294.377 416.506 344.954C373.74 401.245 326.068 462.801 255.442 466.189C179.416 469.835 111.552 422.137 65.1576 361.805C17.4835 299.81 -17.1617 219.583 9.19024 145.964Z"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0)">
|
||||
<path d="M9.19024 145.964C34.0253 76.5814 114.865 54.7299 184.111 29.4823C245.804 6.98884 311.86 -14.9503 370.735 14.143C431.207 44.026 467.948 107.508 477.191 174.311C485.897 237.229 454.931 294.377 416.506 344.954C373.74 401.245 326.068 462.801 255.442 466.189C179.416 469.835 111.552 422.137 65.1576 361.805C17.4835 299.81 -17.1617 219.583 9.19024 145.964Z"/>
|
||||
<image class="home__blob-img" x="90" y="30" href="{{asset('assets/img/silat.png')}}"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</section>
|
||||
<!--===== ABOUT =====-->
|
||||
<section class="about section " id="about">
|
||||
<h2 class="section-title">About</h2>
|
||||
<div class="about__container bd-grid">
|
||||
<div class="about__img">
|
||||
<img src="{{asset('assets/img/silat.png')}}" alt="">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="about__subtitle">PoseAI</h2>
|
||||
<p class="about__text">Merupakan website untuk deteksi 7 gerakan pada jurus 1 tangan kosong IPSI. Menggunakan teknologi AI yaitu Mediapipe untuk model deteksinya.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" type="image/png" href="{{ asset('assets/img/silat2.png') }}">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{{asset('assets/css/styles.css')}}">
|
||||
|
||||
<!-- =====BOX ICONS===== -->
|
||||
<link href='https://cdn.jsdelivr.net/npm/boxicons@2.0.5/css/boxicons.min.css' rel='stylesheet'>
|
||||
|
||||
<title>Deteksi Pose </title>
|
||||
</head>
|
||||
<body>
|
||||
<!--===== HEADER =====-->
|
||||
<header class="l-header">
|
||||
@include('layouts.navbar')
|
||||
</header>
|
||||
|
||||
<main class="l-main">
|
||||
<!--===== HOME =====-->
|
||||
@yield('contents')
|
||||
@yield('script')
|
||||
</main>
|
||||
|
||||
<!--===== FOOTER =====-->
|
||||
|
||||
@include('layouts.footer')
|
||||
|
||||
<!--===== SCROLL REVEAL =====-->
|
||||
<script src="https://unpkg.com/scrollreveal"></script>
|
||||
|
||||
<!--===== MAIN JS =====-->
|
||||
<script src="{{asset('assets/js/main.js')}}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<footer class="footer">
|
||||
<p class="footer__title">Contact</p>
|
||||
<div class="footer__social">
|
||||
<a href="https://id.linkedin.com/in/eka-sulistyaningsih" class="footer__icon"><i class='bx bxl-linkedin' ></i></a>
|
||||
<a href="https://github.com/ekastn15" class="footer__icon"><i class='bx bxl-github' ></i></a>
|
||||
<a href="https://wa.me/6282127686455" class="footer__icon"><i class='bx bxl-whatsapp' ></i></a>
|
||||
</div>
|
||||
<p class="footer__copy">© 2025. All rigths reserved</p>
|
||||
</footer>
|
|
@ -0,0 +1,23 @@
|
|||
<nav class="nav bd-grid">
|
||||
<div class="nav__logo">
|
||||
<img src="{{ asset('assets/img/silat.png') }}" alt="Logo" class="logo-img">
|
||||
<span>PoseAI Silat</span>
|
||||
</div>
|
||||
<div class="nav__menu" id="nav-menu">
|
||||
<ul class="nav__list">
|
||||
<li class="nav__item"><a href="{{ route('home') }}" class="nav__link {{ Request::is('/') ? 'active-link' : '' }}">Beranda</a></li>
|
||||
<li class="nav__item"><a href="{{ route('tutorial') }}" class="nav__link nav__link {{ Request::is('tutorial') ? 'active-link' : '' }}">Tutorial</a></li>
|
||||
<li class="nav__item nav__dropdown">Deteksi
|
||||
<ul class="dropdown__menu">
|
||||
<li><a href="{{ route('upload') }}" class="dropdown__link">Upload Video</a></li>
|
||||
<li><a href="{{ route('realtime') }}" class="dropdown__link">Realtime</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="nav__toggle" id="nav-toggle">
|
||||
<i class='bx bx-menu'></i>
|
||||
</div>
|
||||
</nav>
|
|
@ -0,0 +1,48 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Tutorial')
|
||||
|
||||
@section('contents')
|
||||
<!--===== WORK (TUTORIAL VIDEO) =====-->
|
||||
<section class="work section" id="work">
|
||||
<h2 class="section-title">Tutorial</h2>
|
||||
<div class="work__container bd-grid">
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A1003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A2003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A3003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A4003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A5003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A6003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
<video class="tutor__video" controls>
|
||||
<source src="{{ asset('assets/videos/A7003.mp4') }}" type="video/mp4">
|
||||
Browser Anda tidak mendukung tag video.
|
||||
</video>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register API routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider and all of them will
|
||||
| be assigned to the "api" middleware group. Make something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
||||
return $request->user();
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Broadcast Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may register all of the event broadcasting channels that your
|
||||
| application supports. The given channel authorization callbacks are
|
||||
| used to check if an authenticated user can listen to the channel.
|
||||
|
|
||||
*/
|
||||
|
||||
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
|
||||
return (int) $user->id === (int) $id;
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Console Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is where you may define all of your Closure based console
|
||||
| commands. Each Closure is bound to a command instance allowing a
|
||||
| simple approach to interacting with each command's IO methods.
|
||||
|
|
||||
*/
|
||||
|
||||
Artisan::command('inspire', function () {
|
||||
$this->comment(Inspiring::quote());
|
||||
})->purpose('Display an inspiring quote');
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Web Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register web routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider and all of them will
|
||||
| be assigned to the "web" middleware group. Make something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::get('/',function () {
|
||||
return view('home');
|
||||
})->name('home');
|
||||
|
||||
Route::get('/tutorial',function () {
|
||||
return view('tutorial.index');
|
||||
})->name('tutorial');
|
||||
|
||||
Route::get('/deteksi/upload',function () {
|
||||
return view('deteksi.upload');
|
||||
})->name('upload');
|
||||
|
||||
Route::get('/deteksi/realtime',function () {
|
||||
return view('deteksi.realtime');
|
||||
})->name('realtime');
|
||||
|
||||
// Route::get('/', function () {
|
||||
// return view('welcome');
|
||||
// });
|
Loading…
Reference in New Issue