@ -0,0 +1,6 @@ |
||||
export default { |
||||
plugins: { |
||||
tailwindcss: {}, |
||||
autoprefixer: {}, |
||||
}, |
||||
} |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 518 B |
After Width: | Height: | Size: 601 B |
After Width: | Height: | Size: 409 B |
After Width: | Height: | Size: 645 B |
After Width: | Height: | Size: 486 B |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 376 B |
@ -1,139 +1,27 @@ |
||||
:root { |
||||
--font-familly: "Ubuntu Mono"; |
||||
@tailwind base; |
||||
@tailwind components; |
||||
@tailwind utilities; |
||||
|
||||
@layer utilities { |
||||
/* Hide scrollbar for Chrome, Safari and Opera */ |
||||
.no-scrollbar::-webkit-scrollbar { |
||||
display: none; |
||||
} |
||||
/* Hide scrollbar for IE, Edge and Firefox */ |
||||
.no-scrollbar { |
||||
-ms-overflow-style: none; /* IE and Edge */ |
||||
scrollbar-width: none; /* Firefox */ |
||||
} |
||||
} |
||||
|
||||
::-webkit-scrollbar { |
||||
width: 0 !important |
||||
:root { |
||||
--font-familly: "Ubuntu Mono"; |
||||
} |
||||
|
||||
body { |
||||
padding: 0; |
||||
margin: 0; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
height: 100vh; |
||||
width: 100%; |
||||
font-family: var(--font-familly); |
||||
} |
||||
|
||||
a { |
||||
padding: 0; |
||||
margin: 0; |
||||
color: inherit; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
button { |
||||
padding: 0; |
||||
margin: 0; |
||||
font-family: var(--font-familly); |
||||
} |
||||
|
||||
input { |
||||
padding: 0; |
||||
margin: 0; |
||||
font-family: var(--font-familly); |
||||
} |
||||
|
||||
|
||||
main { |
||||
padding-top: 20px; |
||||
width: 100%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.menu { |
||||
color: white; |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
height: 100px; |
||||
background-color: rgb(36, 30, 30); |
||||
border-bottom: 1px solid black; |
||||
} |
||||
|
||||
.menu a { |
||||
height: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
|
||||
.brand { |
||||
height: 80%; |
||||
margin-left: 30px; |
||||
} |
||||
|
||||
.menu-links { |
||||
display: flex; |
||||
width: fit-content; |
||||
margin-right: 30px; |
||||
} |
||||
|
||||
.menu-link { |
||||
list-style: none; |
||||
padding: 25px; |
||||
} |
||||
|
||||
.menu-link a { |
||||
font-size: 30px; |
||||
} |
||||
|
||||
.blogs-block { |
||||
width: 60%; |
||||
margin:auto; |
||||
padding: 20px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.blog-view { |
||||
display: grid; |
||||
grid-template-columns: 0.5fr 0.5fr 1fr; |
||||
align-items: center; |
||||
border: 2px solid black; |
||||
border-radius: 10px; |
||||
margin-top: 10px; |
||||
margin-bottom: 10px; |
||||
padding-left: 20px; |
||||
padding-bottom: 10px; |
||||
} |
||||
|
||||
.blog-title a { |
||||
padding-left: 10px; |
||||
} |
||||
|
||||
.blog-title a h1 { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
|
||||
.blog-stats { |
||||
padding-top: 15px; |
||||
width: 60%; |
||||
display: flex; |
||||
align-items:flex-start; |
||||
justify-content: space-around; |
||||
font-size: 15px; |
||||
} |
||||
|
||||
.blog-stats img { |
||||
height: 20px; |
||||
} |
||||
|
||||
.info-block { |
||||
width: 20% ; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-evenly; |
||||
} |
||||
|
||||
.md-content { |
||||
font-family: "Courier Prime"; |
||||
width: 60%; |
||||
} |
@ -1,79 +1,96 @@ |
||||
import './bootstrap'; |
||||
|
||||
function addEvent(btn, func) { |
||||
if(btn) func(btn); |
||||
} |
||||
|
||||
window.addEventListener("DOMContentLoaded", () => { |
||||
let modal = document.querySelector('#modal-update'); |
||||
let openModalBtn = document.querySelector("#open-modal"); |
||||
let closeModalBtn = document.querySelector(".close-modal"); |
||||
let deleteBlogBtn = document.querySelector(".btn-blog-delete"); |
||||
let updateBlogBtn = document.querySelector(".btn-blog-update"); |
||||
let likeBtn = document.querySelector(".btn-like"); |
||||
let followBtn = document.querySelector(".btn-follow"); |
||||
let closeModalBtn = document.querySelector("#close-modal"); |
||||
let deleteBlogBtn = document.querySelector("#btn-blog-delete"); |
||||
let updateBlogBtn = document.querySelector("#btn-blog-update"); |
||||
let likeBtn = document.querySelector("#btn-like"); |
||||
let followBtn = document.querySelector("#btn-follow"); |
||||
|
||||
followBtn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/follow/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
if (res.status === 400) alert("Couldn't follow this user"); |
||||
//else window.location.href = "/profile/" + id;
|
||||
addEvent(followBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/follow/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
if (res.status === 400) alert("Couldn't follow this user"); |
||||
//else window.location.href = "/profile/" + id;
|
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
likeBtn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/blog/like/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
if (res.status === 400) alert("Blog already liked"); |
||||
else window.location.href = "/blog/" + id; |
||||
addEvent(likeBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = document.querySelector(".btn-like").getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/blog/like/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
if (res.status === 400) alert(res.value); |
||||
else window.location.href = "/blog/" + id; |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
openModalBtn.addEventListener("click", (e) => { |
||||
modal.showModal(); |
||||
|
||||
addEvent(openModalBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
modal.showModal(); |
||||
}); |
||||
}); |
||||
|
||||
closeModalBtn.addEventListener("click", (e) => { |
||||
modal.close(); |
||||
addEvent(closeModalBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
modal.close(); |
||||
}); |
||||
}); |
||||
|
||||
updateBlogBtn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
let form = document.querySelector('.update-form'); |
||||
let formData = new FormData(form); |
||||
fetch(`/blog/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
}, |
||||
body: formData |
||||
}).then((res) => { |
||||
window.location.href = "/blog/" + id; |
||||
addEvent(updateBlogBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
let form = document.querySelector('.update-form'); |
||||
let formData = new FormData(form); |
||||
fetch(`/blog/${id}`, { |
||||
method: "POST", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
}, |
||||
body: formData |
||||
}).then((res) => { |
||||
window.location.href = "/blog/" + id; |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
deleteBlogBtn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/blog/${id}`, { |
||||
method: "DELETE", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
window.location.href = "/blogs" |
||||
|
||||
addEvent(deleteBlogBtn, (btn) => { |
||||
btn.addEventListener("click", (e) => { |
||||
e.preventDefault(); |
||||
let id = e.target.getAttribute("data-id"); |
||||
let token = document.querySelector('input[name=_token]').value; |
||||
fetch(`/blog/${id}`, { |
||||
method: "DELETE", |
||||
headers: { |
||||
"X-CSRF-Token": token |
||||
} |
||||
}).then((res) => { |
||||
window.location.href = "/blogs" |
||||
}); |
||||
}); |
||||
}); |
||||
}) |
@ -0,0 +1,3 @@ |
||||
@foreach($errors->all() as $key => $error) |
||||
<p>{{ $error }}</p> |
||||
@endforeach |
@ -0,0 +1,5 @@ |
||||
<li class="flex justify-center mb-5"> |
||||
<a href="{{ $link }}"> |
||||
<img class="size-12" src="/img/{{ $icon }}"> |
||||
</a> |
||||
</li> |
@ -0,0 +1,15 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en" class=""> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet"> |
||||
<title>BlogBuntu</title> |
||||
@vite('resources/css/app.css') |
||||
</head> |
||||
<body class="w-full flex p-0 m-0 bg-white dark:bg-black text-black dark:text-white"> |
||||
@include('base.menu') |
||||
@include('base.errors') |
||||
@yield("content") |
||||
</body> |
||||
</html> |
@ -0,0 +1,33 @@ |
||||
<nav class="flex flex-col justify-between w-fit h-screen bg-white border-black pb-5 px-3 |
||||
dark:bg-black border-r dark:border-white"> |
||||
<a href="/" class="w-full flex justify-center mb-12"> |
||||
<img class="size-[6rem] mx-auto" src="/img/blog_logo.webp"> |
||||
</a> |
||||
<ul class="flex flex-col w-full"> |
||||
@if(request()->user()) |
||||
@include('base.icon', [ |
||||
"icon" => "create_icon.svg", |
||||
"link" => "/blog/create" |
||||
]) |
||||
@endif |
||||
@if(request()->user()) |
||||
@include('base.icon', [ |
||||
"icon" => "profile_icon.svg", |
||||
"link" => "/myprofile" |
||||
]) |
||||
@include('base.icon', [ |
||||
"icon" => "signout_icon.svg", |
||||
"link" => "/logout" |
||||
]) |
||||
@else |
||||
@include('base.icon', [ |
||||
"icon" => "register_icon.svg", |
||||
"link" => "/register" |
||||
]) |
||||
@include('base.icon', [ |
||||
"icon" => "signin_icon.svg", |
||||
"link" => "/login" |
||||
]) |
||||
@endif |
||||
</ul> |
||||
</nav> |
@ -1,13 +1,23 @@ |
||||
@extends('layout') |
||||
@extends('base.layout') |
||||
|
||||
@section('body') |
||||
<h1>Create a blog</h1> |
||||
<form action="/blog/" method="post"> |
||||
@csrf |
||||
<p>Title</p><input name="title" type="text" value="{{ old('title') }}"> |
||||
<p>Epilog</p><textarea name="epilog" type="text">{{ old('epilog') }}</textarea> |
||||
<p>Content</p><textarea name="containt" type="text">{{ old('containt') }}</textarea> |
||||
<br> |
||||
<input type="submit"> |
||||
</form> |
||||
@section('content') |
||||
<div class="w-full flex justify-center items-center"> |
||||
<div class="w-2/3 p-10 border border-black dark:border-white rounded-lg"> |
||||
<h1 class="text-6xl font-bold pb-3 mb-5 border-b border-black dark:border-white">Create a blog</h1> |
||||
<form action="/blog/" method="post" class="flex flex-col items-center"> |
||||
<div class="grid grid-cols-4 w-full"> |
||||
<p class="mr-">Title :</p><input class="border border-gray-300 rounded-lg col-span-3 mb-5 p-2" |
||||
name="title" type="text" value="{{ old('title') }}"> |
||||
<p>Image (Optional):</p><input class="border border-gray-300 rounded-lg col-span-3 mb-5 p-2" |
||||
name="image" type="file" value="{{ old('image') }}"> |
||||
<p>Epilog (Optional):</p><textarea class="border border-gray-300 rounded-lg col-span-3 mb-5 p-2" |
||||
name="epilog" type="text">{{ old('epilog') }}</textarea> |
||||
<p>Content (Optional):</p><textarea class="border border-gray-300 rounded-lg col-span-3 mb-5 p-2" |
||||
name="containt" type="text">{{ old('containt') }}</textarea> |
||||
</div> |
||||
<input type="submit" class="rounded-lg bg-blue-500 text-white p-2 w-fit"> |
||||
@csrf |
||||
</form> |
||||
</div> |
||||
</div> |
||||
@endsection |
@ -1,28 +1,47 @@ |
||||
@extends('layout') |
||||
@extends('base.layout') |
||||
|
||||
@section('body') |
||||
@section('content') |
||||
@vite('resources/js/blog.js') |
||||
@if(request()->user() && $blog->user->id == request()->user()->id) |
||||
<button id="open-modal">Update</button> |
||||
<form class="delete-form"> |
||||
@csrf |
||||
<button class="btn btn-blog-delete" data-id="{{$blog->id}}">Delete</button> |
||||
</form> |
||||
@include('blog.modal_update') |
||||
@else |
||||
@endif |
||||
@csrf |
||||
<button class="btn-like" data-id="{{$blog->id}}">Like</button> |
||||
<button class="btn-follow" data-id="{{$blog->user->id}}">Follow</button> |
||||
|
||||
<h1>{{ $blog->title }}</h1> |
||||
<a href="/profile/{{ $blog->user->id }}"><h3>by {{ $blog->user->username }}</h3></a> |
||||
<p>{{ $blog->epilog }}</p> |
||||
<p>Views : {{ $blog->views }}</p> |
||||
<p>Likes : {{ $blog->likes()->count() }}</p> |
||||
@if($blog->containt) |
||||
<div class="md-content"> |
||||
{!! html_entity_decode(app(Spatie\LaravelMarkdown\MarkdownRenderer::class)->toHtml($blog->containt)) !!} |
||||
<div class="w-full h-screen overflow-y-auto"> |
||||
<div class="w-full flex flex-col pt-10 items-center px-[230px]"> |
||||
<div class="w-full flex justify-between"> |
||||
@csrf |
||||
<div> |
||||
@if(request()->user() && $blog->user->id == request()->user()->id) |
||||
<button id="open-modal">Update</button> |
||||
<button id="btn-blog-delete" data-id="{{$blog->id}}">Delete</button> |
||||
@include('blog.modal_update') |
||||
@else |
||||
<button id="btn-follow" data-id="{{$blog->user->id}}">Follow</button> |
||||
@endif |
||||
</div> |
||||
<div class="flex"> |
||||
<div class="flex justify-around items-center mr-5"> |
||||
<p class="text-lg">{{ $blog->views }} views</p> |
||||
</div> |
||||
<div class="flex justify-around items-center bg-gray-200 dark:bg-gray-800 px-3 py-1 rounded-lg"> |
||||
<p class="text-lg mr-2">{{ $blog->likes()->count() }}</p> |
||||
<button id="btn-like" data-id="{{$blog->id}}"><img class="w-[30px]" src="/img/like_icon.svg"></button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="w-full flex flex-col items-center"> |
||||
<div class="w-full flex items-end justify-center border-b border-black pb-5"> |
||||
<p class="text-8xl">{{ $blog->title }}</p> |
||||
<p class="pl-10 text-3xl">by</p> |
||||
<a class="pl-3 text-3xl" href="/profile/{{ $blog->user->id }}">{{ $blog->user->username }}</a> |
||||
</div> |
||||
@if($blog->image) |
||||
<img class="h-[250px] w-min w-max-[445px] mx-auto my-5" |
||||
src="{{ asset('storage/images/blog/' . $blog->image) }}" alt="{{ $blog->image }}"> |
||||
@endif |
||||
<p class="w-full px-[80px] py-10 italic">{{ $blog->epilog }}</p> |
||||
</div> |
||||
@if($blog->containt) |
||||
<div class="md-content"> |
||||
{!! html_entity_decode(app(Spatie\LaravelMarkdown\MarkdownRenderer::class)->toHtml($blog->containt)) !!} |
||||
</div> |
||||
@endif |
||||
</div> |
||||
@endif |
||||
</div> |
||||
@endsection |
@ -1,15 +1,22 @@ |
||||
<div class="blog-view"> |
||||
<div class="blog-title"> |
||||
<a href="/blog/{{ $blog->id }}"><h1>{{ $blog->title }}</h1></a> |
||||
<a href="/profile/{{ $blog->user->id }}">by {{ $blog->user->username }}</a> |
||||
<div class="grid grid-cols-3 w-full bg-white dark:bg-black hover:bg-gray-300 dark:hover:bg-gray-900 h-fit rounded-xl p-2 mt-5"> |
||||
<a class="row-span-2 m-auto h-[150px] w-[266px] w-max-[266px] bg-black dark:bg-white rounded-xl" href="/blog/{{ $blog->id }}"> |
||||
@if($blog->image) |
||||
<img class="h-[150px] w-min w-max-[266px] m-auto" |
||||
src="{{ asset('storage/images/blog/' . $blog->image) }}" alt="{{ $blog->image }}"> |
||||
@endif |
||||
</a> |
||||
<div class="container h-full flex items-center"> |
||||
<a href="/blog/{{ $blog->id }}" class="text-2xl mr-3">{{ $blog->title }}</a> |
||||
<a href="/profile/{{ $blog->user->id }}" class="text-lg">by {{ $blog->user->username }}</a> |
||||
</div> |
||||
<div class="blog-stats"> |
||||
<div class="info-block"> |
||||
<img src="/img/view_icon.png"><p>{{ $blog->views }}</p> |
||||
<div class="flex justify-around items-center"> |
||||
<div class="flex justify-around items-center"> |
||||
<p class="text-lg">{{ $blog->views }} views</p> |
||||
</div> |
||||
<div class="info-block"> |
||||
<img src="/img/like_icon.png"><p>{{ $blog->likes()->count() }}</p> |
||||
<div class="flex justify-around items-center bg-gray-200 dark:bg-gray-800 px-3 py-1 rounded-lg"> |
||||
<p class="text-lg mr-2">{{ $blog->likes()->count() }}</p> |
||||
<img class="w-[30px]" src="/img/like_icon.svg"> |
||||
</div> |
||||
</div> |
||||
<p>{{ $blog->epilog }}</p> |
||||
<a class="w-full col-span-2" href="/blog/{{ $blog->id }}">{{ $blog->epilog }}</a> |
||||
</div> |
@ -1,34 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet"> |
||||
<title>Document</title> |
||||
@vite('resources/css/app.css') |
||||
</head> |
||||
<body> |
||||
<nav class="menu"> |
||||
<a href="/"><img class="brand" src="/img/test_logo.webp"></a> |
||||
<ul class="menu-links"> |
||||
@if(request()->user()) |
||||
<li class="menu-link"><a href="/blog/create">Create a blog</a></li> |
||||
@endif |
||||
<li class="menu-link"><a href="/blogs">Blogs</a></li> |
||||
@if(request()->user()) |
||||
<li class="menu-link"><a href="/myprofile">Profile</a></li> |
||||
<li class="menu-link"><a href="/logout">Logout</a></li> |
||||
@else |
||||
<li class="menu-link"><a href="/register">Register</a></li> |
||||
<li class="menu-link"><a href="/login">Login</a></li> |
||||
@endif |
||||
</ul> |
||||
</nav> |
||||
@foreach($errors->all() as $key => $error) |
||||
<p>{{ $error }}</p> |
||||
@endforeach |
||||
<main> |
||||
@yield("body") |
||||
</main> |
||||
</body> |
||||
</html> |
@ -0,0 +1,24 @@ |
||||
/** @type {import('tailwindcss').Config} */ |
||||
export default { |
||||
darkMode: 'selector', |
||||
content: [ |
||||
"./resources/**/*.blade.php", |
||||
"./resources/**/*.js", |
||||
"./resources/**/*.vue", |
||||
], |
||||
theme: { |
||||
screens: { |
||||
'tablet': '640px', |
||||
// => @media (min-width: 640px) { ... }
|
||||
|
||||
'laptop': '1024px', |
||||
// => @media (min-width: 1024px) { ... }
|
||||
|
||||
'desktop': '1280px', |
||||
// => @media (min-width: 1280px) { ... }
|
||||
}, |
||||
extend: {}, |
||||
}, |
||||
plugins: [], |
||||
} |
||||
|