first commit
This commit is contained in:
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
75
README.md
Normal file
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
1143
Temp/blog-details.html
Normal file
1143
Temp/blog-details.html
Normal file
File diff suppressed because it is too large
Load Diff
1245
Temp/blog-sidebar-right.html
Normal file
1245
Temp/blog-sidebar-right.html
Normal file
File diff suppressed because it is too large
Load Diff
8
app/app.vue
Normal file
8
app/app.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
121
app/components/FooterArea.vue
Normal file
121
app/components/FooterArea.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="footer-area padding-top font-f-2">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-sm-6">
|
||||
<div class="single-footer mr50 hadding2">
|
||||
<div class="site-logo home1-site-logo">
|
||||
<a href="#"
|
||||
><img src="/assets/img/logo/header-logo1.svg" alt="" />
|
||||
</a>
|
||||
<span class="font-f-2">We’re hiring</span>
|
||||
</div>
|
||||
<div class="space30"></div>
|
||||
<p class="font-f-2 font-16 line-height-26">
|
||||
As a graphic designer, add motion to your skillset. Animate
|
||||
whatever you create and tell your story in a magical way with
|
||||
Artboard Studio.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg col-sm-6 hadding2">
|
||||
<div class="single-footer">
|
||||
<h3 class="font-f-1 font-20 weight-700 line-height-20">
|
||||
Discover
|
||||
</h3>
|
||||
<div>
|
||||
<ul class="font-f-2 font-16 line-height-26 pera-c-1">
|
||||
<li><a href="#">Learn</a></li>
|
||||
<li><a href="blog.html">Blog</a></li>
|
||||
<li><a href="#">Pricing</a></li>
|
||||
<li><a href="#">Template Maker</a></li>
|
||||
<li><a href="#">Mockup Generator</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg col-sm-6 hadding2">
|
||||
<div class="single-footer">
|
||||
<h3 class="font-f-2 font-20 weight-700 line-height-20">
|
||||
Company
|
||||
</h3>
|
||||
<div>
|
||||
<ul class="font-f-2 font-16 line-height-26 pera-c-1">
|
||||
<li><a href="about.html">About us</a></li>
|
||||
<li><a href="#">Licensing</a></li>
|
||||
<li><a href="#">privacy Policy</a></li>
|
||||
<li><a href="#">Terms of Use</a></li>
|
||||
<li><a href="#">Refund Policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 hadding2">
|
||||
<div class="single-footer-contact">
|
||||
<h3 class="font-f-2 font-20 weight-700 line-height-20">
|
||||
Get in touch
|
||||
</h3>
|
||||
|
||||
<div class="foonter-contact-1">
|
||||
<div class="foonter-contact-icon-1">
|
||||
<div class="">
|
||||
<img src="/assets/img/icons/footer-icon-1.svg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="foonter-contact-p">
|
||||
<a href="tel:+910225850556">USA: +91 02 2585 0556</a>
|
||||
<a href="tel:+610225850556">UK: +61 02 2585 0556</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foonter-contact-1">
|
||||
<div class="foonter-contact-icon-1">
|
||||
<div class="">
|
||||
<img src="/assets/img/icons/footer-icon-2.svg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="foonter-contact-p">
|
||||
<a href="mailto:Contacthelp@Demoui.co"
|
||||
>Contacthelp@Demoui.co</a
|
||||
>
|
||||
<a href="mailto:Info@Demoui.co">Info@Demoui.co</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center copyright2">
|
||||
<div class="col-lg-6">
|
||||
<p class="font-16 weight-400 font-f-2 line-height-16 pera-c-1">
|
||||
© 2023 Avigo by fleexstudio. All Rights Reserved.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 text-right">
|
||||
<div class="social social1 comon-footer-icons">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#"><i class="fa-brands fa-twitter"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"><i class="fa-brands fa-facebook-f"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"><i class="fa-brands fa-instagram"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"><i class="fa-brands fa-github"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
113
app/components/HeaderSection.vue
Normal file
113
app/components/HeaderSection.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<div class="header-area d-none d-lg-block" id="header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="header-elements">
|
||||
<div class="site-logo home1-site-logo">
|
||||
<a href="#"
|
||||
><img src="/assets/img/logo/header-logo1.svg" alt=""/>
|
||||
</a>
|
||||
<span>We’re hiring</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="main-menu-ex main-menu-ex1">
|
||||
<ul>
|
||||
<li class="has-dropdown"><a href="#">Home <i class="fa-solid fa-angle-down"></i></a>
|
||||
<ul class="sub-menu">
|
||||
<li class="has-dropdown has-dropdown1"><a href="index4.html">Multipage<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="index.html">Real Estate</a></li>
|
||||
<li><a href="index2.html">Management</a></li>
|
||||
<li><a href="index3.html">App landing</a></li>
|
||||
<li><a href="index4.html">Web Hosting </a></li>
|
||||
<li><a href="index5.html">Consulting </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="has-dropdown has-dropdown1"><a href="index4.html">Landing Page<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="single-index1.html">Real Estate</a></li>
|
||||
<li><a href="single-index2.html">Management</a></li>
|
||||
<li><a href="single-index3.html">App landing</a></li>
|
||||
<li><a href="single-index4.html">Web Hosting </a></li>
|
||||
<li><a href="single-index5.html">Consulting </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="about.html">About Us</a>
|
||||
</li>
|
||||
<li class="has-dropdown"><a href="#">Service <i class="fa-solid fa-angle-down"></i></a>
|
||||
<ul class="sub-menu">
|
||||
|
||||
<li class="has-dropdown has-dropdown1"><a href="index4.html">Our Service<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="service.html">Our Service 1</a></li>
|
||||
<li><a href="service2.html">Our Service 2</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="service-details.html">Service Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown-menu-parrent"><a href="#">Pages <i class="fa-solid fa-angle-down"></i></a>
|
||||
<ul>
|
||||
<li><a href="property.html">Property</a></li>
|
||||
<li><a href="property-details.html">Property Details</a></li>
|
||||
<li><a href="pricing-plan.html">Pricing Plan</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="team.html">Our Team</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="has-dropdown"><a href="#">Blog <i class="fa-solid fa-angle-down"></i></a>
|
||||
<ul class="sub-menu">
|
||||
<li class="has-dropdown has-dropdown1"><a href="blog.html">Blog<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="blog.html">Our Blog</a></li>
|
||||
<li><a href="blog-details.html">Blog Formets</a></li>
|
||||
<li><a href="blog-sidebar-left.html">Blog Sidebar Left</a></li>
|
||||
<li><a href="blog-sidebar-right.html">Blog Sidebar Right</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="blog-details.html">Single Blog</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="contact.html">Contact Us</a></li>
|
||||
|
||||
<li class="d-lg-none"><a href="#">Sign In / Sign up</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="header-site-btn">
|
||||
<a href="#" class="home2-site-btn-1 font-f-2 weight-400 font-16 line-height-16">Sign In / Sign Up</a>
|
||||
<a class="cta-btn font-f-2 weight-700" href="property.html">List Your Property</a>
|
||||
</div>
|
||||
<div class="mobile-menu-bar d-lg-none">
|
||||
<i class="fas fa-bars"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
74
app/components/MobileHeader.vue
Normal file
74
app/components/MobileHeader.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mobile-header mobile-header-4 d-block d-lg-none ">
|
||||
<div class="container-fluid">
|
||||
<div class="col-12">
|
||||
<div class="mobile-header-elements">
|
||||
<div class="mobile-logo">
|
||||
<a href="index.html"><img src="/assets/img/logo/header-logo1.svg" alt=""></a>
|
||||
</div>
|
||||
<div class="mobile-nav-icon">
|
||||
<i class="fa-solid fa-bars"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mobile-sidebar d-block d-lg-none">
|
||||
<div class="menu-close">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</div>
|
||||
<div class="mobile-nav">
|
||||
|
||||
<ul class="mobile-nav-list">
|
||||
<li><a href="#">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="single-index1.html">Real Estate</a></li>
|
||||
<li><a href="single-index2.html">Project Management</a></li>
|
||||
<li><a href="single-index3.html">Appland</a></li>
|
||||
<li><a href="single-index4.html">Hostika </a></li>
|
||||
<li><a href="single-index5.html">Insurance </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="about.html">About Us</a></li>
|
||||
|
||||
<li><a href="#">Service</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="service.html">Service</a></li>
|
||||
<li><a href="service2.html">Service</a></li>
|
||||
<li><a href="service-details.html">Service Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#">Blog</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="blog.html">Blog</a></li>
|
||||
<li><a href="blog-left-bar.html">Blog Left</a></li>
|
||||
<li><a href="blog-right-bar.html">Blog Right</a></li>
|
||||
<li><a href="blog-details.html">Blog Details</a></li>
|
||||
<li><a href="blog-single.html">Single Blog</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a href="#">Pages</a>
|
||||
<ul class="sub-menu">
|
||||
<li><a href="property.html">Property</a></li>
|
||||
<li><a href="property-details.html">Property Details</a></li>
|
||||
<li><a href="pricing-plan.html">Pricing Plan</a></li>
|
||||
<li><a href="team.html">Our Team</a></li>
|
||||
<li><a href="faq.html">Our Faq</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="contact.html">Contact Us</a></li>
|
||||
<li><a href="#">Sign In / Sign up </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
19
app/components/PaginaContainer.vue
Normal file
19
app/components/PaginaContainer.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="paginacontainer">
|
||||
|
||||
<div class="progress-wrap">
|
||||
<svg class="progress-circle svg-content" width="100%" height="100%" viewBox="-1 -1 102 102">
|
||||
<path d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
24
app/components/Paginate.vue
Normal file
24
app/components/Paginate.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row text-center">
|
||||
<div class="col-12 m-auto text-center">
|
||||
<div class="theme-pagination text-center">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-solid fa-angle-left"></i></a></li>
|
||||
<li><a class="active" href="#">01</a></li>
|
||||
<li><a href="#">02</a></li>
|
||||
<li>...</li>
|
||||
<li><a href="#">12</a></li>
|
||||
<li><a href="#"><i class="fa-solid fa-angle-right"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
40
app/components/SubsribeStart.vue
Normal file
40
app/components/SubsribeStart.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="subsribe-all sp2">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-7">
|
||||
<div class="all-subsribe-hadding">
|
||||
<h1
|
||||
class="font-f-2 weight-700 font-30 font-lg-45 line-height-30 line-height-lg-45 font-w"
|
||||
>
|
||||
Get the properties you're interested in delivered straight to
|
||||
your inbox.
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="comon-subsribe-all-input">
|
||||
<input type="email" placeholder="Enter your email here" />
|
||||
<div class="subsribe-btn">
|
||||
<div class="home2-btn">
|
||||
<button type="submit"
|
||||
class="font-18 line-height-30 weight-700 font-f-2 font-w"
|
||||
>
|
||||
Get Notified
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
23
app/components/TagsClouds.vue
Normal file
23
app/components/TagsClouds.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="single-widget widget_tag_cloud">
|
||||
<h3 class="font-f-2">Tags</h3>
|
||||
<div class="space10"></div>
|
||||
<div class="tagcloud">
|
||||
<a href="#" class="font-f-2">Healthcare</a>
|
||||
<a href="#" class="font-f-2">Consult</a>
|
||||
<a href="#" class="font-f-2">Cahless</a>
|
||||
<a href="#" class="font-f-2">Cyberattacks</a>
|
||||
<a href="#" class="font-f-2">Meeting</a>
|
||||
<a href="#" class="font-f-2">Leadership</a>
|
||||
<a href="#" class="font-f-2">Health Insurace</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
74
app/components/home/BlogPage.vue
Normal file
74
app/components/home/BlogPage.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Paginate from "~/components/Paginate.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="col-lg-8">
|
||||
<div class="blogs padding-right">
|
||||
<article class="post-blog post-format-image">
|
||||
<div class="single-blog">
|
||||
<div class="execution-images">
|
||||
<div class="execution-img1">
|
||||
<img src="/assets/img/shapes/service-details-shaop-bg.svg" alt="">
|
||||
</div>
|
||||
<div class="execution-img2">
|
||||
<img src="/assets/img/image/service-details-img.png" alt="">
|
||||
</div>
|
||||
<div class="execution-img3">
|
||||
<img src="/assets/img/shapes/service-details-shape.svg" alt="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="author-bio mt-4 mb-3">
|
||||
<div class="author-name">
|
||||
<a href="#" class="font-f-2"><i class="fa-solid fa-user"></i> Miro koyetin</a>
|
||||
</div>
|
||||
<div class="blog-category">
|
||||
<a href="#" class="font-f-2"><i class="fa-solid fa-tag"></i>Lifestyle</a>
|
||||
</div>
|
||||
<div class="blog-date">
|
||||
<a href="#" class="font-f-2"><i class="fa-solid fa-calendar-days"></i>18 March 2023</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hadding2">
|
||||
<h4 class="font-f-2 font-24 line-height-28 weight-500"><a href="blog-single.html">We leverage
|
||||
technology to solve challenges for your business.</a></h4>
|
||||
|
||||
<div class="space32"></div>
|
||||
|
||||
<p class="details-p-hadding font-18 line-height-18 weight-500 font-f-2">Client completes business
|
||||
questionnaire</p>
|
||||
<div class="space16"></div>
|
||||
<p class="font-f-2 weight-400 line-height-28 font-16">After an initial complimentary phone call
|
||||
consultation, for new and potential clients we then conduct an initial assessment, which reviews
|
||||
and covers the current or potential business opportunities to made marketing strategies,
|
||||
marketplace competitive analysis, social media presence and other specific an assessments as
|
||||
needed to determine the best recommendations to improve client productivity, ensure efficiency,
|
||||
and generate revenue immediately. This aids in the discovery process for both client and
|
||||
consultant hen have a two hour meeting to discuss your business goals and provide.</p>
|
||||
|
||||
<div class="space40"></div>
|
||||
<p class="details-p-hadding font-18 line-height-18 weight-500 font-f-2">Client completes business
|
||||
questionnaire</p>
|
||||
<div class="space24"></div>
|
||||
<p class="font-f-2 weight-400 line-height-28 font-16">After an initial complimentary phone call
|
||||
consultation, for new and potential clients we then conduct an initial assessment, which reviews
|
||||
and covers the current or potential business opportunities to made marketing strategies,
|
||||
marketplace competitive analysis, social media presence and other specific an assessments as
|
||||
needed to determine the best recommendations to improve client productivity, ensure efficiency,
|
||||
and generate revenue immediately. This aids in the discovery process for both client and
|
||||
consultant hen have a two hour meeting to discuss your business goals and provide.</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="space60"></div>
|
||||
<Paginate/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
27
app/components/home/PagesHeroHeader.vue
Normal file
27
app/components/home/PagesHeroHeader.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pages-hero">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="page-hadding hadding2">
|
||||
<h1
|
||||
class="font-f-2 weight-700 font-40 font-lg-60 line-height-48 line-height-lg-65">
|
||||
Blog <span class="after">sidebar right</span>
|
||||
</h1>
|
||||
<p class="font-f-2 font-16 weight-500 line-height-16"><a href="index.html">Home</a> <span><i
|
||||
class="fa-solid fa-angle-right"></i></span> Blog <span><i class="fa-solid fa-angle-right"></i></span>
|
||||
Blog Details </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
14
app/components/home/Preloader.vue
Normal file
14
app/components/home/Preloader.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="preloader">
|
||||
<div id="loader"></div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
32
app/components/home/WidgetCategories.vue
Normal file
32
app/components/home/WidgetCategories.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="single-widget widget_categories">
|
||||
<h3 class="font-f-2">Blog Category</h3>
|
||||
<div class="space10"></div>
|
||||
<div class="blog-category-list">
|
||||
<ul>
|
||||
<li><a class="active font-f-2" href="#">Excutive consultant (10) <span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a></li>
|
||||
<li><a href="#" class="font-f-2">Marketing & advertising (12) <span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a></li>
|
||||
<li><a href="#" class="font-f-2">Accounbility & execution (08)<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a></li>
|
||||
<li><a href="#" class="font-f-2">Business planning (21)<span><i class="fa-solid fa-angle-right"></i></span></a>
|
||||
</li>
|
||||
<li><a href="#" class="font-f-2">Privet planning (13)<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a></li>
|
||||
<li><a href="#" class="font-f-2">Mutual invest planning (06)<span><i
|
||||
class="fa-solid fa-angle-right"></i></span></a></li>
|
||||
<li><a href="#" class="font-f-2">Project managment (1)<span><i class="fa-solid fa-angle-right"></i></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
71
app/components/home/WidgetRecentPost.vue
Normal file
71
app/components/home/WidgetRecentPost.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="single-widget single-widget-post-sidebar">
|
||||
<h3 class="font-f-2">Search</h3>
|
||||
|
||||
<div class="recent-post">
|
||||
<div class="">
|
||||
<div class="recent-img">
|
||||
<img src="/assets/img/image/blog-details-side1.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-post-content">
|
||||
<div class="blog-date-time">
|
||||
<ul class="blog-date">
|
||||
<li><img src="/assets/img/icons/date.svg" alt=""> 11/02/2022</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h6><a href="blog-details.html" class="font-f-2">Leadership Burnout: What causes it and how avoid
|
||||
it.</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="recent-post">
|
||||
<div class="">
|
||||
<div class="recent-img">
|
||||
<img src="/assets/img/image/blog-details-side2.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-post-content">
|
||||
<div class="blog-date-time">
|
||||
<ul class="blog-date">
|
||||
<li><img src="/assets/img/icons/date.svg" alt=""> 11/02/2022</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h6><a href="blog-details.html" class="font-f-2">New Consulting For All Kind Offer Finance...</a>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="recent-post">
|
||||
<div class="">
|
||||
<div class="recent-img">
|
||||
<img src="/assets/img/image/blog-details-side3.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="recent-post-content">
|
||||
<div class="blog-date-time">
|
||||
<ul class="blog-date">
|
||||
<li><img src="/assets/img/icons/date.svg" alt=""> 11/02/2022</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h6><a href="blog-details.html" class="font-f-2">What we are capable to usually discovered...</a>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
19
app/components/home/WidgetSearch.vue
Normal file
19
app/components/home/WidgetSearch.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="single-widget widget_search">
|
||||
<h3 class="font-f-2">Search</h3>
|
||||
<div class="search-form-widget">
|
||||
<form action="#">
|
||||
<input type="search" placeholder="Type keyword here">
|
||||
<button type="submit" class="search-icon"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
31
app/components/home/WidgetSidebarImgBox.vue
Normal file
31
app/components/home/WidgetSidebarImgBox.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="sidebar-img-box-all text-center">
|
||||
<div class="sidebar-img">
|
||||
<img src="/assets/img/image/sidebar-box-img.png" alt="">
|
||||
</div>
|
||||
<div class="sidebar-box-hadding">
|
||||
<div class="space16"></div>
|
||||
<h4><a href="#" class="font-f-2 font-20 line-height-20 weight-500 font-w">Alex Blake</a></h4>
|
||||
<div class="space24"></div>
|
||||
<p class="font-f-2 font-16 line-height-26 weight-400 font-w">When it comes to business, listen to
|
||||
Henry David Thoreau: things usually don’t happen overnight – instead, to find success takes a lot of
|
||||
time, effort, and courage. Opus includes everything you need to build a beautiful website.</p>
|
||||
</div>
|
||||
<div class="details-side-box-icon">
|
||||
<div class="space24"></div>
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
23
app/components/home/WidgetTagCloud.vue
Normal file
23
app/components/home/WidgetTagCloud.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="single-widget widget_tag_cloud">
|
||||
<h3 class="font-f-2">Tags</h3>
|
||||
<div class="space10"></div>
|
||||
<div class="tagcloud">
|
||||
<a href="#" class="font-f-2">Healthcare</a>
|
||||
<a href="#" class="font-f-2">Consult</a>
|
||||
<a href="#" class="font-f-2">Cahless</a>
|
||||
<a href="#" class="font-f-2">Cyberattacks</a>
|
||||
<a href="#" class="font-f-2">Meeting</a>
|
||||
<a href="#" class="font-f-2">Leadership</a>
|
||||
<a href="#" class="font-f-2">Health Insurace</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
88
app/layouts/admin.vue
Normal file
88
app/layouts/admin.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="d-flex" id="wrapper">
|
||||
<!-- Sidebar -->
|
||||
<div class="bg-dark text-white p-3" id="sidebar-wrapper" style="min-width: 250px; min-height: 100vh;">
|
||||
<div class="sidebar-heading text-center py-4 fs-4 fw-bold border-bottom">Admin Panel</div>
|
||||
<div class="list-group list-group-flush my-3">
|
||||
<NuxtLink to="/admin" class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-tachometer-alt me-2"></i> Dashboard
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/admin/settings"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-cogs me-2"></i> Settings
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/admin/security"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-shield-alt me-2"></i> Güvenlik & Ağ
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/admin/users"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-users me-2"></i> Kullanıcılar
|
||||
</NuxtLink>
|
||||
|
||||
<div class="sidebar-heading text-white-50 mt-3 mb-1 small text-uppercase">Blog</div>
|
||||
<NuxtLink to="/admin/blog/categories"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-tags me-2"></i> Kategoriler
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/admin/blog/tags"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-hashtag me-2"></i> Etiketler
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/admin/blog/posts"
|
||||
class="list-group-item list-group-item-action bg-transparent text-white border-0">
|
||||
<i class="fas fa-newspaper me-2"></i> Postlar
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/" class="list-group-item list-group-item-action bg-transparent text-white border-0 mt-5">
|
||||
<i class="fas fa-home me-2"></i> Siteye Dön
|
||||
</NuxtLink>
|
||||
<button @click="handleLogout"
|
||||
class="list-group-item list-group-item-action bg-transparent text-danger border-0">
|
||||
<i class="fas fa-sign-out-alt me-2"></i> Çıkış
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div id="page-content-wrapper" class="w-100">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom px-4">
|
||||
<button class="btn btn-primary" id="menu-toggle">Toggle Menu</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ms-auto mt-2 mt-lg-0">
|
||||
<li class="nav-item active">
|
||||
<span class="nav-link">Hoşgeldin, Admin</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4 py-4">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { signOut } = useAuth();
|
||||
|
||||
const handleLogout = async () => {
|
||||
await signOut({ callbackUrl: '/auth/login' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#sidebar-wrapper {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.list-group-item-action:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.router-link-active {
|
||||
background-color: rgba(255, 255, 255, 0.2) !important;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
72
app/layouts/default.vue
Normal file
72
app/layouts/default.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot />
|
||||
<div class="progress-wrap">
|
||||
<svg class="progress-circle svg-content" width="100%" height="100%" viewBox="-1 -1 102 102">
|
||||
<path d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { useHeroStore } from '@/stores/hero';
|
||||
import { useSettingStore } from '@/stores/setting';
|
||||
|
||||
const heroStore = useHeroStore();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
useHead(computed(() => {
|
||||
const title = settingStore.settings?.title ?? heroStore.hero?.title ?? 'Blog details Sidebar Right || Avigo Multipurpose Theme';
|
||||
const meta: Array<Record<string, string>> = [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
|
||||
];
|
||||
if (settingStore.settings?.meta_description) {
|
||||
meta.push({ name: 'description', content: settingStore.settings.meta_description });
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
meta
|
||||
}
|
||||
}));
|
||||
|
||||
onMounted(() => {
|
||||
// page-progress
|
||||
const progressPath = document.querySelector(".progress-wrap path") as SVGPathElement | null;
|
||||
if (progressPath) {
|
||||
const pathLength = progressPath.getTotalLength();
|
||||
// use webkitTransition (lowercase) to satisfy TypeScript and cast style where needed
|
||||
progressPath.style.transition = (progressPath.style as any).webkitTransition = "none";
|
||||
progressPath.style.strokeDasharray = pathLength + " " + pathLength;
|
||||
progressPath.style.strokeDashoffset = String(pathLength);
|
||||
progressPath.getBoundingClientRect();
|
||||
progressPath.style.transition = (progressPath.style as any).webkitTransition = "stroke-dashoffset 10ms linear";
|
||||
const updateProgress = () => {
|
||||
const scroll = $(window).scrollTop();
|
||||
const height = $(document).height() - $(window).height();
|
||||
const prog = pathLength - (scroll * pathLength) / height;
|
||||
progressPath!.style.strokeDashoffset = String(prog);
|
||||
};
|
||||
updateProgress();
|
||||
$(window).scroll(updateProgress);
|
||||
const offset = 50;
|
||||
const duration = 550;
|
||||
jQuery(window).on("scroll", () => {
|
||||
if (jQuery(window).scrollTop() > offset) {
|
||||
jQuery(".progress-wrap").addClass("active-progress");
|
||||
} else {
|
||||
jQuery(".progress-wrap").removeClass("active-progress");
|
||||
}
|
||||
});
|
||||
jQuery(".progress-wrap").on("click", (event: any) => {
|
||||
event.preventDefault();
|
||||
jQuery("html, body").animate({ scrollTop: 0 }, duration);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
11
app/middleware/admin.ts
Normal file
11
app/middleware/admin.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default defineNuxtRouteMiddleware((to, from) => {
|
||||
const { status, data } = useAuth();
|
||||
|
||||
if (status.value !== 'authenticated') {
|
||||
return navigateTo('/auth/login?callbackUrl=' + to.fullPath);
|
||||
}
|
||||
|
||||
if (!data.value?.user?.is_admin) {
|
||||
return navigateTo('/');
|
||||
}
|
||||
});
|
||||
8
app/middleware/guest-only.ts
Normal file
8
app/middleware/guest-only.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// Middleware to redirect authenticated users away from guest-only pages
|
||||
export default defineNuxtRouteMiddleware((to, from) => {
|
||||
const { status } = useAuth();
|
||||
|
||||
if (status.value === 'authenticated') {
|
||||
return navigateTo('/');
|
||||
}
|
||||
});
|
||||
350
app/pages/admin/blog/categories/index.vue
Normal file
350
app/pages/admin/blog/categories/index.vue
Normal file
@@ -0,0 +1,350 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Kategori Yönetimi</h2>
|
||||
</div>
|
||||
|
||||
<!-- Filter / Search -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<select v-model="filterStatus" class="form-select" @change="fetchCategories(1)">
|
||||
<option value="">Aktif Kategoriler</option>
|
||||
<option value="only">Silinenler (Çöp Kutusu)</option>
|
||||
<option value="with">Tümü (Silinenler Dahil)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Categories List Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Kategoriler</h5>
|
||||
<button class="btn btn-success btn-sm" @click="openModal(null)">
|
||||
<i class="fas fa-plus me-2"></i> Yeni Kategori
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div v-if="loading" class="text-center py-5">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="categories.length === 0" class="text-center py-5 text-muted">
|
||||
Kayıt bulunamadı.
|
||||
</div>
|
||||
|
||||
<div v-else class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Başlık</th>
|
||||
<th>Slug</th>
|
||||
<th>Açıklama</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="category in categories" :key="category.ID">
|
||||
<td>{{ category.ID }}</td>
|
||||
<td>
|
||||
<!-- Indentation for hierarchy if available, otherwise flat -->
|
||||
<div :style="{ paddingLeft: (category.parent_id ? 20 : 0) + 'px' }">
|
||||
<span v-if="category.parent_id" class="text-muted me-1">↳</span>
|
||||
{{ category.title }}
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="badge bg-light text-dark">{{ category.slug }}</span></td>
|
||||
<td>{{ category.description }}</td>
|
||||
<td>
|
||||
<span v-if="category.DeletedAt" class="badge bg-danger">Silindi</span>
|
||||
<span v-else class="badge bg-success">Aktif</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div v-if="!category.DeletedAt">
|
||||
<button class="btn btn-sm btn-outline-primary me-2" @click="openModal(category)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" @click="deleteCategory(category.ID)">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<button class="btn btn-sm btn-outline-success me-2" @click="restoreCategory(category.ID)">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" @click="hardDeleteCategory(category.ID)">
|
||||
<i class="fas fa-times-circle"></i> Kalıcı Sil
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav v-if="pagination.total > pagination.per_page" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item" :class="{ disabled: pagination.page === 1 }">
|
||||
<button class="page-link" @click="fetchCategories(pagination.page - 1)">Önceki</button>
|
||||
</li>
|
||||
<li v-for="page in Math.ceil(pagination.total / pagination.per_page)" :key="page"
|
||||
class="page-item" :class="{ active: pagination.page === page }">
|
||||
<button class="page-link" @click="fetchCategories(page)">{{ page }}</button>
|
||||
</li>
|
||||
<li class="page-item" :class="{ disabled: pagination.page >= Math.ceil(pagination.total / pagination.per_page) }">
|
||||
<button class="page-link" @click="fetchCategories(pagination.page + 1)">Sonraki</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create/Edit Modal -->
|
||||
<div class="modal fade" id="categoryModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ isEditing ? 'Kategoriyi Düzenle' : 'Yeni Kategori' }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveCategory">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Başlık</label>
|
||||
<input v-model="formData.title" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Açıklama</label>
|
||||
<textarea v-model="formData.description" class="form-control" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Üst Kategori (Opsiyonel)</label>
|
||||
<select v-model="formData.parent_id" class="form-select">
|
||||
<option :value="null">Ana Kategori</option>
|
||||
<!-- Only show active categories as parents to avoid confusion -->
|
||||
<option v-for="cat in activeCategories" :key="cat.ID" :value="cat.ID"
|
||||
:disabled="cat.ID === formData.ID">
|
||||
{{ cat.title }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2"
|
||||
data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Category } from '~~/types/category';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const categories = ref<Category[]>([]);
|
||||
const activeCategories = ref<Category[]>([]); // For parent selection
|
||||
const loading = ref(false);
|
||||
const isEditing = ref(false);
|
||||
const formData = ref<Partial<Category>>({});
|
||||
const filterStatus = ref(''); // '' = active, 'only' = trashed, 'with' = all
|
||||
let categoryModal: any = null;
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
// -- API --
|
||||
|
||||
const fetchCategories = async (page = 1) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const query: any = { page }; // Pagination if supported by admin endpoint
|
||||
if (filterStatus.value) {
|
||||
query.trashed = filterStatus.value;
|
||||
}
|
||||
|
||||
// Use Admin endpoint for management
|
||||
const url = '/api/v1/admin/categories';
|
||||
|
||||
const res = await $fetch<any>(url, {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
query
|
||||
});
|
||||
|
||||
if (res.data) {
|
||||
categories.value = res.data;
|
||||
pagination.value = res.meta || { page: 1, per_page: 100, total: res.data.length }; // Fallback if no meta
|
||||
} else if (Array.isArray(res)) {
|
||||
// Fallback for non-paginated response (if API changes or for active list)
|
||||
categories.value = res;
|
||||
pagination.value = { page: 1, per_page: 100, total: res.length };
|
||||
} else {
|
||||
categories.value = [];
|
||||
}
|
||||
|
||||
// Fetch active categories for parent selection (always needs active ones)
|
||||
if (filterStatus.value === '') {
|
||||
activeCategories.value = categories.value;
|
||||
} else {
|
||||
// If we are viewing trashed, we still need active categories for the dropdown
|
||||
// We can fetch them separately/lightweight if needed, or just allow 'null' parent
|
||||
// checking if we have them cached or fetch explicitly
|
||||
// For now, let's just fetch active ones if we don't have them
|
||||
const activeRes = await $fetch<Category[]>('/api/v1/categories', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
activeCategories.value = activeRes || [];
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
categories.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const openModal = (category: Category | null) => {
|
||||
isEditing.value = !!category;
|
||||
formData.value = category ? { ...category } : { title: '', description: '', parent_id: null };
|
||||
|
||||
// Check if modal instance exists
|
||||
const el = document.getElementById('categoryModal');
|
||||
if (el) {
|
||||
// @ts-ignore
|
||||
categoryModal = new bootstrap.Modal(el);
|
||||
categoryModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const saveCategory = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const url = isEditing.value
|
||||
? `/api/v1/categories/${formData.value.ID}`
|
||||
: '/api/v1/categories';
|
||||
|
||||
const method = isEditing.value ? 'PUT' : 'POST';
|
||||
|
||||
await $fetch(url, {
|
||||
method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: formData.value
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', `Kategori ${isEditing.value ? 'güncellendi' : 'eklendi'}.`, 'success');
|
||||
if (categoryModal) categoryModal.hide();
|
||||
fetchCategories(pagination.value.page);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteCategory = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Kategori silinecek (Çöp kutusuna taşınacak).",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sil',
|
||||
cancelButtonText: 'İptal',
|
||||
confirmButtonColor: '#d33'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
await $fetch(`/api/v1/categories/${id}`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Silindi', 'Kategori silindi.', 'success');
|
||||
fetchCategories(pagination.value.page);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const restoreCategory = async (id: number) => {
|
||||
try {
|
||||
await $fetch(`/api/v1/admin/categories/${id}/restore`, {
|
||||
method: 'POST',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Kategori geri yüklendi.', 'success');
|
||||
fetchCategories(pagination.value.page);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Geri yükleme başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const hardDeleteCategory = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Kalıcı Olarak Sil?',
|
||||
text: "Bu işlem geri alınamaz!",
|
||||
icon: 'error',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Kalıcı Sil',
|
||||
cancelButtonText: 'İptal',
|
||||
confirmButtonColor: '#d33'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
await $fetch(`/api/v1/admin/categories/${id}/hard`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Silindi', 'Kategori kalıcı olarak silindi.', 'success');
|
||||
fetchCategories(pagination.value.page);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchCategories();
|
||||
});
|
||||
</script>
|
||||
325
app/pages/admin/blog/posts/[id].vue
Normal file
325
app/pages/admin/blog/posts/[id].vue
Normal file
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Gönderi Düzenle</h2>
|
||||
<NuxtLink to="/admin/blog/posts" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i> Geri Dön
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div v-if="loadingData" class="text-center py-5">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="card">
|
||||
<div class="card-body">
|
||||
<form @submit.prevent="updatePost">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- Title -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Başlık</label>
|
||||
<input v-model="formData.title" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">İçerik</label>
|
||||
<textarea v-model="formData.content" class="form-control" rows="10" required></textarea>
|
||||
<div class="form-text">HTML içeriği girebilirsiniz.</div>
|
||||
</div>
|
||||
|
||||
<!-- Tags -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Etiketler</div>
|
||||
<div class="card-body" style="max-height: 200px; overflow-y: auto;">
|
||||
<div v-if="availableTags.length === 0" class="text-muted small">Etiket bulunamadı.</div>
|
||||
<div v-for="tag in availableTags" :key="tag.ID" class="form-check">
|
||||
<input class="form-check-input" type="checkbox" :value="tag.ID" v-model="selectedTags" :id="`tag-${tag.ID}`">
|
||||
<label class="form-check-label" :for="`tag-${tag.ID}`">
|
||||
{{ tag.name }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<!-- Categories -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Kategoriler</div>
|
||||
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
||||
<div v-for="cat in categories" :key="cat.ID" class="form-check">
|
||||
<input class="form-check-input" type="checkbox" :value="cat.ID" v-model="formData.category_ids" :id="`cat-${cat.ID}`">
|
||||
<label class="form-check-label" :for="`cat-${cat.ID}`">
|
||||
{{ cat.title }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Image Upload & Options -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Öne Çıkan Görsel</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3 text-center">
|
||||
<div v-if="imagePreview" class="mb-3">
|
||||
<img :src="imagePreview" class="img-fluid rounded" style="max-height: 200px;">
|
||||
<button type="button" class="btn btn-sm btn-danger mt-2" @click="removeImage">Değiştir / Kaldır</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="mb-3">
|
||||
<i class="fas fa-image fa-3x text-muted"></i>
|
||||
</div>
|
||||
<input type="file" class="form-control" @change="handleFileUpload" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="imageFile">
|
||||
<hr>
|
||||
<h6>Resim Ayarları</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Genişlik (px)</label>
|
||||
<input v-model="imageOptions.width" type="number" class="form-control form-control-sm" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Yükseklik (px)</label>
|
||||
<input v-model="imageOptions.height" type="number" class="form-control form-control-sm" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Kalite (1-100)</label>
|
||||
<input v-model="imageOptions.quality" type="number" class="form-control form-control-sm" min="1" max="100">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Format</label>
|
||||
<select v-model="imageOptions.format" class="form-select form-select-sm">
|
||||
<option value="jpeg">JPEG</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="webp">WebP</option>
|
||||
<option value="avif">AVIF</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Update Button -->
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" class="btn btn-primary" :disabled="saving">
|
||||
<span v-if="saving" class="spinner-border spinner-border-sm me-2"></span>
|
||||
{{ saving ? 'Güncelleniyor...' : 'Güncelle' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Category } from '~~/types/category';
|
||||
import type { Post } from '~~/types/post';
|
||||
import type { Tag, TagResponse } from '~~/types/tag';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const loadingData = ref(true);
|
||||
const saving = ref(false);
|
||||
const categories = ref<Category[]>([]);
|
||||
const availableTags = ref<Tag[]>([]);
|
||||
const selectedTags = ref<number[]>([]);
|
||||
const imageFile = ref<File | null>(null);
|
||||
const imagePreview = ref<string | null>(null);
|
||||
|
||||
const formData = ref({
|
||||
title: '',
|
||||
content: '',
|
||||
category_ids: [] as number[],
|
||||
});
|
||||
|
||||
const imageOptions = ref({
|
||||
width: null as number | null,
|
||||
height: null as number | null,
|
||||
quality: 80,
|
||||
format: 'jpeg'
|
||||
});
|
||||
|
||||
const postId = route.params.id as string;
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const [catRes, tagRes] = await Promise.all([
|
||||
$fetch<Category[]>('/api/v1/categories', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
}),
|
||||
$fetch<TagResponse>('/api/v1/admin/tags', { // Fetching all tags
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
params: { limit: 100 }
|
||||
})
|
||||
]);
|
||||
|
||||
categories.value = catRes || [];
|
||||
availableTags.value = tagRes?.data || [];
|
||||
|
||||
// After fetching data, fetch post
|
||||
await fetchPost();
|
||||
|
||||
} catch (e) {
|
||||
console.error('Veriler yüklenemedi', e);
|
||||
loadingData.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPost = async () => {
|
||||
try {
|
||||
const res = await $fetch<Post>(`/api/v1/posts/${postId}`, {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
if (res) {
|
||||
formData.value.title = res.title;
|
||||
formData.value.content = res.content;
|
||||
formData.value.category_ids = res.categories?.map(c => c.ID) || [];
|
||||
|
||||
// Pre-select tags
|
||||
if (res.tags) {
|
||||
selectedTags.value = res.tags.map(t => t.ID);
|
||||
}
|
||||
|
||||
// Image
|
||||
if (res.images) {
|
||||
// Should parse if JSON or string
|
||||
let imgPath = res.images;
|
||||
if (imgPath.startsWith('[') || imgPath.startsWith('{')) {
|
||||
try {
|
||||
const parsed = JSON.parse(imgPath);
|
||||
if (Array.isArray(parsed) && parsed.length > 0) imgPath = parsed[0];
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
imagePreview.value = getImageUrl(imgPath);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Post yüklenemedi', e);
|
||||
Swal.fire('Hata', 'Gönderi bulunamadı veya yüklenemedi.', 'error');
|
||||
router.push('/admin/blog/posts');
|
||||
} finally {
|
||||
loadingData.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const getImageUrl = (path: string) => {
|
||||
if (path.startsWith('http')) return path;
|
||||
if (path.startsWith('/')) return `${config.public.BASE_API_URL}${path}`;
|
||||
return `${config.public.BASE_API_URL}/${path}`;
|
||||
};
|
||||
|
||||
|
||||
const handleFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
const file = target.files[0];
|
||||
imageFile.value = file;
|
||||
imagePreview.value = URL.createObjectURL(file);
|
||||
|
||||
// Default format based on uploaded file or keep jpeg
|
||||
if (file.type === 'image/png') imageOptions.value.format = 'png';
|
||||
else if (file.type === 'image/webp') imageOptions.value.format = 'webp';
|
||||
else imageOptions.value.format = 'jpeg';
|
||||
}
|
||||
};
|
||||
|
||||
const removeImage = () => {
|
||||
imageFile.value = null;
|
||||
imagePreview.value = null;
|
||||
};
|
||||
|
||||
const updatePost = async () => {
|
||||
saving.value = true;
|
||||
try {
|
||||
const data = new FormData();
|
||||
data.append('title', formData.value.title);
|
||||
data.append('content', formData.value.content);
|
||||
|
||||
if (formData.value.category_ids.length > 0) {
|
||||
data.append('category_ids', formData.value.category_ids.join(','));
|
||||
}
|
||||
|
||||
if (selectedTags.value.length > 0) {
|
||||
data.append('tag_ids', selectedTags.value.join(','));
|
||||
}
|
||||
|
||||
// Optimize & Append Image if exists
|
||||
if (imageFile.value) {
|
||||
const optimizeData = new FormData();
|
||||
optimizeData.append('file', imageFile.value);
|
||||
if (imageOptions.value.width) optimizeData.append('width', imageOptions.value.width.toString());
|
||||
if (imageOptions.value.height) optimizeData.append('height', imageOptions.value.height.toString());
|
||||
optimizeData.append('quality', imageOptions.value.quality.toString());
|
||||
optimizeData.append('format', imageOptions.value.format);
|
||||
|
||||
// Fetch as Blob from server/api/optimize
|
||||
const optimizedBlob = await $fetch<Blob>('/api/optimize', {
|
||||
method: 'POST',
|
||||
body: optimizeData,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
const ext = imageOptions.value.format === 'jpg' ? 'jpeg' : imageOptions.value.format;
|
||||
const filename = `img-${Date.now()}.${ext === 'jpeg' ? 'jpg' : ext}`;
|
||||
const optimizedFile = new File([optimizedBlob], filename, { type: `image/${ext}` });
|
||||
|
||||
data.append('images', optimizedFile);
|
||||
}
|
||||
|
||||
await $fetch(`/api/v1/posts/${postId}`, {
|
||||
method: 'PUT',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: data
|
||||
});
|
||||
|
||||
Swal.fire({
|
||||
title: 'Başarılı',
|
||||
text: 'Gönderi güncellendi.',
|
||||
icon: 'success',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Listeye Dön',
|
||||
cancelButtonText: 'Kalsın'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push('/admin/blog/posts');
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', error.data?.message || 'Bir hata oluştu.', 'error');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
253
app/pages/admin/blog/posts/create.vue
Normal file
253
app/pages/admin/blog/posts/create.vue
Normal file
@@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Yeni Gönderi Ekle</h2>
|
||||
<NuxtLink to="/admin/blog/posts" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i> Geri Dön
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form @submit.prevent="savePost">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- Title -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Başlık</label>
|
||||
<input v-model="formData.title" type="text" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">İçerik</label>
|
||||
<textarea v-model="formData.content" class="form-control" rows="10" required></textarea>
|
||||
<div class="form-text">HTML içeriği girebilirsiniz.</div>
|
||||
</div>
|
||||
|
||||
<!-- Tags -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Etiketler</div>
|
||||
<div class="card-body" style="max-height: 200px; overflow-y: auto;">
|
||||
<div v-if="availableTags.length === 0" class="text-muted small">Etiket bulunamadı.</div>
|
||||
<div v-for="tag in availableTags" :key="tag.ID" class="form-check">
|
||||
<input class="form-check-input" type="checkbox" :value="tag.ID" v-model="selectedTags" :id="`tag-${tag.ID}`">
|
||||
<label class="form-check-label" :for="`tag-${tag.ID}`">
|
||||
{{ tag.name }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<!-- Categories -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Kategoriler</div>
|
||||
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
||||
<div v-if="categories.length === 0" class="text-muted small">Kategori bulunamadı.</div>
|
||||
<div v-for="cat in categories" :key="cat.ID" class="form-check">
|
||||
<input class="form-check-input" type="checkbox" :value="cat.ID" v-model="formData.category_ids" :id="`cat-${cat.ID}`">
|
||||
<label class="form-check-label" :for="`cat-${cat.ID}`">
|
||||
{{ cat.title }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Image Upload & Options -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">Öne Çıkan Görsel</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3 text-center">
|
||||
<div v-if="imagePreview" class="mb-3">
|
||||
<img :src="imagePreview" class="img-fluid rounded" style="max-height: 200px;">
|
||||
<button type="button" class="btn btn-sm btn-danger mt-2" @click="removeImage">Kaldır</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="mb-3">
|
||||
<i class="fas fa-image fa-3x text-muted"></i>
|
||||
</div>
|
||||
<input type="file" class="form-control" @change="handleFileUpload" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="imageFile">
|
||||
<hr>
|
||||
<h6>Resim Ayarları</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Genişlik (px)</label>
|
||||
<input v-model="imageOptions.width" type="number" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Yükseklik (px)</label>
|
||||
<input v-model="imageOptions.height" type="number" class="form-control form-control-sm" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Kalite (1-100)</label>
|
||||
<input v-model="imageOptions.quality" type="number" class="form-control form-control-sm" min="1" max="100">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Format</label>
|
||||
<select v-model="imageOptions.format" class="form-select form-select-sm">
|
||||
<option value="jpeg">JPEG</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="webp">WebP</option>
|
||||
<option value="avif">AVIF</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Publish Button -->
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
{{ loading ? 'İşleniyor...' : 'Yayınla' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Category } from '~~/types/category';
|
||||
import type { Tag, TagResponse } from '~~/types/tag';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
const loading = ref(false);
|
||||
const categories = ref<Category[]>([]);
|
||||
const availableTags = ref<Tag[]>([]);
|
||||
const selectedTags = ref<number[]>([]);
|
||||
const imageFile = ref<File | null>(null);
|
||||
const imagePreview = ref<string | null>(null);
|
||||
|
||||
const formData = ref({
|
||||
title: '',
|
||||
content: '',
|
||||
category_ids: [] as number[],
|
||||
});
|
||||
|
||||
const imageOptions = ref({
|
||||
width: null as number | null,
|
||||
height: null as number | null,
|
||||
quality: 80,
|
||||
format: 'jpeg'
|
||||
});
|
||||
|
||||
// Fetch Categories and Tags
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const [catRes, tagRes] = await Promise.all([
|
||||
$fetch<Category[]>('/api/v1/categories', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
}),
|
||||
$fetch<TagResponse>('/api/v1/admin/tags', { // Fetching all tags (admin endpoint for safety/completeness)
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
params: { limit: 100 } // Get a reasonable amount of tags
|
||||
})
|
||||
]);
|
||||
|
||||
categories.value = catRes || [];
|
||||
availableTags.value = tagRes?.data || [];
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
const file = target.files[0];
|
||||
imageFile.value = file;
|
||||
imagePreview.value = URL.createObjectURL(file);
|
||||
|
||||
// Default format based on uploaded file or keep jpeg
|
||||
if (file.type === 'image/png') imageOptions.value.format = 'png';
|
||||
else if (file.type === 'image/webp') imageOptions.value.format = 'webp';
|
||||
else imageOptions.value.format = 'jpeg';
|
||||
}
|
||||
};
|
||||
|
||||
const removeImage = () => {
|
||||
imageFile.value = null;
|
||||
imagePreview.value = null;
|
||||
};
|
||||
|
||||
const savePost = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = new FormData();
|
||||
data.append('title', formData.value.title);
|
||||
data.append('content', formData.value.content);
|
||||
|
||||
if (formData.value.category_ids.length > 0) {
|
||||
data.append('category_ids', formData.value.category_ids.join(','));
|
||||
}
|
||||
|
||||
if (selectedTags.value.length > 0) {
|
||||
data.append('tag_ids', selectedTags.value.join(','));
|
||||
}
|
||||
|
||||
// Optimize Image and append to FormData
|
||||
if (imageFile.value) {
|
||||
const optimizeData = new FormData();
|
||||
optimizeData.append('file', imageFile.value);
|
||||
if (imageOptions.value.width) optimizeData.append('width', imageOptions.value.width.toString());
|
||||
if (imageOptions.value.height) optimizeData.append('height', imageOptions.value.height.toString());
|
||||
optimizeData.append('quality', imageOptions.value.quality.toString());
|
||||
optimizeData.append('format', imageOptions.value.format);
|
||||
|
||||
const optimizedBlob = await $fetch<Blob>('/api/optimize', {
|
||||
method: 'POST',
|
||||
body: optimizeData,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
const ext = imageOptions.value.format === 'jpg' ? 'jpeg' : imageOptions.value.format;
|
||||
const filename = `img-${Date.now()}.${ext === 'jpeg' ? 'jpg' : ext}`;
|
||||
const optimizedFile = new File([optimizedBlob], filename, { type: `image/${ext}` });
|
||||
|
||||
data.append('images', optimizedFile);
|
||||
}
|
||||
|
||||
await $fetch('/api/v1/posts', {
|
||||
method: 'POST',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: data
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Gönderi başarıyla oluşturuldu.', 'success');
|
||||
router.push('/admin/blog/posts');
|
||||
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', error.data?.message || 'Bir hata oluştu.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
252
app/pages/admin/blog/posts/index.vue
Normal file
252
app/pages/admin/blog/posts/index.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Gönderi Yönetimi</h2>
|
||||
<NuxtLink to="/admin/blog/posts/create" class="btn btn-primary">
|
||||
<i class="fas fa-plus me-2"></i> Yeni Gönderi
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<!-- Filter / Search -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<select v-model="filterStatus" class="form-select" @change="fetchPosts(1)">
|
||||
<option value="">Tümü</option>
|
||||
<option value="only">Silinenler (Çöp Kutusu)</option>
|
||||
<option value="with">Tümü (Silinenler Dahil)</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Future: Add search input here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Posts List -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div v-if="loading" class="text-center py-5">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="posts.length === 0" class="text-center py-5 text-muted">
|
||||
Kayıt bulunamadı.
|
||||
</div>
|
||||
|
||||
<div v-else class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Resim</th>
|
||||
<th>Başlık</th>
|
||||
<th>Kategoriler</th>
|
||||
<th>Etiketler</th>
|
||||
<th>Durum</th>
|
||||
<th>Tarih</th>
|
||||
<th class="text-end">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="post in posts" :key="post.ID">
|
||||
<td>{{ post.ID }}</td>
|
||||
<td>
|
||||
<img v-if="getFirstImage(post.images)" :src="getImageUrl(getFirstImage(post.images)!)"
|
||||
alt="thumbnail" class="rounded" style="width: 50px; height: 50px; object-fit: cover;">
|
||||
<div v-else class="bg-light rounded d-flex align-items-center justify-content-center text-muted"
|
||||
style="width: 50px; height: 50px;">
|
||||
<i class="fas fa-image"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold">{{ post.title }}</div>
|
||||
<small class="text-muted">{{ post.slug }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span v-for="cat in post.categories" :key="cat.ID" class="badge bg-info text-dark me-1">
|
||||
{{ cat.title }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-for="tag in post.tags" :key="tag.ID" class="badge bg-secondary me-1">
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="post.DeletedAt" class="badge bg-danger">Silindi</span>
|
||||
<span v-else class="badge bg-success">Aktif</span>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ formatDate(post.CreatedAt) }}</div>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div v-if="!post.DeletedAt">
|
||||
<NuxtLink :to="`/admin/blog/posts/${post.ID}`" class="btn btn-sm btn-outline-primary me-2">
|
||||
<i class="fas fa-edit"></i>
|
||||
</NuxtLink>
|
||||
<button class="btn btn-sm btn-outline-danger" @click="deletePost(post.ID)">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<button class="btn btn-sm btn-outline-success" @click="restorePost(post.ID)">
|
||||
<i class="fas fa-trash-restore"></i> Geri Yükle
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav v-if="pagination.total > pagination.per_page" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item" :class="{ disabled: pagination.page === 1 }">
|
||||
<button class="page-link" @click="fetchPosts(pagination.page - 1)">Önceki</button>
|
||||
</li>
|
||||
<li v-for="page in Math.ceil(pagination.total / pagination.per_page)" :key="page"
|
||||
class="page-item" :class="{ active: pagination.page === page }">
|
||||
<button class="page-link" @click="fetchPosts(page)">{{ page }}</button>
|
||||
</li>
|
||||
<li class="page-item" :class="{ disabled: pagination.page >= Math.ceil(pagination.total / pagination.per_page) }">
|
||||
<button class="page-link" @click="fetchPosts(pagination.page + 1)">Sonraki</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Post, PostResponse } from '~~/types/post';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const posts = ref<Post[]>([]);
|
||||
const loading = ref(false);
|
||||
const filterStatus = ref(''); // '' = active (default from API perspective usually?), or we need to handle default
|
||||
// Default listing in doc: /api/v1/admin/posts
|
||||
// Trashed only: ?trashed=only
|
||||
// With trashed: ?trashed=with
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const fetchPosts = async (page = 1) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const query: any = { page, limit: pagination.value.per_page };
|
||||
if (filterStatus.value) {
|
||||
query.trashed = filterStatus.value;
|
||||
}
|
||||
|
||||
const res = await $fetch<PostResponse>('/api/v1/admin/posts', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
query
|
||||
});
|
||||
|
||||
posts.value = res.data || [];
|
||||
pagination.value = res.meta;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
posts.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deletePost = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Bu gönderi silinecek (Çöp kutusuna taşınacak).",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sil',
|
||||
cancelButtonText: 'İptal',
|
||||
confirmButtonColor: '#d33'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
await $fetch(`/api/v1/posts/${id}`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Silindi', 'Gönderi silindi.', 'success');
|
||||
fetchPosts(pagination.value.page);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const restorePost = async (id: number) => {
|
||||
// Implement restore logic if API supports it, otherwise basic delete is usually soft delete.
|
||||
// If current delete IS soft delete, usually there's a restore endpoint or update with deleted_at=null.
|
||||
// Assuming for now we just show it for concept, but strict restore endpoint might be needed.
|
||||
// For now, let's keep it simple. If no explicit restore endpoint documented, maybe we can't restore easily from UI yet.
|
||||
// But wait, the user asked to implement based on admin_post.md.
|
||||
// Use case "sadece soft delete olmuslar listesi" implies we can see them.
|
||||
// Usually a PUT to /api/v1/admin/posts/{id}/restore or similar.
|
||||
// Since not documented, I will skip implementation of ACTUAL restore call but keep the button or maybe comment it out
|
||||
// until confirmed. Or I can assume standard behaviour if I knew the backend.
|
||||
// Let's assume standard soft delete REST pattern often allows toggle or specific endpoint.
|
||||
// I'll leave the button but functionality might be missing.
|
||||
// Actually, let's look at the docs again.
|
||||
// Docs only show GET lists.
|
||||
// I will remove Restore button functionality for now to avoid errors, or just show alert 'Not implemented'.
|
||||
Swal.fire('Bilgi', 'Geri yükleme özelliği henüz API tarafında dökümante edilmedi.', 'info');
|
||||
};
|
||||
|
||||
const getFirstImage = (imagesStr: string): string | null => {
|
||||
try {
|
||||
// API returns "images": "uploads/posts/..." OR JSON string "[\"...\"]"
|
||||
// Let's try to parse if it looks like JSON
|
||||
if (imagesStr.startsWith('[') || imagesStr.startsWith('{')) {
|
||||
const parsed = JSON.parse(imagesStr);
|
||||
if (Array.isArray(parsed) && parsed.length > 0) return parsed[0];
|
||||
}
|
||||
return imagesStr;
|
||||
} catch (e) {
|
||||
return imagesStr;
|
||||
}
|
||||
};
|
||||
|
||||
const getImageUrl = (path: string) => {
|
||||
if (path.startsWith('http')) return path;
|
||||
if (path.startsWith('/')) return `${config.public.BASE_API_URL}${path}`;
|
||||
return `${config.public.BASE_API_URL}/${path}`;
|
||||
};
|
||||
|
||||
const formatDate = (dateStr: string) => {
|
||||
return new Date(dateStr).toLocaleDateString('tr-TR', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchPosts();
|
||||
});
|
||||
</script>
|
||||
317
app/pages/admin/blog/tags/index.vue
Normal file
317
app/pages/admin/blog/tags/index.vue
Normal file
@@ -0,0 +1,317 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Etiket Yönetimi</h2>
|
||||
<button class="btn btn-primary" @click="openModal()">
|
||||
<i class="fas fa-plus me-2"></i> Yeni Etiket
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-outline-secondary" :class="{ active: filterTrashed === 'without' }" @click="changeFilter('without')">
|
||||
Aktif
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" :class="{ active: filterTrashed === 'only' }" @click="changeFilter('only')">
|
||||
Çöp Kutusu
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" :class="{ active: filterTrashed === 'with' }" @click="changeFilter('with')">
|
||||
Hepsi
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div v-if="loading" class="text-center py-5">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Etiket Adı</th>
|
||||
<th>Oluşturulma</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="tag in tags" :key="tag.ID">
|
||||
<td>#{{ tag.ID }}</td>
|
||||
<td>
|
||||
<span class="fw-bold">{{ tag.name }}</span>
|
||||
</td>
|
||||
<td>{{ new Date(tag.CreatedAt).toLocaleDateString('tr-TR') }}</td>
|
||||
<td>
|
||||
<span v-if="tag.DeletedAt" class="badge bg-danger">Silinmiş</span>
|
||||
<span v-else class="badge bg-success">Aktif</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button v-if="!tag.DeletedAt" class="btn btn-outline-primary" @click="openModal(tag)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
|
||||
<button v-if="!tag.DeletedAt" class="btn btn-outline-danger" @click="deleteTag(tag.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
|
||||
<button v-if="tag.DeletedAt" class="btn btn-outline-success" @click="restoreTag(tag.ID)" title="Geri Yükle">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
|
||||
<button v-if="tag.DeletedAt" class="btn btn-outline-dark" @click="hardDeleteTag(tag.ID)" title="Kalıcı Sil">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="tags.length === 0">
|
||||
<td colspan="5" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav v-if="totalPages > 1" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item" :class="{ disabled: currentPage === 1 }">
|
||||
<button class="page-link" @click="changePage(currentPage - 1)">Önceki</button>
|
||||
</li>
|
||||
<li v-for="page in totalPages" :key="page" class="page-item" :class="{ active: currentPage === page }">
|
||||
<button class="page-link" @click="changePage(page)">{{ page }}</button>
|
||||
</li>
|
||||
<li class="page-item" :class="{ disabled: currentPage === totalPages }">
|
||||
<button class="page-link" @click="changePage(currentPage + 1)">Sonraki</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tag Modal -->
|
||||
<div class="modal fade" id="tagModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ isEditing ? 'Etiket Düzenle' : 'Yeni Etiket Ekle' }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveTag">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Etiket Adı</label>
|
||||
<input v-model="tagForm.name" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="saving">
|
||||
<span v-if="saving" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Tag, TagResponse } from '~~/types/tag';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const tags = ref<Tag[]>([]);
|
||||
const currentPage = ref(1);
|
||||
const totalPages = ref(1);
|
||||
const filterTrashed = ref<'without' | 'with' | 'only'>('without');
|
||||
|
||||
const tagForm = ref({
|
||||
ID: 0,
|
||||
name: ''
|
||||
});
|
||||
const isEditing = ref(false);
|
||||
let tagModal: any = null;
|
||||
|
||||
const fetchTags = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await $fetch<TagResponse>('/api/v1/admin/tags', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
params: {
|
||||
page: currentPage.value,
|
||||
limit: 10,
|
||||
...(filterTrashed.value !== 'without' && { trashed: filterTrashed.value })
|
||||
}
|
||||
});
|
||||
|
||||
if (res && res.data) {
|
||||
tags.value = res.data;
|
||||
totalPages.value = Math.ceil(res.meta.total / res.meta.per_page);
|
||||
} else {
|
||||
tags.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Etiketler yüklenirken bir hata oluştu.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const changePage = (page: number) => {
|
||||
if (page >= 1 && page <= totalPages.value) {
|
||||
currentPage.value = page;
|
||||
fetchTags();
|
||||
}
|
||||
};
|
||||
|
||||
const changeFilter = (filter: 'without' | 'with' | 'only') => {
|
||||
filterTrashed.value = filter;
|
||||
currentPage.value = 1;
|
||||
fetchTags();
|
||||
};
|
||||
|
||||
const openModal = (tag: Tag | null = null) => {
|
||||
if (tag) {
|
||||
isEditing.value = true;
|
||||
tagForm.value = { ID: tag.ID, name: tag.name };
|
||||
} else {
|
||||
isEditing.value = false;
|
||||
tagForm.value = { ID: 0, name: '' };
|
||||
}
|
||||
|
||||
const modalEl = document.getElementById('tagModal');
|
||||
if (modalEl) {
|
||||
// @ts-ignore
|
||||
tagModal = new bootstrap.Modal(modalEl);
|
||||
tagModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const saveTag = async () => {
|
||||
saving.value = true;
|
||||
try {
|
||||
let url = '/api/v1/tags';
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
|
||||
if (isEditing.value && tagForm.value.ID) {
|
||||
url = `/api/v1/tags/${tagForm.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
await $fetch(url, {
|
||||
method: method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: { name: tagForm.value.name }
|
||||
});
|
||||
|
||||
if (tagModal) tagModal.hide();
|
||||
Swal.fire('Başarılı', `Etiket ${isEditing.value ? 'güncellendi' : 'eklendi'}.`, 'success');
|
||||
fetchTags();
|
||||
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', error.data?.message || 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteTag = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Bu etiketi çöp kutusuna taşımak istediğinize emin misiniz?",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sil',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
await $fetch(`/api/v1/tags/${id}`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
Swal.fire('Silindi', 'Etiket çöp kutusuna taşındı.', 'success');
|
||||
fetchTags();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const hardDeleteTag = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'DİKKAT! Kalıcı Silme',
|
||||
text: "Bu işlem geri alınamaz! Etiketi tamamen silmek istediğinize emin misiniz?",
|
||||
icon: 'error',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Tamamen Sil',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
await $fetch(`/api/v1/admin/tags/${id}/hard`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
Swal.fire('Silindi', 'Etiket kalıcı olarak silindi.', 'success');
|
||||
fetchTags();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Kalıcı silme işlemi başarısız.', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const restoreTag = async (id: number) => {
|
||||
try {
|
||||
await $fetch(`/api/v1/admin/tags/${id}/restore`, {
|
||||
method: 'POST',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
Swal.fire('Geri Yüklendi', 'Etiket başarıyla geri yüklendi.', 'success');
|
||||
fetchTags();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Geri yükleme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchTags();
|
||||
});
|
||||
</script>
|
||||
14
app/pages/admin/index.vue
Normal file
14
app/pages/admin/index.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div>
|
||||
admin index
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
501
app/pages/admin/security/index.vue
Normal file
501
app/pages/admin/security/index.vue
Normal file
@@ -0,0 +1,501 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Güvenlik & Ağ Yönetimi</h2>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs mb-4" id="securityTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="whitelist-tab" data-bs-toggle="tab" data-bs-target="#whitelist"
|
||||
type="button" role="tab" aria-controls="whitelist" aria-selected="true">CORS Whitelist</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="blacklist-tab" data-bs-toggle="tab" data-bs-target="#blacklist"
|
||||
type="button" role="tab" aria-controls="blacklist" aria-selected="false">CORS Blacklist</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="ratelimit-tab" data-bs-toggle="tab" data-bs-target="#ratelimit"
|
||||
type="button" role="tab" aria-controls="ratelimit" aria-selected="false">Rate Limit</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="securityTabContent">
|
||||
<!-- WHITELIST TAB -->
|
||||
<div class="tab-pane fade show active" id="whitelist" role="tabpanel" aria-labelledby="whitelist-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Whitelist Origins</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="form-check form-switch me-3 mb-0">
|
||||
<input class="form-check-input" type="checkbox" v-model="showDeleted"
|
||||
id="whitelistDeleted">
|
||||
<label class="form-check-label" for="whitelistDeleted">Silinenler</label>
|
||||
</div>
|
||||
<button class="btn btn-success btn-sm" @click="openModal('whitelist')"><i
|
||||
class="fas fa-plus me-2"></i> Yeni
|
||||
Ekle</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Origin</th>
|
||||
<th>Açıklama</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end" width="150">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in whitelistItems" :key="item.ID">
|
||||
<td>{{ item.origin }}</td>
|
||||
<td>{{ item.description }}</td>
|
||||
<td>
|
||||
<span class="badge" :class="item.is_active ? 'bg-success' : 'bg-secondary'">
|
||||
{{ item.is_active ? 'Aktif' : 'Pasif' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<template v-if="!item.DeletedAt">
|
||||
<button class="btn btn-outline-primary"
|
||||
@click="openModal('whitelist', item)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger"
|
||||
@click="deleteItem('whitelist', item.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</template>
|
||||
<button v-else class="btn btn-outline-success"
|
||||
@click="restoreItem('whitelist', item.ID)" title="Geri Yükle">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="whitelistItems.length === 0">
|
||||
<td colspan="4" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BLACKLIST TAB -->
|
||||
<div class="tab-pane fade" id="blacklist" role="tabpanel" aria-labelledby="blacklist-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Blacklist Origins</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="form-check form-switch me-3 mb-0">
|
||||
<input class="form-check-input" type="checkbox" v-model="showDeleted"
|
||||
id="blacklistDeleted">
|
||||
<label class="form-check-label" for="blacklistDeleted">Silinenler</label>
|
||||
</div>
|
||||
<button class="btn btn-success btn-sm" @click="openModal('blacklist')"><i
|
||||
class="fas fa-plus me-2"></i>
|
||||
Yeni
|
||||
Ekle</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Origin</th>
|
||||
<th>Sebep</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end" width="150">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in blacklistItems" :key="item.ID">
|
||||
<td>{{ item.origin }}</td>
|
||||
<td>{{ item.reason }}</td>
|
||||
<td>
|
||||
<span class="badge" :class="item.is_active ? 'bg-danger' : 'bg-secondary'">
|
||||
{{ item.is_active ? 'Aktif' : 'Pasif' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<template v-if="!item.DeletedAt">
|
||||
<button class="btn btn-outline-primary"
|
||||
@click="openModal('blacklist', item)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger"
|
||||
@click="deleteItem('blacklist', item.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</template>
|
||||
<button v-else class="btn btn-outline-success"
|
||||
@click="restoreItem('blacklist', item.ID)" title="Geri Yükle">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="blacklistItems.length === 0">
|
||||
<td colspan="4" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RATE LIMIT TAB -->
|
||||
<div class="tab-pane fade" id="ratelimit" role="tabpanel" aria-labelledby="ratelimit-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Rate Limits</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="form-check form-switch me-3 mb-0">
|
||||
<input class="form-check-input" type="checkbox" v-model="showDeleted"
|
||||
id="ratelimitDeleted">
|
||||
<label class="form-check-label" for="ratelimitDeleted">Silinenler</label>
|
||||
</div>
|
||||
<button class="btn btn-success btn-sm" @click="openModal('ratelimit')"><i
|
||||
class="fas fa-plus me-2"></i>
|
||||
Yeni
|
||||
Ekle</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>İsim</th>
|
||||
<th>Max İstek / Süre (sn)</th>
|
||||
<th>Açıklama</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end" width="150">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in rateLimitItems" :key="item.ID">
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.max_requests }} / {{ item.window_seconds }}sn</td>
|
||||
<td>{{ item.description }}</td>
|
||||
<td>
|
||||
<span class="badge" :class="item.is_active ? 'bg-success' : 'bg-secondary'">
|
||||
{{ item.is_active ? 'Aktif' : 'Pasif' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<template v-if="!item.DeletedAt">
|
||||
<button class="btn btn-outline-primary"
|
||||
@click="openModal('ratelimit', item)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger"
|
||||
@click="deleteItem('ratelimit', item.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</template>
|
||||
<button v-else class="btn btn-outline-success"
|
||||
@click="restoreItem('ratelimit', item.ID)" title="Geri Yükle">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="rateLimitItems.length === 0">
|
||||
<td colspan="5" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="securityModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ modalTitle }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveItem">
|
||||
<!-- Common Fields -->
|
||||
<div v-if="activeTab === 'whitelist' || activeTab === 'blacklist'" class="mb-3">
|
||||
<label class="form-label">Origin (URL)</label>
|
||||
<input v-model="formData.origin" type="text" class="form-control"
|
||||
placeholder="http://example.com" required>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'whitelist'" class="mb-3">
|
||||
<label class="form-label">Açıklama</label>
|
||||
<input v-model="formData.description" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'blacklist'" class="mb-3">
|
||||
<label class="form-label">Sebep</label>
|
||||
<input v-model="formData.reason" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<!-- Rate Limit Fields -->
|
||||
<div v-if="activeTab === 'ratelimit'" class="mb-3">
|
||||
<label class="form-label">İsim (Endpoint/Key)</label>
|
||||
<input v-model="formData.name" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div v-if="activeTab === 'ratelimit'" class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Max İstek</label>
|
||||
<input v-model="formData.max_requests" type="number" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Süre (Saniye)</label>
|
||||
<input v-model="formData.window_seconds" type="number" class="form-control"
|
||||
required>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="activeTab === 'ratelimit'" class="mb-3">
|
||||
<label class="form-label">Açıklama</label>
|
||||
<input v-model="formData.description" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" v-model="formData.is_active"
|
||||
id="isActiveCheck">
|
||||
<label class="form-check-label" for="isActiveCheck">Aktif</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2"
|
||||
data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { CorsWhitelistItem, CorsBlacklistItem, RateLimitItem } from '~~/types/security';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const loading = ref(false);
|
||||
|
||||
const activeTab = ref<'whitelist' | 'blacklist' | 'ratelimit'>('whitelist');
|
||||
const showDeleted = ref(false); // Global toggle for simplicity, or could be per tab
|
||||
const whitelistItems = ref<CorsWhitelistItem[]>([]);
|
||||
const blacklistItems = ref<CorsBlacklistItem[]>([]);
|
||||
const rateLimitItems = ref<RateLimitItem[]>([]);
|
||||
|
||||
const formData = ref<any>({});
|
||||
const isEditing = ref(false);
|
||||
let securityModal: any = null;
|
||||
|
||||
const modalTitle = computed(() => {
|
||||
const action = isEditing.value ? 'Düzenle' : 'Ekle';
|
||||
if (activeTab.value === 'whitelist') return `Whitelist ${action}`;
|
||||
if (activeTab.value === 'blacklist') return `Blacklist ${action}`;
|
||||
return `Rate Limit ${action}`;
|
||||
});
|
||||
|
||||
// Watch for tab or filter changes
|
||||
watch([activeTab, showDeleted], () => {
|
||||
fetchItems();
|
||||
});
|
||||
|
||||
// -- API HANDLERS --
|
||||
|
||||
const fetchItems = async () => {
|
||||
try {
|
||||
const query = showDeleted.value ? { deleted: 'true' } : {};
|
||||
const headers = { Authorization: `Bearer ${(authData.value as any)?.accessToken}` };
|
||||
|
||||
if (activeTab.value === 'whitelist') {
|
||||
const res = await $fetch<any>('/api/v1/admin/cors/whitelist', { baseURL: config.public.BASE_API_URL, headers, query });
|
||||
whitelistItems.value = res.items || [];
|
||||
} else if (activeTab.value === 'blacklist') {
|
||||
const res = await $fetch<any>('/api/v1/admin/cors/blacklist', { baseURL: config.public.BASE_API_URL, headers, query });
|
||||
blacklistItems.value = res.items || [];
|
||||
} else {
|
||||
const res = await $fetch<any>('/api/v1/admin/rate-limit', { baseURL: config.public.BASE_API_URL, headers, query });
|
||||
rateLimitItems.value = res.items || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fetch error:', error);
|
||||
// Fallback or empty list on error
|
||||
if (activeTab.value === 'whitelist') whitelistItems.value = [];
|
||||
else if (activeTab.value === 'blacklist') blacklistItems.value = [];
|
||||
else rateLimitItems.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const openModal = (tab: 'whitelist' | 'blacklist' | 'ratelimit', item: any = null) => {
|
||||
activeTab.value = tab;
|
||||
if (item) {
|
||||
isEditing.value = true;
|
||||
formData.value = { ...item };
|
||||
} else {
|
||||
isEditing.value = false;
|
||||
formData.value = { is_active: true };
|
||||
}
|
||||
|
||||
const modalEl = document.getElementById('securityModal');
|
||||
if (modalEl) {
|
||||
// @ts-ignore
|
||||
securityModal = new bootstrap.Modal(modalEl);
|
||||
securityModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const saveItem = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
let endpoint = '';
|
||||
if (activeTab.value === 'whitelist') endpoint = '/api/v1/admin/cors/whitelist';
|
||||
else if (activeTab.value === 'blacklist') endpoint = '/api/v1/admin/cors/blacklist';
|
||||
else endpoint = '/api/v1/admin/rate-limit';
|
||||
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
if (isEditing.value && formData.value.ID) {
|
||||
endpoint += `/${formData.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
// Convert numbers for RateLimit
|
||||
if (activeTab.value === 'ratelimit') {
|
||||
formData.value.max_requests = Number(formData.value.max_requests);
|
||||
formData.value.window_seconds = Number(formData.value.window_seconds);
|
||||
}
|
||||
|
||||
await $fetch(endpoint, {
|
||||
method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: formData.value
|
||||
});
|
||||
|
||||
if (securityModal) securityModal.hide();
|
||||
Swal.fire('Başarılı', 'İşlem başarıyla tamamlandı.', 'success');
|
||||
fetchItems();
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = async (tab: string, id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Silme Tipi?',
|
||||
text: "Kayıt nasıl silinsin?",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: 'Soft Sil (Arşivle)',
|
||||
denyButtonText: 'Hard Sil (Kalıcı)',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (result.isDismissed) return;
|
||||
|
||||
const isHard = result.isDenied;
|
||||
|
||||
try {
|
||||
let endpoint = '';
|
||||
if (tab === 'whitelist') endpoint = `/api/v1/admin/cors/whitelist/${id}`;
|
||||
else if (tab === 'blacklist') endpoint = `/api/v1/admin/cors/blacklist/${id}`;
|
||||
else endpoint = `/api/v1/admin/rate-limit/${id}`;
|
||||
|
||||
if (isHard) endpoint += '/hard';
|
||||
|
||||
await $fetch(endpoint, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Silindi!', isHard ? 'Kayıt kalıcı olarak silindi.' : 'Kayıt arşivlendi (soft delete).', 'success');
|
||||
fetchItems();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const restoreItem = async (tab: string, id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Kayıt geri yüklenecek.",
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Geri Yükle',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
let endpoint = '';
|
||||
if (tab === 'whitelist') endpoint = `/api/v1/admin/cors/whitelist/${id}/restore`;
|
||||
else if (tab === 'blacklist') endpoint = `/api/v1/admin/cors/blacklist/${id}/restore`;
|
||||
else endpoint = `/api/v1/admin/rate-limit/${id}/restore`;
|
||||
|
||||
await $fetch(endpoint, {
|
||||
method: 'POST', // Assuming POST for restore action
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Kayıt geri yüklendi.', 'success');
|
||||
fetchItems();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Geri yükleme başarısız. Endpoint mevcut olmayabilir.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// Bootstrap tabs events
|
||||
const tabEls = document.querySelectorAll('button[data-bs-toggle="tab"]');
|
||||
tabEls.forEach(tabEl => {
|
||||
tabEl.addEventListener('shown.bs.tab', (event: any) => {
|
||||
const targetId = event.target.getAttribute('data-bs-target');
|
||||
if (targetId === '#whitelist') activeTab.value = 'whitelist';
|
||||
if (targetId === '#blacklist') activeTab.value = 'blacklist';
|
||||
if (targetId === '#ratelimit') activeTab.value = 'ratelimit';
|
||||
// fetchItems() is called by watcher
|
||||
});
|
||||
});
|
||||
|
||||
fetchItems(); // Initial fetch
|
||||
});
|
||||
</script>
|
||||
```
|
||||
578
app/pages/admin/settings/index.vue
Normal file
578
app/pages/admin/settings/index.vue
Normal file
@@ -0,0 +1,578 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Ayarlar</h2>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs mb-4" id="settingsTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button"
|
||||
role="tab" aria-controls="general" aria-selected="true">Genel Ayarlar</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="hero-tab" data-bs-toggle="tab" data-bs-target="#hero" type="button" role="tab"
|
||||
aria-controls="hero" aria-selected="false">Hero (Banner) Ayarları</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="settingsTabContent">
|
||||
<!-- GENERAL SETTINGS TAB -->
|
||||
<div class="tab-pane fade show active" id="general" role="tabpanel" aria-labelledby="general-tab">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form @submit.prevent="updateSettings">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Site Başlığı</label>
|
||||
<input v-model="settingForm.title" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Slogan</label>
|
||||
<input v-model="settingForm.slogan" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Telefon</label>
|
||||
<input v-model="settingForm.phone" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Email</label>
|
||||
<input v-model="settingForm.email" type="email" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Adres</label>
|
||||
<textarea v-model="settingForm.address" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Harita Embed Code</label>
|
||||
<textarea v-model="settingForm.map_embed" class="form-control" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Copyright Metni</label>
|
||||
<input v-model="settingForm.copyright" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">SEO Ayarları</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Meta Başlık</label>
|
||||
<input v-model="settingForm.meta_title" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Meta Açıklama</label>
|
||||
<input v-model="settingForm.meta_description" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Sosyal Medya</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Facebook</label>
|
||||
<input v-model="settingForm.facebook" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Twitter / X</label>
|
||||
<input v-model="settingForm.x" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Instagram</label>
|
||||
<input v-model="settingForm.instagram" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Linkedin</label>
|
||||
<input v-model="settingForm.linkedin" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Pinterest</label>
|
||||
<input v-model="settingForm.pinterest" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label class="form-label">Whatsapp</label>
|
||||
<input v-model="settingForm.whatsapp" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Logolar</h5>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Beyaz Logo (Dark Mod için)</label>
|
||||
<input @change="handleFileUpload($event, 'w_logo')" type="file" class="form-control">
|
||||
<div v-if="settingForm.w_logo && typeof settingForm.w_logo === 'string'" class="mt-2">
|
||||
<img :src="config.public.BASE_API_URL + settingForm.w_logo" height="50" class="bg-dark p-1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Siyah Logo (Light Mod için)</label>
|
||||
<input @change="handleFileUpload($event, 'b_logo')" type="file" class="form-control">
|
||||
<div v-if="settingForm.b_logo && typeof settingForm.b_logo === 'string'" class="mt-2">
|
||||
<img :src="config.public.BASE_API_URL + settingForm.b_logo" height="50" class="bg-light border p-1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">Resim Optimizasyon Ayarları (Logo İçin)</h5>
|
||||
<hr>
|
||||
<div class="row bg-light p-3 rounded mx-1">
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Format</label>
|
||||
<select v-model="imageSettings.format" class="form-select">
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="webp">WEBP</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Kalite (1-100)</label>
|
||||
<input v-model="imageSettings.quality" type="number" min="1" max="100" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Genişlik (px)</label>
|
||||
<input v-model="imageSettings.width" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Yükseklik (px)</label>
|
||||
<input v-model="imageSettings.height" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HERO SETTINGS TAB -->
|
||||
<div class="tab-pane fade" id="hero" role="tabpanel" aria-labelledby="hero-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Hero Listesi</h5>
|
||||
<button class="btn btn-success btn-sm" @click="openHeroModal()"><i class="fas fa-plus me-2"></i> Yeni
|
||||
Ekle</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Resim</th>
|
||||
<th>Başlık</th>
|
||||
<th>Alt Başlıklar</th>
|
||||
<th>Durum</th>
|
||||
<th class="text-end" width="100">İşlemler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="hero in heroes" :key="hero.ID">
|
||||
<td>
|
||||
<img v-if="hero.image" :src="config.public.BASE_API_URL + hero.image"
|
||||
style="max-width: 60px; height: 40px; object-fit: cover;" class="rounded border">
|
||||
<span v-else>-</span>
|
||||
</td>
|
||||
<td>{{ hero.title }}</td>
|
||||
<td>
|
||||
<small class="d-block text-muted">{{ hero.text1 }}</small>
|
||||
<small class="d-block text-muted">{{ hero.text2 }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge" :class="hero.is_active ? 'bg-success' : 'bg-secondary'">
|
||||
{{ hero.is_active ? 'Aktif' : 'Pasif' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-outline-primary" @click="openHeroModal(hero)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" @click="deleteHero(hero.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="heroes.length === 0">
|
||||
<td colspan="5" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HERO MODAL -->
|
||||
<div class="modal fade" id="heroModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ isEditingHero ? 'Hero Düzenle' : 'Yeni Hero Ekle' }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveHero">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Başlık</label>
|
||||
<input v-model="heroForm.title" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 1</label>
|
||||
<input v-model="heroForm.text1" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 2</label>
|
||||
<input v-model="heroForm.text2" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 4</label>
|
||||
<input v-model="heroForm.text4" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Text 5</label>
|
||||
<input v-model="heroForm.text5" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Renk</label>
|
||||
<div class="input-group">
|
||||
<input v-model="heroForm.color" type="color" class="form-control form-control-color"
|
||||
title="Renk Seçin">
|
||||
<input v-model="heroForm.color" type="text" class="form-control" placeholder="#ffffff">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Durum</label>
|
||||
<div class="form-check form-switch mt-2">
|
||||
<input class="form-check-input" type="checkbox" v-model="heroForm.is_active" id="heroActive">
|
||||
<label class="form-check-label" for="heroActive">Aktif</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Görsel</label>
|
||||
<input @change="handleHeroFileUpload($event)" type="file" class="form-control">
|
||||
<div v-if="heroForm.image && typeof heroForm.image === 'string'" class="mt-2">
|
||||
<small>Mevcut Görsel:</small>
|
||||
<img :src="config.public.BASE_API_URL + heroForm.image" height="80" class="d-block mt-1 rounded">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<div class="p-3 bg-light rounded border">
|
||||
<h6>Resim Optimizasyon Ayarları</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Format</label>
|
||||
<select v-model="imageSettings.format" class="form-select">
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="webp">WEBP</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Kalite</label>
|
||||
<input v-model="imageSettings.quality" type="number" min="1" max="100" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Genişlik</label>
|
||||
<input v-model="imageSettings.width" type="number" class="form-control" placeholder="Opsiyonel">
|
||||
</div>
|
||||
<div class="col-md-3 mb-2">
|
||||
<label class="form-label">Yükseklik</label>
|
||||
<input v-model="imageSettings.height" type="number" class="form-control"
|
||||
placeholder="Opsiyonel">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Setting } from '~~/types/setting';
|
||||
import type { Hero } from '~~/types/hero';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const loading = ref(false);
|
||||
|
||||
// --- SETTINGS ---
|
||||
const settingForm = ref<Partial<Setting>>({});
|
||||
const w_logo_file = ref<File | null>(null);
|
||||
const b_logo_file = ref<File | null>(null);
|
||||
|
||||
const imageSettings = ref({
|
||||
format: 'avif',
|
||||
quality: 80,
|
||||
width: null as number | null,
|
||||
height: null as number | null
|
||||
});
|
||||
|
||||
// Fetch Settings
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const data = await $fetch<Setting>('/api/v1/setting', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
});
|
||||
if (data) {
|
||||
settingForm.value = { ...data };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Settings fetch error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: Event, type: 'w_logo' | 'b_logo') => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
if (type === 'w_logo') w_logo_file.value = target.files[0];
|
||||
if (type === 'b_logo') b_logo_file.value = target.files[0];
|
||||
}
|
||||
};
|
||||
|
||||
const optimizeImage = async (file: File): Promise<File> => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('format', imageSettings.value.format);
|
||||
formData.append('quality', String(imageSettings.value.quality));
|
||||
if (imageSettings.value.width) formData.append('width', String(imageSettings.value.width));
|
||||
if (imageSettings.value.height) formData.append('height', String(imageSettings.value.height));
|
||||
|
||||
const optimizedBlob = await $fetch<Blob>('/api/optimize', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
const ext = imageSettings.value.format === 'jpg' ? 'jpeg' : imageSettings.value.format;
|
||||
const filename = `img-${Date.now()}-${Math.floor(Math.random() * 10000)}.${ext === 'jpeg' ? 'jpg' : ext}`;
|
||||
|
||||
const optimizedFile = new File([optimizedBlob], filename, {
|
||||
type: `image/${ext}`
|
||||
});
|
||||
|
||||
return optimizedFile;
|
||||
};
|
||||
|
||||
const updateSettings = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
Object.keys(settingForm.value).forEach(key => {
|
||||
const value = (settingForm.value as any)[key];
|
||||
if (value !== null && value !== undefined && key !== 'w_logo' && key !== 'b_logo' && key !== 'ID' && key !== 'CreatedAt' && key !== 'UpdatedAt' && key !== 'DeletedAt') {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
if (w_logo_file.value) {
|
||||
const optimized = await optimizeImage(w_logo_file.value);
|
||||
formData.append('w_logo', optimized);
|
||||
}
|
||||
if (b_logo_file.value) {
|
||||
const optimized = await optimizeImage(b_logo_file.value);
|
||||
formData.append('b_logo', optimized);
|
||||
}
|
||||
|
||||
formData.append('is_active', 'true');
|
||||
|
||||
let url = '/api/v1/setting';
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
|
||||
if (settingForm.value.ID) {
|
||||
url = `/api/v1/setting/${settingForm.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
await $fetch(url, {
|
||||
method: method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Ayarlar güncellendi.', 'success');
|
||||
fetchSettings(); // Refresh
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Güncelleme sırasında hata oluştu.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// --- HERO ---
|
||||
const heroes = ref<Hero[]>([]);
|
||||
const heroForm = ref<Partial<Hero>>({});
|
||||
const heroImageFile = ref<File | null>(null);
|
||||
const isEditingHero = ref(false);
|
||||
let heroModal: any = null;
|
||||
|
||||
const fetchHeroes = async () => {
|
||||
try {
|
||||
const response = await $fetch<any>('/api/v1/heroes', {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
});
|
||||
|
||||
if (response && Array.isArray(response.data)) {
|
||||
heroes.value = response.data;
|
||||
} else if (Array.isArray(response)) {
|
||||
heroes.value = response;
|
||||
} else if (response && typeof response === 'object') {
|
||||
heroes.value = [response]; // Wrap single object
|
||||
} else {
|
||||
heroes.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Hero fetch error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const openHeroModal = (hero: Hero | null = null) => {
|
||||
if (hero) {
|
||||
isEditingHero.value = true;
|
||||
heroForm.value = { ...hero };
|
||||
} else {
|
||||
isEditingHero.value = false;
|
||||
heroForm.value = { is_active: true };
|
||||
}
|
||||
heroImageFile.value = null;
|
||||
|
||||
// Initialize Modal
|
||||
const modalEl = document.getElementById('heroModal');
|
||||
if (modalEl) {
|
||||
// @ts-ignore
|
||||
heroModal = new bootstrap.Modal(modalEl);
|
||||
heroModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const handleHeroFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
heroImageFile.value = target.files[0];
|
||||
}
|
||||
};
|
||||
|
||||
const saveHero = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const formData = new FormData();
|
||||
Object.keys(heroForm.value).forEach(key => {
|
||||
const value = (heroForm.value as any)[key];
|
||||
if (value !== null && value !== undefined && key !== 'image' && key !== 'ID' && key !== 'CreatedAt' && key !== 'UpdatedAt' && key !== 'DeletedAt') {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
if (heroImageFile.value) {
|
||||
const optimized = await optimizeImage(heroImageFile.value);
|
||||
formData.append('image', optimized);
|
||||
}
|
||||
|
||||
// Ensure is_active sent as string 'true'/'false' if backend expects it
|
||||
// formData.set('is_active', String(heroForm.value.is_active));
|
||||
|
||||
let url = '/api/v1/hero';
|
||||
let method: 'POST' | 'PUT' = 'POST';
|
||||
|
||||
if (isEditingHero.value && heroForm.value.ID) {
|
||||
url = `/api/v1/hero/${heroForm.value.ID}`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
await $fetch(url, {
|
||||
method: method,
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
|
||||
if (heroModal) heroModal.hide();
|
||||
Swal.fire('Başarılı', `Hero ${isEditingHero.value ? 'güncellendi' : 'eklendi'}.`, 'success');
|
||||
fetchHeroes();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteHero = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Emin misiniz?',
|
||||
text: "Bu hero kaydını silmek istediğinize emin misiniz?",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet, Sil',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
await $fetch(`/api/v1/hero/${id}`, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: {
|
||||
Authorization: `Bearer ${(authData.value as any)?.accessToken}`
|
||||
}
|
||||
});
|
||||
Swal.fire('Silindi!', 'Kayıt başarıyla silindi.', 'success');
|
||||
fetchHeroes();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchSettings();
|
||||
fetchHeroes();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Tabs styling */
|
||||
.nav-tabs .nav-link {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
font-weight: bold;
|
||||
color: #0d6efd;
|
||||
}
|
||||
</style>
|
||||
457
app/pages/admin/users/index.vue
Normal file
457
app/pages/admin/users/index.vue
Normal file
@@ -0,0 +1,457 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Kullanıcı Yönetimi</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center bg-white">
|
||||
<h5 class="mb-0">Kullanıcı Listesi</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="form-check form-switch me-3 mb-0">
|
||||
<input class="form-check-input" type="checkbox" v-model="showDeleted" id="userDeleted">
|
||||
<label class="form-check-label" for="userDeleted">Silinenler</label>
|
||||
</div>
|
||||
<button class="btn btn-success btn-sm" @click="openModal(null)"><i class="fas fa-plus me-2"></i> Yeni
|
||||
Kullanıcı</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Avatar</th>
|
||||
<th>Kullanıcı Adı</th>
|
||||
<th>Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in users" :key="user.ID">
|
||||
<td>{{ user.ID }}</td>
|
||||
<td>
|
||||
<img :src="getAvatarUrl(user)" alt="Avatar" class="rounded-circle border" width="40" height="40"
|
||||
style="object-fit: cover;"
|
||||
onerror="this.src='https://ui-avatars.com/api/?name=User&background=random'">
|
||||
</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>
|
||||
{{ user.email }}
|
||||
<span v-if="user.email_verified" class="badge bg-success ms-1"><i class="fas fa-check"></i></span>
|
||||
<span v-else class="badge bg-warning ms-1" title="Email Doğrulanmadı"><i
|
||||
class="fas fa-exclamation"></i></span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="user.profiles && user.profiles.length > 0">
|
||||
{{ user.profiles[0]?.first_name }} {{ user.profiles[0]?.last_name }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge" :class="user.is_admin ? 'bg-primary' : 'bg-secondary'">
|
||||
{{ user.is_admin ? 'Admin' : 'User' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<template v-if="!user.DeletedAt">
|
||||
<button class="btn btn-outline-primary" @click="openModal(user)" title="Düzenle">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" @click="deleteUser(user.ID)" title="Sil">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button class="btn btn-outline-success" @click="restoreUser(user.ID)" title="Geri Yükle">
|
||||
<i class="fas fa-trash-restore"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" @click="deleteUser(user.ID)" title="Kalıcı Sil">
|
||||
<i class="fas fa-ban"></i>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="users.length === 0">
|
||||
<td colspan="6" class="text-center py-4">Kayıt bulunamadı.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="userModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ isEditing ? 'Kullanıcı Düzenle' : 'Yeni Kullanıcı Ekle' }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="saveUser">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Kullanıcı Adı</label>
|
||||
<input v-model="formData.username" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Email</label>
|
||||
<input v-model="formData.email" type="email" class="form-control" required>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">İsim</label>
|
||||
<input v-model="formData.first_name" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Soyisim</label>
|
||||
<input v-model="formData.last_name" type="text" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Avatar</label>
|
||||
<div class="d-flex align-items-center mb-2" v-if="formData.avatar_url">
|
||||
<img :src="config.public.BASE_API_URL + formData.avatar_url" alt="Avatar Preview"
|
||||
class="rounded-circle me-3"
|
||||
style="width: 50px; height: 50px; object-fit: cover; border: 1px solid #dee2e6;">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger"
|
||||
@click="formData.avatar_url = ''">Kaldır</button>
|
||||
</div>
|
||||
<input type="file" class="form-control" @change="handleFileUpload" accept="image/*">
|
||||
<input v-model="formData.avatar_url" type="text" class="form-control mt-2"
|
||||
placeholder="veya URL girin (/uploads/...)">
|
||||
|
||||
<!-- Image Optimization Settings -->
|
||||
<div class="mt-3 p-3 border rounded bg-light">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<small class="fw-bold text-primary"><i class="fas fa-magic me-1"></i> Resim Optimizasyonu</small>
|
||||
<span class="badge bg-secondary" style="font-size: 0.7em">İsteğe Bağlı</span>
|
||||
</div>
|
||||
<div class="row g-2">
|
||||
<div class="col-6 col-md-3">
|
||||
<label class="form-label small text-muted">Format</label>
|
||||
<select v-model="imageSettings.format" class="form-select form-select-sm">
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="webp">WEBP</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<label class="form-label small text-muted">Kalite (1-100)</label>
|
||||
<input v-model="imageSettings.quality" type="number" class="form-control form-control-sm" min="1"
|
||||
max="100">
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<label class="form-label small text-muted">Genişlik (px)</label>
|
||||
<input v-model="imageSettings.width" type="number" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<label class="form-label small text-muted">Yükseklik (px)</label>
|
||||
<input v-model="imageSettings.height" type="number" class="form-control form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Şifre <span v-if="isEditing" class="text-muted small">(Boş bırakılırsa
|
||||
değişmez)</span></label>
|
||||
<input v-model="formData.password" type="password" class="form-control" :required="!isEditing"
|
||||
minlength="6">
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" v-model="formData.is_admin" id="isAdminCheck">
|
||||
<label class="form-check-label" for="isAdminCheck">Admin Yetkisi</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" v-model="formData.email_verified"
|
||||
id="emailVerifiedCheck">
|
||||
<label class="form-check-label" for="emailVerifiedCheck">Email Onaylı</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">İptal</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { User } from '~~/types/user';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'admin'
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const { data: authData } = useAuth();
|
||||
const loading = ref(false);
|
||||
const users = ref<User[]>([]);
|
||||
const showDeleted = ref(false);
|
||||
const formData = ref<any>({});
|
||||
const isEditing = ref(false);
|
||||
const avatarFile = ref<File | null>(null);
|
||||
|
||||
let userModal: any = null;
|
||||
|
||||
// -- API HANDLERS --
|
||||
|
||||
const fetchUsers = async () => {
|
||||
try {
|
||||
const endpoint = showDeleted.value ? '/api/v1/users/list/deleted' : '/api/v1/users/list';
|
||||
const res = await $fetch<any>(endpoint, {
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
users.value = res.users || [];
|
||||
} catch (error) {
|
||||
console.error('Fetch error:', error);
|
||||
users.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
watch(showDeleted, () => {
|
||||
fetchUsers();
|
||||
});
|
||||
|
||||
const openModal = (user: User | null = null) => {
|
||||
if (user) {
|
||||
isEditing.value = true;
|
||||
// Flatten the structure for the form
|
||||
// Check if avatar_url is on user or profile
|
||||
const avatarUrl = user.avatar_url || user.profiles?.[0]?.avatar_url || '';
|
||||
|
||||
formData.value = {
|
||||
...user,
|
||||
first_name: user.profiles?.[0]?.first_name || '',
|
||||
last_name: user.profiles?.[0]?.last_name || '',
|
||||
avatar_url: avatarUrl,
|
||||
password: '' // Don't prefill password
|
||||
};
|
||||
} else {
|
||||
isEditing.value = false;
|
||||
formData.value = { is_admin: false, email_verified: false };
|
||||
}
|
||||
|
||||
const modalEl = document.getElementById('userModal');
|
||||
if (modalEl) {
|
||||
// Reset image settings
|
||||
imageSettings.value = {
|
||||
format: 'avif',
|
||||
quality: 80,
|
||||
width: null,
|
||||
height: null
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
userModal = new bootstrap.Modal(modalEl);
|
||||
userModal.show();
|
||||
}
|
||||
};
|
||||
|
||||
const getAvatarUrl = (user: User) => {
|
||||
// Priority: avatar_url (from User or Profile) -> UI Avatar
|
||||
// Check user.avatar_url first (if backend sends it on user object)
|
||||
// Then check profiles[0].avatar
|
||||
const avatarPath = user.avatar_url || user.profiles?.[0]?.avatar_url;
|
||||
|
||||
if (avatarPath) {
|
||||
// If it's a full URL (e.g. googlelh3...) return as is
|
||||
if (avatarPath.startsWith('http')) return avatarPath;
|
||||
// If local path, prepend base API URL
|
||||
return config.public.BASE_API_URL + avatarPath;
|
||||
}
|
||||
|
||||
// Default: UI Avatars
|
||||
const name = (user.profiles?.[0]?.first_name && user.profiles?.[0]?.last_name)
|
||||
? `${user.profiles[0].first_name} ${user.profiles[0].last_name}`
|
||||
: user.username;
|
||||
|
||||
return `https://ui-avatars.com/api/?name=${encodeURIComponent(name)}&background=random&color=fff`;
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) {
|
||||
avatarFile.value = target.files[0];
|
||||
}
|
||||
};
|
||||
|
||||
const imageSettings = ref({
|
||||
format: 'avif',
|
||||
quality: 80,
|
||||
width: null as number | null,
|
||||
height: null as number | null
|
||||
});
|
||||
|
||||
const optimizeImage = async (file: File): Promise<File> => {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
fd.append('format', imageSettings.value.format);
|
||||
fd.append('quality', String(imageSettings.value.quality));
|
||||
if (imageSettings.value.width) fd.append('width', String(imageSettings.value.width));
|
||||
if (imageSettings.value.height) fd.append('height', String(imageSettings.value.height));
|
||||
|
||||
const optimizedBlob = await $fetch<Blob>('/api/optimize', {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
const ext = imageSettings.value.format === 'jpg' ? 'jpeg' : imageSettings.value.format;
|
||||
const filename = `avatar-${Date.now()}.${ext === 'jpeg' ? 'jpg' : ext}`;
|
||||
|
||||
return new File([optimizedBlob], filename, { type: `image/${ext}` });
|
||||
};
|
||||
|
||||
const saveUser = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (isEditing.value) {
|
||||
// Context: PUT /api/v1/users/:id
|
||||
// Using Multipart/Form-Data for strict compliance with backend requirements
|
||||
const userId = formData.value.ID;
|
||||
const fd = new FormData();
|
||||
|
||||
// Append Avatar if selected
|
||||
if (avatarFile.value) {
|
||||
try {
|
||||
const optimized = await optimizeImage(avatarFile.value);
|
||||
fd.append('avatar', optimized);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
fd.append('avatar', avatarFile.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Append other fields
|
||||
// Explicitly mapping known fields to ensure order and presence matches expectation,
|
||||
// or just iterating keys. Iterating keys is safer for "all fields".
|
||||
// However, we must ensure boolean -> string conversion.
|
||||
|
||||
Object.keys(formData.value).forEach(key => {
|
||||
const val = formData.value[key];
|
||||
// Filter out non-form fields and sensitive/system fields
|
||||
if (key !== 'ID' && key !== 'profiles' && key !== 'avatar_url' && key !== 'CreatedAt' && key !== 'UpdatedAt' && key !== 'DeletedAt') {
|
||||
if (key === 'password' && !val) return; // Skip empty password
|
||||
fd.append(key, String(val));
|
||||
}
|
||||
});
|
||||
|
||||
await $fetch(`/api/v1/users/${userId}`, {
|
||||
method: 'PUT',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` },
|
||||
body: fd
|
||||
});
|
||||
|
||||
// Reset file
|
||||
avatarFile.value = null;
|
||||
Swal.fire('Başarılı', 'Kullanıcı güncellendi.', 'success');
|
||||
|
||||
} else {
|
||||
// Context: Create (Register) - POST JSON
|
||||
await $fetch('/api/v1/auth/register', {
|
||||
method: 'POST',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
body: formData.value
|
||||
});
|
||||
Swal.fire('Başarılı', 'Kullanıcı oluşturuldu.', 'success');
|
||||
}
|
||||
|
||||
if (userModal) userModal.hide();
|
||||
fetchUsers();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'İşlem başarısız.', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteUser = async (id: number) => {
|
||||
const isHardDelete = showDeleted.value; // If showing deleted, then next action is hard delete
|
||||
|
||||
const result = await Swal.fire({
|
||||
title: isHardDelete ? 'Kalıcı Silinecek?' : 'Silinecek?',
|
||||
text: isHardDelete ? "Bu işlem geri alınamaz!" : "Kullanıcı arşivlenecek.",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: isHardDelete ? 'Evet, Kalıcı Sil' : 'Evet, Sil',
|
||||
cancelButtonText: 'İptal',
|
||||
confirmButtonColor: '#d33'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
let endpoint = `/api/v1/users/${id}`;
|
||||
if (isHardDelete) endpoint += '/hard';
|
||||
|
||||
await $fetch(endpoint, {
|
||||
method: 'DELETE',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Silindi!', 'İşlem başarılı.', 'success');
|
||||
fetchUsers();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Silme işlemi başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const restoreUser = async (id: number) => {
|
||||
const result = await Swal.fire({
|
||||
title: 'Geri Yükle?',
|
||||
text: "Kullanıcı aktif edilecek.",
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Evet',
|
||||
cancelButtonText: 'İptal'
|
||||
});
|
||||
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
try {
|
||||
await $fetch(`/api/v1/users/${id}/restore`, {
|
||||
method: 'POST',
|
||||
baseURL: config.public.BASE_API_URL,
|
||||
headers: { Authorization: `Bearer ${(authData.value as any)?.accessToken}` }
|
||||
});
|
||||
|
||||
Swal.fire('Başarılı', 'Kullanıcı geri yüklendi.', 'success');
|
||||
fetchUsers();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire('Hata', 'Geri yükleme başarısız.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchUsers();
|
||||
});
|
||||
</script>
|
||||
177
app/pages/auth/login.vue
Normal file
177
app/pages/auth/login.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<div class="login-area pt-120 pb-120">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6 col-md-8">
|
||||
<div class="login-form-wrap shadow-lg p-5 rounded bg-white">
|
||||
<div class="login-header text-center mb-4">
|
||||
<h2 class="mb-2">Giriş Yap</h2>
|
||||
<p>
|
||||
Hesabınız yok mu?
|
||||
<NuxtLink to="/auth/register" class="text-primary fw-bold">Kayıt Olun</NuxtLink>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleLogin">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">E-posta Adresi</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
|
||||
<input type="email" class="form-control" id="email" v-model="form.email"
|
||||
placeholder="E-posta adresinizi girin" required>
|
||||
</div>
|
||||
<div v-if="errors.email" class="text-danger small mt-1">{{ errors.email }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Şifre</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
||||
<input type="password" class="form-control" id="password" v-model="form.password"
|
||||
placeholder="Şifrenizi girin" required>
|
||||
</div>
|
||||
<div v-if="errors.password" class="text-danger small mt-1">{{ errors.password }}</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="remember-me">
|
||||
<label class="form-check-label" for="remember-me">Beni Hatırla</label>
|
||||
</div>
|
||||
<a href="#" class="text-muted small">Şifremi Unuttum?</a>
|
||||
</div>
|
||||
|
||||
<!-- Turnstile Component -->
|
||||
<ClientOnly>
|
||||
<div class="mb-4 d-flex justify-content-center">
|
||||
<NuxtTurnstile v-model="turnstileToken" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100 py-2" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2" role="status"
|
||||
aria-hidden="true"></span>
|
||||
{{ loading ? 'Giriş Yapılıyor...' : 'Giriş Yap' }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { loginSchema, type LoginInput } from '~~/utils/validations';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'guest-only',
|
||||
auth: { unauthenticatedOnly: true, navigateAuthenticatedTo: '/' }
|
||||
});
|
||||
|
||||
const { signIn } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
// Reactive form state
|
||||
const form = reactive<LoginInput>({
|
||||
email: '',
|
||||
password: ''
|
||||
});
|
||||
|
||||
// Validation errors state
|
||||
const errors = reactive<Partial<Record<keyof LoginInput, string>>>({});
|
||||
const loading = ref(false);
|
||||
const turnstileToken = ref('');
|
||||
|
||||
const validate = () => {
|
||||
const result = loginSchema.safeParse(form);
|
||||
|
||||
// Clear previous errors
|
||||
Object.keys(errors).forEach(key => delete errors[key as keyof LoginInput]);
|
||||
|
||||
if (!result.success) {
|
||||
result.error.errors.forEach(err => {
|
||||
if (err.path[0]) {
|
||||
errors[err.path[0] as keyof LoginInput] = err.message;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleLogin = async () => {
|
||||
if (!validate()) return;
|
||||
|
||||
if (!turnstileToken.value) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Güvenlik Kontrolü',
|
||||
text: 'Lütfen Turnstile güvenlik kontrolünü tamamlayın.',
|
||||
timer: 3000,
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const result = await signIn('credentials', {
|
||||
email: form.email,
|
||||
password: form.password,
|
||||
redirect: false,
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Giriş Başarısız',
|
||||
text: 'E-posta veya şifre hatalı.',
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 3000
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Giriş Başarılı',
|
||||
text: 'Yönlendiriliyorsunuz...',
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 1500
|
||||
});
|
||||
setTimeout(() => {
|
||||
router.push('/');
|
||||
}, 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Hata',
|
||||
text: 'Bir şeyler ters gitti, lütfen tekrar deneyin.',
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-area {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-form-wrap {
|
||||
border-top: 5px solid #0d6efd;
|
||||
}
|
||||
</style>
|
||||
222
app/pages/auth/register.vue
Normal file
222
app/pages/auth/register.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<div class="register-area pt-120 pb-120">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8 col-md-10">
|
||||
<div class="register-form-wrap shadow-lg p-5 rounded bg-white">
|
||||
<div class="register-header text-center mb-4">
|
||||
<h2 class="mb-2">Hesap Oluşturun</h2>
|
||||
<p>
|
||||
Zaten hesabınız var mı?
|
||||
<NuxtLink to="/auth/login" class="text-primary fw-bold">Giriş Yapın</NuxtLink>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleRegister">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Kullanıcı Adı</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
||||
<input type="text" class="form-control" id="username" v-model="form.username"
|
||||
placeholder="Kullanıcı adı seçin" required>
|
||||
</div>
|
||||
<div v-if="errors.username" class="text-danger small mt-1">{{ errors.username }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="first_name" class="form-label">Ad</label>
|
||||
<input type="text" class="form-control" id="first_name" v-model="form.first_name"
|
||||
placeholder="Adınız" required>
|
||||
<div v-if="errors.first_name" class="text-danger small mt-1">{{ errors.first_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="last_name" class="form-label">Soyad</label>
|
||||
<input type="text" class="form-control" id="last_name" v-model="form.last_name"
|
||||
placeholder="Soyadınız" required>
|
||||
<div v-if="errors.last_name" class="text-danger small mt-1">{{ errors.last_name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">E-posta Adresi</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
|
||||
<input type="email" class="form-control" id="email" v-model="form.email"
|
||||
placeholder="E-posta adresiniz" required>
|
||||
</div>
|
||||
<div v-if="errors.email" class="text-danger small mt-1">{{ errors.email }}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="password" class="form-label">Şifre</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
||||
<input type="password" class="form-control" id="password"
|
||||
v-model="form.password" placeholder="Şifreniz" required>
|
||||
</div>
|
||||
<div v-if="errors.password" class="text-danger small mt-1">{{ errors.password }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="passwordConfirm" class="form-label">Şifre Tekrar</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
||||
<input type="password" class="form-control" id="passwordConfirm"
|
||||
v-model="form.passwordConfirm" placeholder="Şifrenizi tekrar girin"
|
||||
required>
|
||||
</div>
|
||||
<div v-if="errors.passwordConfirm" class="text-danger small mt-1">{{
|
||||
errors.passwordConfirm }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Turnstile Component -->
|
||||
<ClientOnly>
|
||||
<div class="mb-4 d-flex justify-content-center">
|
||||
<NuxtTurnstile v-model="turnstileToken" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
|
||||
<button type="submit" class="btn btn-success w-100 py-2" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2" role="status"
|
||||
aria-hidden="true"></span>
|
||||
{{ loading ? 'Kayıt Yapılıyor...' : 'Kayıt Ol' }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { registerSchema, type RegisterInput } from '~~/utils/validations';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'guest-only',
|
||||
auth: { unauthenticatedOnly: true, navigateAuthenticatedTo: '/' }
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const router = useRouter();
|
||||
|
||||
const form = reactive<RegisterInput>({
|
||||
username: '',
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
passwordConfirm: ''
|
||||
});
|
||||
|
||||
const errors = reactive<Partial<Record<keyof RegisterInput, string>>>({});
|
||||
const loading = ref(false);
|
||||
const turnstileToken = ref('');
|
||||
|
||||
const validate = () => {
|
||||
// Zod validasyonu
|
||||
const result = registerSchema.safeParse(form);
|
||||
|
||||
// Clear previous errors
|
||||
Object.keys(errors).forEach(key => delete errors[key as keyof RegisterInput]);
|
||||
|
||||
if (!result.success) {
|
||||
result.error.errors.forEach(err => {
|
||||
if (err.path[0]) {
|
||||
errors[err.path[0] as keyof RegisterInput] = err.message;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleRegister = async () => {
|
||||
if (!validate()) return;
|
||||
|
||||
if (!turnstileToken.value) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Güvenlik Kontrolü',
|
||||
text: 'Lütfen Turnstile güvenlik kontrolünü tamamlayın.',
|
||||
timer: 3000,
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const apiUrl = config.public.NUXT_PUBLIC_API_BASE || 'http://127.0.0.1:8080';
|
||||
|
||||
// Backend API çağrısı
|
||||
const response = await fetch(`${apiUrl}/api/v1/auth/register`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: form.username,
|
||||
first_name: form.first_name,
|
||||
last_name: form.last_name,
|
||||
email: form.email,
|
||||
password: form.password
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Kayıt Başarılı!',
|
||||
text: data.message || 'Lütfen e-posta adresinizi doğrulayın.',
|
||||
confirmButtonText: 'Giriş Yap'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push('/auth/login');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Kayıt Hatası',
|
||||
text: errorData.message || 'Kayıt işlemi sırasında bir hata oluştu.',
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Hata',
|
||||
text: 'Sunucu ile iletişim hatası.',
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.register-area {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.register-form-wrap {
|
||||
border-top: 5px solid #198754;
|
||||
}
|
||||
</style>
|
||||
150
app/pages/auth/resend-verify.vue
Normal file
150
app/pages/auth/resend-verify.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div class="resend-verify-area pt-120 pb-120">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6 col-md-8">
|
||||
<div class="resend-form-wrap shadow-lg p-5 rounded bg-white">
|
||||
<div class="header text-center mb-4">
|
||||
<h2 class="mb-2">Doğrulama E-postası Gönder</h2>
|
||||
<p class="text-muted">
|
||||
E-posta adresinizi girin, doğrulama bağlantısını tekrar gönderelim.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleResend">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">E-posta Adresi</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
|
||||
<input type="email" class="form-control" id="email" v-model="email"
|
||||
placeholder="E-posta adresinizi girin" required>
|
||||
</div>
|
||||
<div v-if="error" class="text-danger small mt-1">{{ error }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Turnstile Component -->
|
||||
<ClientOnly>
|
||||
<div class="mb-4 d-flex justify-content-center">
|
||||
<NuxtTurnstile v-model="turnstileToken" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100 py-2" :disabled="loading">
|
||||
<span v-if="loading" class="spinner-border spinner-border-sm me-2" role="status"
|
||||
aria-hidden="true"></span>
|
||||
{{ loading ? 'Gönderiliyor...' : 'Gönder' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<NuxtLink to="/auth/login" class="text-decoration-none">
|
||||
<i class="fas fa-arrow-left me-1"></i> Giriş sayfasına dön
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'; // Import z directly if not exported from validations, or use from validations if available
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'guest-only',
|
||||
auth: { unauthenticatedOnly: true, navigateAuthenticatedTo: '/' }
|
||||
});
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const email = ref('');
|
||||
const error = ref('');
|
||||
const loading = ref(false);
|
||||
const turnstileToken = ref('');
|
||||
|
||||
const emailSchema = z.string().email({ message: 'Geçerli bir e-posta adresi giriniz' });
|
||||
|
||||
const validate = () => {
|
||||
const result = emailSchema.safeParse(email.value);
|
||||
if (!result.success) {
|
||||
error.value = result.error.errors[0].message;
|
||||
return false;
|
||||
}
|
||||
error.value = '';
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleResend = async () => {
|
||||
if (!validate()) return;
|
||||
|
||||
if (!turnstileToken.value) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Güvenlik Kontrolü',
|
||||
text: 'Lütfen Turnstile güvenlik kontrolünü tamamlayın.',
|
||||
timer: 3000,
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const apiUrl = config.public.NUXT_PUBLIC_API_BASE || 'http://127.0.0.1:8080';
|
||||
|
||||
const response = await fetch(`${apiUrl}/api/v1/auth/resend-verification`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email.value
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Başarılı!',
|
||||
text: 'Doğrulama bağlantısı e-posta adresinize gönderildi.',
|
||||
confirmButtonText: 'Tamam'
|
||||
});
|
||||
email.value = ''; // Reset form
|
||||
turnstileToken.value = ''; // Reset token ideally, but might need manual reset
|
||||
} else {
|
||||
const data = await response.json();
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Hata',
|
||||
text: data.message || data.error || 'İşlem başarısız oldu.',
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Hata',
|
||||
text: 'Sunucu ile iletişim hatası.',
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resend-verify-area {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.resend-form-wrap {
|
||||
border-top: 5px solid #0d6efd;
|
||||
}
|
||||
</style>
|
||||
114
app/pages/auth/verify.vue
Normal file
114
app/pages/auth/verify.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="verify-area pt-120 pb-120">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6 col-md-8">
|
||||
<div class="verify-content text-center shadow-lg p-5 rounded bg-white">
|
||||
|
||||
<div v-if="loading" class="text-center py-5">
|
||||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
<p class="mt-3 text-muted fs-5">E-posta adresiniz doğrulanıyor...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="success">
|
||||
<div class="mb-4">
|
||||
<div class="success-icon d-inline-flex align-items-center justify-content-center bg-success text-white rounded-circle"
|
||||
style="width: 80px; height: 80px;">
|
||||
<i class="fas fa-check fa-3x"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="mb-3 text-success">Doğrulama Başarılı!</h3>
|
||||
<p class="text-muted mb-4 fs-5">Hesabınız başarıyla doğrulandı. Artık giriş yapabilirsiniz.
|
||||
</p>
|
||||
<NuxtLink to="/auth/login" class="btn btn-primary btn-lg w-100">
|
||||
Giriş Yap
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="mb-4">
|
||||
<div class="error-icon d-inline-flex align-items-center justify-content-center bg-danger text-white rounded-circle"
|
||||
style="width: 80px; height: 80px;">
|
||||
<i class="fas fa-times fa-3x"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="mb-3 text-danger">Doğrulama Hatası</h3>
|
||||
<p class="text-muted mb-4 fs-5">{{ displayError }}</p>
|
||||
<NuxtLink to="/auth/login" class="btn btn-outline-primary">
|
||||
Giriş sayfasına dön
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const route = useRoute();
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'guest-only',
|
||||
auth: { unauthenticatedOnly: true, navigateAuthenticatedTo: '/' }
|
||||
});
|
||||
|
||||
const loading = ref(true);
|
||||
const success = ref(false);
|
||||
const errorMessage = ref('');
|
||||
|
||||
const displayError = computed(() => {
|
||||
return errorMessage.value || 'Doğrulama işlemi sırasında bir hata oluştu.';
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
const token = route.query.token as string;
|
||||
|
||||
if (!token) {
|
||||
loading.value = false;
|
||||
errorMessage.value = "Geçersiz doğrulama bağlantısı (token eksik).";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const apiUrl = config.public.NUXT_PUBLIC_API_BASE || 'http://127.0.0.1:8080';
|
||||
|
||||
// Backend API: GET /api/v1/auth/verify-email?token=...
|
||||
const response = await fetch(`${apiUrl}/api/v1/auth/verify-email?token=${token}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
success.value = true;
|
||||
} else {
|
||||
const data = await response.json();
|
||||
errorMessage.value = data.message || 'Token geçersiz veya süresi dolmuş.';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Verify error:", error);
|
||||
errorMessage.value = 'Sunucu ile bağlantı kurulamadı.';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.verify-area {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 80vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.verify-content {
|
||||
border-top: 5px solid #0d6efd;
|
||||
}
|
||||
</style>
|
||||
61
app/pages/index.vue
Normal file
61
app/pages/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Paginate from "~/components/Paginate.vue";
|
||||
import FooterArea from "~/components/FooterArea.vue";
|
||||
import SubsribeStart from "~/components/SubsribeStart.vue";
|
||||
import TagsClouds from "~/components/TagsClouds.vue";
|
||||
import WidgetSidebarImgBox from "~/components/home/WidgetSidebarImgBox.vue";
|
||||
import WidgetRecentPost from "~/components/home/WidgetRecentPost.vue";
|
||||
import WidgetCategories from "~/components/home/WidgetCategories.vue";
|
||||
import WidgetSearch from "~/components/home/WidgetSearch.vue";
|
||||
import BlogPage from "~/components/home/BlogPage.vue";
|
||||
import PagesHeroHeader from "~/components/home/PagesHeroHeader.vue";
|
||||
import MobileHeader from "~/components/MobileHeader.vue";
|
||||
import HeaderSection from "~/components/HeaderSection.vue";
|
||||
import Preloader from "~/components/home/Preloader.vue";
|
||||
import PaginaContainer from "~/components/PaginaContainer.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Preloader/>
|
||||
<!--=====progress START=======-->
|
||||
<PaginaContainer/>
|
||||
<!--=====progress END=======-->
|
||||
<!--=====HEADER START=======-->
|
||||
<HeaderSection/>
|
||||
<!--=====HEADER END=======-->
|
||||
<!--=====Mobile header start=======-->
|
||||
<MobileHeader/>
|
||||
<!--=====Mobile header end=======-->
|
||||
<!--=====pages hero header end=======-->
|
||||
<PagesHeroHeader/>
|
||||
<!--=====pages hero header end=======-->
|
||||
<div class="blog-page sp2">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<BlogPage/>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="widgets lg-ml-15">
|
||||
<WidgetSearch/>
|
||||
<WidgetCategories/>
|
||||
<WidgetSidebarImgBox/>
|
||||
<TagsClouds/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--=====SUBSRIBE START=======-->
|
||||
<SubsribeStart/>
|
||||
<!--=====SUBSRIBE END=======-->
|
||||
<!--=====Footer start=======-->
|
||||
<FooterArea/>
|
||||
<!--=====Footer end=======-->
|
||||
<!--================== sidebar===================== -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
20
app/plugins/01.fetch_setting.ts
Normal file
20
app/plugins/01.fetch_setting.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { Setting } from "~~/types/setting";
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
|
||||
|
||||
const { useSettingStore } = await import('@/stores/setting')
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const apiUrl = config.public.BASE_API_URL;
|
||||
|
||||
try {
|
||||
const data = await $fetch<Setting>(`${apiUrl}/api/v1/setting`)
|
||||
if (data) {
|
||||
settingStore.setSettings(data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch settings:', error)
|
||||
}
|
||||
})
|
||||
20
app/plugins/02.fetch_hero.ts
Normal file
20
app/plugins/02.fetch_hero.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { Hero } from "~~/types/hero";
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
|
||||
|
||||
const { useHeroStore } = await import('@/stores/hero')
|
||||
const heroStore = useHeroStore()
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const apiUrl = config.public.BASE_API_URL;
|
||||
|
||||
try {
|
||||
const data = await $fetch<Hero>(`${apiUrl}/api/v1/hero`)
|
||||
if (data) {
|
||||
heroStore.setHero(data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch settings:', error)
|
||||
}
|
||||
})
|
||||
11
app/plugins/auth-error.ts
Normal file
11
app/plugins/auth-error.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const { data, signOut } = useAuth();
|
||||
|
||||
// Watch for session changes
|
||||
watch(data, async (session) => {
|
||||
if (session?.error === 'RefreshAccessTokenError') {
|
||||
console.warn('Refresh token expired or invalid. Signing out...');
|
||||
await signOut({ callbackUrl: '/auth/login' });
|
||||
}
|
||||
}, { immediate: true });
|
||||
});
|
||||
7
app/plugins/fontawesome.client.ts
Normal file
7
app/plugins/fontawesome.client.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// Converted to a no-op: we register Font Awesome using an SSR-aware plugin `app/plugins/fontawesome.ts`.
|
||||
// Keep this client-only file present (if you relied on it elsewhere) but do not inject the runtime script
|
||||
// to avoid hydration mismatches.
|
||||
export default defineNuxtPlugin(() => {
|
||||
if (process.server) return
|
||||
// No-op on client — FontAwesome is registered via app/plugins/fontawesome.ts
|
||||
})
|
||||
39
app/plugins/fontawesome.ts
Normal file
39
app/plugins/fontawesome.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// SSR-friendly Font Awesome plugin
|
||||
// Registers the Vue component and a small set of icons so server-render and client-render match.
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
// Import a conservative set of icons used in the admin UI
|
||||
import {
|
||||
faHouse,
|
||||
faUsers,
|
||||
faCogs,
|
||||
faNewspaper,
|
||||
faTags,
|
||||
faHashtag,
|
||||
faRightFromBracket,
|
||||
faPlus,
|
||||
faWandMagic,
|
||||
faGaugeHigh,
|
||||
faShieldAlt
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
// Add selected icons to the library
|
||||
library.add(
|
||||
faHouse,
|
||||
faUsers,
|
||||
faCogs,
|
||||
faNewspaper,
|
||||
faTags,
|
||||
faHashtag,
|
||||
faRightFromBracket,
|
||||
faPlus,
|
||||
faWandMagic,
|
||||
faGaugeHigh,
|
||||
faShieldAlt
|
||||
)
|
||||
|
||||
// Globally register component
|
||||
nuxtApp.vueApp.component('FontAwesomeIcon', FontAwesomeIcon)
|
||||
})
|
||||
|
||||
5
app/plugins/sweetalert2.client.ts
Normal file
5
app/plugins/sweetalert2.client.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import Swal from 'sweetalert2'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.provide('swal', Swal)
|
||||
})
|
||||
18
app/stores/hero.ts
Normal file
18
app/stores/hero.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { Hero } from '~~/types/hero';
|
||||
|
||||
interface HeroState {
|
||||
hero: Hero | null;
|
||||
|
||||
}
|
||||
|
||||
export const useHeroStore = defineStore('hero', {
|
||||
state: (): HeroState => ({
|
||||
hero: null,
|
||||
}),
|
||||
actions: {
|
||||
setHero(newHero: Hero | null): void {
|
||||
this.hero = newHero;
|
||||
}
|
||||
}
|
||||
});
|
||||
18
app/stores/setting.ts
Normal file
18
app/stores/setting.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { Setting } from '~~/types/setting';
|
||||
|
||||
interface SettingState {
|
||||
settings: Setting | null;
|
||||
|
||||
}
|
||||
|
||||
export const useSettingStore = defineStore('setting', {
|
||||
state: (): SettingState => ({
|
||||
settings: null,
|
||||
}),
|
||||
actions: {
|
||||
setSettings(newSettings: Setting | null): void {
|
||||
this.settings = newSettings;
|
||||
}
|
||||
}
|
||||
});
|
||||
10
content.config.ts
Normal file
10
content.config.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineContentConfig, defineCollection } from '@nuxt/content'
|
||||
|
||||
export default defineContentConfig({
|
||||
collections: {
|
||||
content: defineCollection({
|
||||
type: 'page',
|
||||
source: '**/*.md'
|
||||
})
|
||||
}
|
||||
})
|
||||
0
content/LoginRegiter.md
Normal file
0
content/LoginRegiter.md
Normal file
654
content/admin_cors.md
Normal file
654
content/admin_cors.md
Normal file
@@ -0,0 +1,654 @@
|
||||
White List
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/cors/whitelist' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/whitelist
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"count": 3,
|
||||
"items": [
|
||||
{
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-15T07:43:24.505+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:24.505+03:00",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://localhost:8080",
|
||||
"description": "default seeded whitelist",
|
||||
"is_active": true,
|
||||
"created_by": "seed"
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T07:43:24.488+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:24.488+03:00",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://localhost:5173",
|
||||
"description": "default seeded whitelist",
|
||||
"is_active": true,
|
||||
"created_by": "seed"
|
||||
},
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T07:43:24.473+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:24.473+03:00",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://localhost:3000",
|
||||
"description": "default seeded whitelist",
|
||||
"is_active": true,
|
||||
"created_by": "seed"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 696
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:36:01 GMT
|
||||
|
||||
whitelist add
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/admin/cors/whitelist' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "test",
|
||||
"is_active": true,
|
||||
"origin": "http://test.com"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/whitelist
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T20:37:14.89782Z",
|
||||
"UpdatedAt": "2026-02-15T20:37:14.89782Z",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://test.com",
|
||||
"description": "test",
|
||||
"is_active": true,
|
||||
"created_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 214
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:37:14 GMT
|
||||
vary: Origin
|
||||
|
||||
whitelist Update
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/admin/cors/whitelist/4' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "Test",
|
||||
"is_active": true,
|
||||
"origin": "http://updatetest.com"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/whitelist/4
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T23:37:14.897+03:00",
|
||||
"UpdatedAt": "2026-02-15T20:38:29.294829Z",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://updatetest.com",
|
||||
"description": "Test",
|
||||
"is_active": true,
|
||||
"created_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 224
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:38:28 GMT
|
||||
vary: Origin
|
||||
|
||||
|
||||
whitelist delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/cors/whitelist/4' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/whitelist/4
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"message": "soft deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:39:22 GMT
|
||||
vary: Origin
|
||||
|
||||
whitelist hard delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/cors/whitelist/4/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/whitelist/4/hard
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"message": "hard deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:40:08 GMT
|
||||
vary: Origin
|
||||
|
||||
|
||||
########################################################################
|
||||
|
||||
Blacklist add
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/admin/cors/blacklist' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"is_active": true,
|
||||
"origin": "http://post.test.com",
|
||||
"reason": "spamer"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/blacklist
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T20:42:27.229052Z",
|
||||
"UpdatedAt": "2026-02-15T20:42:27.229052Z",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://post.test.com",
|
||||
"reason": "spamer",
|
||||
"is_active": true,
|
||||
"created_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 218
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:42:26 GMT
|
||||
vary: Origin
|
||||
|
||||
Blacklist List
|
||||
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/cors/blacklist' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/blacklist
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"items": [
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T23:42:27.229+03:00",
|
||||
"UpdatedAt": "2026-02-15T23:42:27.229+03:00",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://post.test.com",
|
||||
"reason": "spamer",
|
||||
"is_active": true,
|
||||
"created_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 235
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:43:26 GMT
|
||||
|
||||
|
||||
Blacklist Update
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/admin/cors/blacklist/1' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"is_active": true,
|
||||
"origin": "http://update.test.com",
|
||||
"reason": "Sapammer Update"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/blacklist/1
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T23:42:27.229+03:00",
|
||||
"UpdatedAt": "2026-02-15T20:44:35.812266Z",
|
||||
"DeletedAt": null,
|
||||
"origin": "http://update.test.com",
|
||||
"reason": "Sapammer Update",
|
||||
"is_active": true,
|
||||
"created_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 231
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:44:35 GMT
|
||||
vary: Origin
|
||||
|
||||
Blacklist Delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/cors/blacklist/1' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/blacklist/1
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"message": "soft deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:45:14 GMT
|
||||
vary: Origin
|
||||
|
||||
Blacklist Hard Delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/cors/blacklist/1/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/cors/blacklist/1/hard
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"message": "hard deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:45:40 GMT
|
||||
vary: Origin
|
||||
|
||||
Rate Limit List
|
||||
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/rate-limit' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/rate-limit
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"count": 2,
|
||||
"items": [
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T07:43:24.453+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:24.453+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "login",
|
||||
"description": "Login endpoint default rate limit",
|
||||
"max_requests": 10,
|
||||
"window_seconds": 60,
|
||||
"is_active": true,
|
||||
"updated_by": "seed"
|
||||
},
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T07:43:24.439+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:24.439+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "register",
|
||||
"description": "Register endpoint default rate limit",
|
||||
"max_requests": 5,
|
||||
"window_seconds": 60,
|
||||
"is_active": true,
|
||||
"updated_by": "seed"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 534
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:46:22 GMT
|
||||
|
||||
Rate Limit Create
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/admin/rate-limit' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "test için",
|
||||
"is_active": true,
|
||||
"max_requests": 100,
|
||||
"name": "test",
|
||||
"window_seconds": 100
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/rate-limit
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-15T20:47:20.555797Z",
|
||||
"UpdatedAt": "2026-02-15T20:47:20.555797Z",
|
||||
"DeletedAt": null,
|
||||
"name": "test",
|
||||
"description": "test için",
|
||||
"max_requests": 100,
|
||||
"window_seconds": 100,
|
||||
"is_active": true,
|
||||
"updated_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 249
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:47:20 GMT
|
||||
vary: Origin
|
||||
|
||||
Rate Limit Update
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/admin/rate-limit/3' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "update",
|
||||
"is_active": true,
|
||||
"max_requests": 34,
|
||||
"name": "update",
|
||||
"window_seconds": 34
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/rate-limit/3
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"item": {
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-15T23:47:20.555+03:00",
|
||||
"UpdatedAt": "2026-02-15T20:48:22.836239Z",
|
||||
"DeletedAt": null,
|
||||
"name": "update",
|
||||
"description": "update",
|
||||
"max_requests": 34,
|
||||
"window_seconds": 34,
|
||||
"is_active": true,
|
||||
"updated_by": "beyhan@beyhan.dev"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 247
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:48:22 GMT
|
||||
vary: Origin
|
||||
|
||||
|
||||
Rate Limit Delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/rate-limit/3' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/rate-limit/3
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"message": "soft deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:48:56 GMT
|
||||
vary: Origin
|
||||
|
||||
Rate Limit Hard Delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/rate-limit/3/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/rate-limit/3/hard
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"message": "hard deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 33
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 20:49:21 GMT
|
||||
vary: Origin
|
||||
380
content/admin_kategori.md
Normal file
380
content/admin_kategori.md
Normal file
@@ -0,0 +1,380 @@
|
||||
css ler /public/css/ kalsorunde
|
||||
* Bootstrap v5.2.0-beta1 kullanarak yapabilirsin
|
||||
sweetaler2
|
||||
|
||||
sadece soft delete edilmis
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/categories?trashed=only' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/categories?trashed=only
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"ID": 11,
|
||||
"CreatedAt": "2026-02-16T02:27:17.611+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:46:47.319+03:00",
|
||||
"DeletedAt": "2026-02-16T02:56:25.664+03:00",
|
||||
"title": "rftghyujkiiiüüğğççöö",
|
||||
"slug": "rftghyujkiiiuuggccoo",
|
||||
"description": "sfdfsd",
|
||||
"parent_id": 1
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 300
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 10:45:03 GMT
|
||||
|
||||
#############
|
||||
|
||||
admin kategoriler list hepsi
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/categories?trashed=with' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/categories?trashed=with
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-16T02:48:15.651+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:48:15.651+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "sdadasd",
|
||||
"slug": "sdadasd",
|
||||
"description": "asdasdad"
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-16T02:29:37.895+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:40:55.819+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "update",
|
||||
"slug": "update",
|
||||
"description": "update"
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"CreatedAt": "2026-02-16T02:27:17.611+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:46:47.319+03:00",
|
||||
"DeletedAt": "2026-02-16T02:56:25.664+03:00",
|
||||
"title": "rftghyujkiiiüüğğççöö",
|
||||
"slug": "rftghyujkiiiuuggccoo",
|
||||
"description": "sfdfsd",
|
||||
"parent_id": 1
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"CreatedAt": "2026-02-16T02:26:53.621+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:55:27.599+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "34345345",
|
||||
"slug": "34345345",
|
||||
"description": "sfdfsd",
|
||||
"parent_id": 8
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"CreatedAt": "2026-02-15T07:43:42.09+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.09+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Finans",
|
||||
"slug": "finans",
|
||||
"description": "Finans kategorisi seed verisi",
|
||||
"children": [
|
||||
{
|
||||
"ID": 10,
|
||||
"CreatedAt": "2026-02-16T02:26:53.621+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:55:27.599+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "34345345",
|
||||
"slug": "34345345",
|
||||
"description": "sfdfsd",
|
||||
"parent_id": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"CreatedAt": "2026-02-15T07:43:42.07+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.07+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Saglik",
|
||||
"slug": "saglik",
|
||||
"description": "Saglik kategorisi seed verisi"
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"CreatedAt": "2026-02-15T07:43:42.053+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.053+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Spor",
|
||||
"slug": "spor",
|
||||
"description": "Spor kategorisi seed verisi"
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"CreatedAt": "2026-02-15T07:43:42.038+03:00",
|
||||
"UpdatedAt": "2026-02-16T02:48:47.358+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Egitim",
|
||||
"slug": "egitim",
|
||||
"description": "Egitim kategorisi seed verisi",
|
||||
"parent_id": 2
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T07:43:42.023+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.023+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Yasam",
|
||||
"slug": "yasam",
|
||||
"description": "Yasam kategorisi seed verisi"
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-15T07:43:42.005+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.005+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Guncel",
|
||||
"slug": "guncel",
|
||||
"description": "Guncel kategorisi seed verisi"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total": 12
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 2197
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 10:43:49 GMT
|
||||
|
||||
|
||||
|
||||
#################################################
|
||||
|
||||
kategorileri ekleme
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/categories' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMjA1MDM2LCJpYXQiOjE3NzExOTc4MzZ9.p1hHNkMya9mEII-Bkc9TkMtBeWt6k3bp2e-pR5zw_EI' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "sfdfsd",
|
||||
"parent_id": null,
|
||||
"title": "öçşiğüIi"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/categories
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-15T23:29:37.89581Z",
|
||||
"UpdatedAt": "2026-02-15T23:29:37.89581Z",
|
||||
"DeletedAt": null,
|
||||
"title": "öçşiğüIi",
|
||||
"slug": "ocsiguii",
|
||||
"description": "sfdfsd"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 173
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 23:29:37 GMT
|
||||
vary: Origin
|
||||
|
||||
Responses
|
||||
Code Description
|
||||
201
|
||||
|
||||
Created
|
||||
|
||||
{
|
||||
"children": [
|
||||
"string"
|
||||
],
|
||||
"description": "string",
|
||||
"id": 0,
|
||||
"parent_id": 0,
|
||||
"title": "string"
|
||||
}
|
||||
|
||||
400
|
||||
|
||||
#################################################
|
||||
|
||||
kategoriler update
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/categories/12' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMjA1MDM2LCJpYXQiOjE3NzExOTc4MzZ9.p1hHNkMya9mEII-Bkc9TkMtBeWt6k3bp2e-pR5zw_EI' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "update",
|
||||
"parent_id": null,
|
||||
"title": "update"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/categories/12
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-16T02:29:37.895+03:00",
|
||||
"UpdatedAt": "2026-02-15T23:40:55.819633Z",
|
||||
"DeletedAt": null,
|
||||
"title": "update",
|
||||
"slug": "update",
|
||||
"description": "update"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 168
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 23:40:55 GMT
|
||||
vary: Origin
|
||||
|
||||
############################
|
||||
|
||||
kategorileri silme
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/categories/12' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMjA1MDM2LCJpYXQiOjE3NzExOTc4MzZ9.p1hHNkMya9mEII-Bkc9TkMtBeWt6k3bp2e-pR5zw_EI'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/categories/12
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "category deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 30
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 23:42:58 GMT
|
||||
vary: Origin
|
||||
|
||||
####################
|
||||
restore etme
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/admin/categories/11/restore' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0' \
|
||||
-d ''
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/categories/11/restore
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"category_id": 11,
|
||||
"message": "category restored successfully"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 61
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 10:46:40 GMT
|
||||
vary: Origin
|
||||
|
||||
###########
|
||||
hard delete
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/categories/11/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/categories/11/hard
|
||||
475
content/admin_oanel.md
Normal file
475
content/admin_oanel.md
Normal file
@@ -0,0 +1,475 @@
|
||||
css ler /public/css/ kalsorunde
|
||||
* Bootstrap v5.2.0-beta1 kullanarak yapabilirsin
|
||||
settings index.vue de tab li bir yapi ile settings ve hero yu yapalim
|
||||
solda bir sidebar menu ile yapalim
|
||||
Admin Panel Settings
|
||||
settings ve hero da resimleri gondermeden once en boy format kalite ayarlarini yapacaz "sharp": "^0.34.5",
|
||||
bu kutuplahnetyi kulanalim seçmelerde default olarak avif formati olsun
|
||||
# Login olmak#
|
||||
|
||||
is_admin = true olanalar sadece girebilir adminb kismina
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/auth/login' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"email": "beyhan@beyhan.dev",
|
||||
"password": "1923btO**"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/auth/login
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgzOTc5LCJpYXQiOjE3NzExNzY3Nzl9.bVzWG3KHsKkqm11A1uNru5H3g5kZtq30lQxgasCqhBk",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJyZWZyZXNoIiwic3ViIjoiMSIsImV4cCI6MTc3Mzc2ODc3OSwiaWF0IjoxNzcxMTc2Nzc5fQ.wRT0ECN-UsF4ileQHUXl0evePXlaCuG8vb11wWt75Es",
|
||||
"user": {
|
||||
"email": "beyhan@beyhan.dev",
|
||||
"first_name": "Beyhan",
|
||||
"id": 1,
|
||||
"is_admin": true,
|
||||
"last_name": "Oğur",
|
||||
"username": "beyhano"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 765
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:32:58 GMT
|
||||
vary: Origin
|
||||
#####################################
|
||||
#Settings Yeni Ekle#
|
||||
'''
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/setting' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE' \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F 'title=Title' \
|
||||
-F 'meta_title=Meta Title' \
|
||||
-F 'meta_description=Meta Description' \
|
||||
-F 'phone=Phone' \
|
||||
-F 'url=URL' \
|
||||
-F 'email=Email' \
|
||||
-F 'facebook=Facebook' \
|
||||
-F 'x=x' \
|
||||
-F 'instagram=Instagram' \
|
||||
-F 'whatsapp=Whatsapp' \
|
||||
-F 'pinterest=Pinterest' \
|
||||
-F 'linkedin=Linkedin' \
|
||||
-F 'slogan=Slogan' \
|
||||
-F 'address=Address' \
|
||||
-F 'copyright=Copyright' \
|
||||
-F 'map_embed=Map Embed' \
|
||||
-F 'is_active=true' \
|
||||
-F 'w_logo=@845660.png;type=image/png' \
|
||||
-F 'b_logo=@845660.png;type=image/png'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/setting
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T17:24:34.125454Z",
|
||||
"UpdatedAt": "2026-02-15T17:24:34.125454Z",
|
||||
"DeletedAt": null,
|
||||
"title": "Title",
|
||||
"meta_title": "Meta Title",
|
||||
"meta_description": "Meta Description",
|
||||
"phone": "Phone",
|
||||
"url": "URL",
|
||||
"email": "Email",
|
||||
"facebook": "Facebook",
|
||||
"x": "x",
|
||||
"instagram": "Instagram",
|
||||
"whatsapp": "Whatsapp",
|
||||
"pinterest": "Pinterest",
|
||||
"linkedin": "Linkedin",
|
||||
"slogan": "Slogan",
|
||||
"address": "Address",
|
||||
"copyright": "Copyright",
|
||||
"map_embed": "Map Embed",
|
||||
"w_logo": "/uploads/settings/w_1771176274_845660.png",
|
||||
"b_logo": "/uploads/settings/b_1771176274_845660.png",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 564
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:24:33 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Settings Güncelle#
|
||||
'''
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/setting/1' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE' \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F 'title=Title' \
|
||||
-F 'meta_title=Meta Title' \
|
||||
-F 'meta_description=Meta Description' \
|
||||
-F 'phone=Phone' \
|
||||
-F 'url=URL' \
|
||||
-F 'email=Email' \
|
||||
-F 'facebook=Facebook' \
|
||||
-F 'x=x' \
|
||||
-F 'instagram=Instagram' \
|
||||
-F 'whatsapp=Whatsapp' \
|
||||
-F 'pinterest=Pinterest' \
|
||||
-F 'linkedin=Linkedin' \
|
||||
-F 'slogan=Slogan' \
|
||||
-F 'address=Address' \
|
||||
-F 'copyright=Copyright' \
|
||||
-F 'map_embed=Map Embed' \
|
||||
-F 'is_active=true' \
|
||||
-F 'w_logo=@18d11cf76c60f0b453aaea8da0838d3b.png;type=image/png' \
|
||||
-F 'b_logo=@1657955547black-google-icon.png;type=image/png'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/setting/1
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T19:43:23.226+03:00",
|
||||
"UpdatedAt": "2026-02-15T17:27:21.266645Z",
|
||||
"DeletedAt": null,
|
||||
"title": "Title",
|
||||
"meta_title": "Meta Title",
|
||||
"meta_description": "Meta Description",
|
||||
"phone": "Phone",
|
||||
"url": "URL",
|
||||
"email": "Email",
|
||||
"facebook": "Facebook",
|
||||
"x": "x",
|
||||
"instagram": "Instagram",
|
||||
"whatsapp": "Whatsapp",
|
||||
"pinterest": "Pinterest",
|
||||
"linkedin": "Linkedin",
|
||||
"slogan": "Slogan",
|
||||
"address": "Address",
|
||||
"copyright": "Copyright",
|
||||
"map_embed": "Map Embed",
|
||||
"w_logo": "/uploads/settings/w_1771176441_18d11cf76c60f0b453aaea8da0838d3b.png",
|
||||
"b_logo": "/uploads/settings/b_1771176441_1657955547black-google-icon.png",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 613
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:27:20 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Settings Silme#
|
||||
'''
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/setting/1' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/setting/1
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "setting deleted successfully"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 38
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:26:38 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Settings Listeleme#
|
||||
'''
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/setting' \
|
||||
-H 'accept: application/json'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/setting
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T19:43:23.226+03:00",
|
||||
"UpdatedAt": "2026-02-15T20:27:21.266+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Title",
|
||||
"meta_title": "Meta Title",
|
||||
"meta_description": "Meta Description",
|
||||
"phone": "Phone",
|
||||
"url": "URL",
|
||||
"email": "Email",
|
||||
"facebook": "Facebook",
|
||||
"x": "x",
|
||||
"instagram": "Instagram",
|
||||
"whatsapp": "Whatsapp",
|
||||
"pinterest": "Pinterest",
|
||||
"linkedin": "Linkedin",
|
||||
"slogan": "Slogan",
|
||||
"address": "Address",
|
||||
"copyright": "Copyright",
|
||||
"map_embed": "Map Embed",
|
||||
"w_logo": "/uploads/settings/w_1771176441_18d11cf76c60f0b453aaea8da0838d3b.png",
|
||||
"b_logo": "/uploads/settings/b_1771176441_1657955547black-google-icon.png",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 615
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:28:37 GMT
|
||||
'''
|
||||
|
||||
|
||||
|
||||
#####################################
|
||||
admin için Hero ayarlari
|
||||
|
||||
#Hero Yeni Ekle#
|
||||
'''
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/hero' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE' \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F 'title=Title' \
|
||||
-F 'text1=Text1' \
|
||||
-F 'text2=Text2' \
|
||||
-F 'text4=Text4' \
|
||||
-F 'text5=Text5' \
|
||||
-F 'color=Color' \
|
||||
-F 'is_active=true' \
|
||||
-F 'image=@1200x630bb.png;type=image/png'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/hero
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T17:13:52.46361Z",
|
||||
"UpdatedAt": "2026-02-15T17:13:52.46361Z",
|
||||
"DeletedAt": null,
|
||||
"color": "Color",
|
||||
"title": "Title",
|
||||
"text1": "Text1",
|
||||
"text2": "Text2",
|
||||
"text4": "Text4",
|
||||
"text5": "Text5",
|
||||
"image": "/uploads/heroes/1771175632_1200x630bb.png",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 272
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:13:51 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Hero Güncelle#
|
||||
'''
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/hero/2' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE' \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F 'title=Title' \
|
||||
-F 'text1=Text1' \
|
||||
-F 'text2=Text2' \
|
||||
-F 'text4=Text4' \
|
||||
-F 'text5=Text5' \
|
||||
-F 'color=Color' \
|
||||
-F 'is_active=true' \
|
||||
-F 'image=@1632286445-en-sqdgame-main-playgrou-5BVA_cover.jpg;type=image/jpeg'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/hero/2
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T20:13:52.463+03:00",
|
||||
"UpdatedAt": "2026-02-15T17:17:21.182814Z",
|
||||
"DeletedAt": null,
|
||||
"color": "Color",
|
||||
"title": "Title",
|
||||
"text1": "Text1",
|
||||
"text2": "Text2",
|
||||
"text4": "Text4",
|
||||
"text5": "Text5",
|
||||
"image": "/uploads/heroes/1771175841_1632286445-en-sqdgame-main-playgrou-5BVA_cover.jpg",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 312
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:17:21 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Hero Silme#
|
||||
'''
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/hero/1' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTgwODI4LCJpYXQiOjE3NzExNzM2Mjh9.l51p91--l7JcUbBPHwwVjqRgoT7KXFtU-33HLr4YfBE'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/hero/1
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "hero deleted successfully"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 39
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:18:39 GMT
|
||||
vary: Origin
|
||||
'''
|
||||
|
||||
#Hero Listeleme#
|
||||
'''
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/hero' \
|
||||
-H 'accept: application/json'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/hero
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T20:13:52.463+03:00",
|
||||
"UpdatedAt": "2026-02-15T20:17:21.182+03:00",
|
||||
"DeletedAt": null,
|
||||
"color": "Color",
|
||||
"title": "Title",
|
||||
"text1": "Text1",
|
||||
"text2": "Text2",
|
||||
"text4": "Text4",
|
||||
"text5": "Text5",
|
||||
"image": "/uploads/heroes/1771175841_1632286445-en-sqdgame-main-playgrou-5BVA_cover.jpg",
|
||||
"is_active": true
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 314
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 17:20:30 GMT
|
||||
'''
|
||||
|
||||
##############################################################################################
|
||||
1175
content/admin_post.md
Normal file
1175
content/admin_post.md
Normal file
File diff suppressed because it is too large
Load Diff
934
content/admin_tags.md
Normal file
934
content/admin_tags.md
Normal file
@@ -0,0 +1,934 @@
|
||||
css ler /public/css/ kalsorunde
|
||||
* Bootstrap v5.2.0-beta1 kullanarak yapabilirsin
|
||||
|
||||
|
||||
|
||||
tags ekleme
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/tags' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"name": "test4444"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/tags
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-17T09:50:12.778586Z",
|
||||
"UpdatedAt": "2026-02-17T09:50:12.778586Z",
|
||||
"DeletedAt": null,
|
||||
"name": "test4444"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 128
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:50:12 GMT
|
||||
vary: Origi
|
||||
|
||||
#################
|
||||
tags güncelleme
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/tags/13' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"name": "test4444_update"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/tags/13
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-17T12:50:12.778+03:00",
|
||||
"UpdatedAt": "2026-02-17T09:51:54.295883Z",
|
||||
"DeletedAt": null,
|
||||
"name": "test4444_update"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 137
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:51:53 GMT
|
||||
vary: Origin
|
||||
|
||||
#################
|
||||
tags silme
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/tags/13' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/tags/13
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "tag deleted"
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 25
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:55:04 GMT
|
||||
vary: Origin
|
||||
|
||||
#################
|
||||
|
||||
Listele hepsi
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/tags?trashed=with' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/tags?trashed=with
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-17T12:50:12.778+03:00",
|
||||
"UpdatedAt": "2026-02-17T12:51:54.295+03:00",
|
||||
"DeletedAt": "2026-02-17T12:55:04.871+03:00",
|
||||
"name": "test4444_update"
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-15T07:43:42.295+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.295+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "testing",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T07:43:42.673+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.673+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 1",
|
||||
"images": "uploads/posts/post_1_75e8c4.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 1.",
|
||||
"slug": "seed-post-1"
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"CreatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 9",
|
||||
"images": "uploads/posts/post_9_03c3b8.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 9.",
|
||||
"slug": "seed-post-9"
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"CreatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 21",
|
||||
"images": "uploads/posts/post_21_626d54.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 21.",
|
||||
"slug": "seed-post-21"
|
||||
},
|
||||
{
|
||||
"ID": 31,
|
||||
"CreatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 31",
|
||||
"images": "uploads/posts/post_31_7a6f61.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 31.",
|
||||
"slug": "seed-post-31"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"CreatedAt": "2026-02-15T07:43:42.277+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.277+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "security",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T07:43:42.829+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.829+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 2",
|
||||
"images": "uploads/posts/post_2_a15fd6.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 2.",
|
||||
"slug": "seed-post-2"
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"CreatedAt": "2026-02-15T07:43:45.891+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:45.891+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 18",
|
||||
"images": "uploads/posts/post_18_ec88ac.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 18.",
|
||||
"slug": "seed-post-18"
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"CreatedAt": "2026-02-15T07:43:46.25+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.25+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 20",
|
||||
"images": "uploads/posts/post_20_09d967.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 20.",
|
||||
"slug": "seed-post-20"
|
||||
},
|
||||
{
|
||||
"ID": 30,
|
||||
"CreatedAt": "2026-02-15T07:43:48.058+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.058+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 30",
|
||||
"images": "uploads/posts/post_30_d116c0.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 30.",
|
||||
"slug": "seed-post-30"
|
||||
},
|
||||
{
|
||||
"ID": 37,
|
||||
"CreatedAt": "2026-02-15T07:43:49.511+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.511+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 37",
|
||||
"images": "uploads/posts/post_37_573af9.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 37.",
|
||||
"slug": "seed-post-37"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"CreatedAt": "2026-02-15T07:43:42.259+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.259+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "devops",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-15T07:43:42.966+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.966+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 3",
|
||||
"images": "uploads/posts/post_3_291f5f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 3.",
|
||||
"slug": "seed-post-3"
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"CreatedAt": "2026-02-15T07:43:43.624+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.624+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 5",
|
||||
"images": "uploads/posts/post_5_954662.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 5.",
|
||||
"slug": "seed-post-5"
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"CreatedAt": "2026-02-15T07:43:45.377+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:45.377+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 14",
|
||||
"images": "uploads/posts/post_14_c21ae0.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 14.",
|
||||
"slug": "seed-post-14"
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"CreatedAt": "2026-02-15T07:43:45.891+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:45.891+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 18",
|
||||
"images": "uploads/posts/post_18_ec88ac.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 18.",
|
||||
"slug": "seed-post-18"
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"CreatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 22",
|
||||
"images": "uploads/posts/post_22_2aa79a.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 22.",
|
||||
"slug": "seed-post-22"
|
||||
},
|
||||
{
|
||||
"ID": 28,
|
||||
"CreatedAt": "2026-02-15T07:43:47.546+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.546+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 28",
|
||||
"images": "uploads/posts/post_28_a10a99.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 28.",
|
||||
"slug": "seed-post-28"
|
||||
},
|
||||
{
|
||||
"ID": 35,
|
||||
"CreatedAt": "2026-02-15T07:43:49.258+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.258+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 35",
|
||||
"images": "uploads/posts/post_35_30ee16.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 35.",
|
||||
"slug": "seed-post-35"
|
||||
},
|
||||
{
|
||||
"ID": 39,
|
||||
"CreatedAt": "2026-02-15T07:43:49.767+03:00",
|
||||
"UpdatedAt": "2026-02-17T12:28:44.936+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 39",
|
||||
"images": "uploads/posts/post_39_0e773c.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 39.",
|
||||
"slug": "seed-post-39"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"CreatedAt": "2026-02-15T07:43:42.242+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.242+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "cloud",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 9,
|
||||
"CreatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 9",
|
||||
"images": "uploads/posts/post_9_03c3b8.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 9.",
|
||||
"slug": "seed-post-9"
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"CreatedAt": "2026-02-15T07:43:44.653+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.653+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 10",
|
||||
"images": "uploads/posts/post_10_19b004.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 10.",
|
||||
"slug": "seed-post-10"
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-15T07:43:44.905+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.905+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 12",
|
||||
"images": "uploads/posts/post_12_ddfaa3.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 12.",
|
||||
"slug": "seed-post-12"
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"CreatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 21",
|
||||
"images": "uploads/posts/post_21_626d54.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 21.",
|
||||
"slug": "seed-post-21"
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"CreatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 22",
|
||||
"images": "uploads/posts/post_22_2aa79a.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 22.",
|
||||
"slug": "seed-post-22"
|
||||
},
|
||||
{
|
||||
"ID": 26,
|
||||
"CreatedAt": "2026-02-15T07:43:47.278+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.278+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 26",
|
||||
"images": "uploads/posts/post_26_ce05c4.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 26.",
|
||||
"slug": "seed-post-26"
|
||||
},
|
||||
{
|
||||
"ID": 29,
|
||||
"CreatedAt": "2026-02-15T07:43:47.674+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.674+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 29",
|
||||
"images": "uploads/posts/post_29_5a1d1f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 29.",
|
||||
"slug": "seed-post-29"
|
||||
},
|
||||
{
|
||||
"ID": 30,
|
||||
"CreatedAt": "2026-02-15T07:43:48.058+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.058+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 30",
|
||||
"images": "uploads/posts/post_30_d116c0.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 30.",
|
||||
"slug": "seed-post-30"
|
||||
},
|
||||
{
|
||||
"ID": 31,
|
||||
"CreatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 31",
|
||||
"images": "uploads/posts/post_31_7a6f61.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 31.",
|
||||
"slug": "seed-post-31"
|
||||
},
|
||||
{
|
||||
"ID": 34,
|
||||
"CreatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 34",
|
||||
"images": "uploads/posts/post_34_6f7963.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 34.",
|
||||
"slug": "seed-post-34"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"CreatedAt": "2026-02-15T07:43:42.227+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.227+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "docker",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 4",
|
||||
"images": "uploads/posts/post_4_3d6f3f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 4.",
|
||||
"slug": "seed-post-4"
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"CreatedAt": "2026-02-15T07:43:43.759+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.759+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 6",
|
||||
"images": "uploads/posts/post_6_ad3af8.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 6.",
|
||||
"slug": "seed-post-6"
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"CreatedAt": "2026-02-15T07:43:44.393+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.393+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 8",
|
||||
"images": "uploads/posts/post_8_80cbb5.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 8.",
|
||||
"slug": "seed-post-8"
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"CreatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.525+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 9",
|
||||
"images": "uploads/posts/post_9_03c3b8.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 9.",
|
||||
"slug": "seed-post-9"
|
||||
},
|
||||
{
|
||||
"ID": 32,
|
||||
"CreatedAt": "2026-02-15T07:43:48.329+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.329+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 32",
|
||||
"images": "uploads/posts/post_32_214285.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 32.",
|
||||
"slug": "seed-post-32"
|
||||
},
|
||||
{
|
||||
"ID": 39,
|
||||
"CreatedAt": "2026-02-15T07:43:49.767+03:00",
|
||||
"UpdatedAt": "2026-02-17T12:28:44.936+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 39",
|
||||
"images": "uploads/posts/post_39_0e773c.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 39.",
|
||||
"slug": "seed-post-39"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"CreatedAt": "2026-02-15T07:43:42.212+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.212+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "api",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 5,
|
||||
"CreatedAt": "2026-02-15T07:43:43.624+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.624+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 5",
|
||||
"images": "uploads/posts/post_5_954662.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 5.",
|
||||
"slug": "seed-post-5"
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"CreatedAt": "2026-02-15T07:43:44.243+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.243+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 7",
|
||||
"images": "uploads/posts/post_7_d973fd.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 7.",
|
||||
"slug": "seed-post-7"
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"CreatedAt": "2026-02-15T07:43:45.629+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:45.629+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 16",
|
||||
"images": "uploads/posts/post_16_6a0c58.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 16.",
|
||||
"slug": "seed-post-16"
|
||||
},
|
||||
{
|
||||
"ID": 27,
|
||||
"CreatedAt": "2026-02-15T07:43:47.412+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.412+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 27",
|
||||
"images": "uploads/posts/post_27_c75542.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 27.",
|
||||
"slug": "seed-post-27"
|
||||
},
|
||||
{
|
||||
"ID": 29,
|
||||
"CreatedAt": "2026-02-15T07:43:47.674+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.674+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 29",
|
||||
"images": "uploads/posts/post_29_5a1d1f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 29.",
|
||||
"slug": "seed-post-29"
|
||||
},
|
||||
{
|
||||
"ID": 31,
|
||||
"CreatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:48.197+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 31",
|
||||
"images": "uploads/posts/post_31_7a6f61.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 31.",
|
||||
"slug": "seed-post-31"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"CreatedAt": "2026-02-15T07:43:42.192+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.192+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "jwt",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-15T07:43:45.044+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:45.044+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 13",
|
||||
"images": "uploads/posts/post_13_b37f04.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 13.",
|
||||
"slug": "seed-post-13"
|
||||
},
|
||||
{
|
||||
"ID": 19,
|
||||
"CreatedAt": "2026-02-15T07:43:46.017+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.017+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 19",
|
||||
"images": "uploads/posts/post_19_25715c.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 19.",
|
||||
"slug": "seed-post-19"
|
||||
},
|
||||
{
|
||||
"ID": 24,
|
||||
"CreatedAt": "2026-02-15T07:43:46.876+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.876+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 24",
|
||||
"images": "uploads/posts/post_24_97be20.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 24.",
|
||||
"slug": "seed-post-24"
|
||||
},
|
||||
{
|
||||
"ID": 34,
|
||||
"CreatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 34",
|
||||
"images": "uploads/posts/post_34_6f7963.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 34.",
|
||||
"slug": "seed-post-34"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"CreatedAt": "2026-02-15T07:43:42.176+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.176+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "redis",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-15T07:43:42.829+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.829+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 2",
|
||||
"images": "uploads/posts/post_2_a15fd6.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 2.",
|
||||
"slug": "seed-post-2"
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 4",
|
||||
"images": "uploads/posts/post_4_3d6f3f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 4.",
|
||||
"slug": "seed-post-4"
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"CreatedAt": "2026-02-15T07:43:44.905+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.905+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 12",
|
||||
"images": "uploads/posts/post_12_ddfaa3.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 12.",
|
||||
"slug": "seed-post-12"
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"CreatedAt": "2026-02-15T07:43:46.25+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.25+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 20",
|
||||
"images": "uploads/posts/post_20_09d967.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 20.",
|
||||
"slug": "seed-post-20"
|
||||
},
|
||||
{
|
||||
"ID": 23,
|
||||
"CreatedAt": "2026-02-15T07:43:46.742+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.742+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 23",
|
||||
"images": "uploads/posts/post_23_4ff46d.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 23.",
|
||||
"slug": "seed-post-23"
|
||||
},
|
||||
{
|
||||
"ID": 34,
|
||||
"CreatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.078+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 34",
|
||||
"images": "uploads/posts/post_34_6f7963.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 34.",
|
||||
"slug": "seed-post-34"
|
||||
},
|
||||
{
|
||||
"ID": 35,
|
||||
"CreatedAt": "2026-02-15T07:43:49.258+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:49.258+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 35",
|
||||
"images": "uploads/posts/post_35_30ee16.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 35.",
|
||||
"slug": "seed-post-35"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T07:43:42.16+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.16+03:00",
|
||||
"DeletedAt": null,
|
||||
"name": "mysql",
|
||||
"posts": [
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T07:43:42.673+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:42.673+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 1",
|
||||
"images": "uploads/posts/post_1_75e8c4.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 1.",
|
||||
"slug": "seed-post-1"
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"CreatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:43.484+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 4",
|
||||
"images": "uploads/posts/post_4_3d6f3f.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 4.",
|
||||
"slug": "seed-post-4"
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"CreatedAt": "2026-02-15T07:43:44.393+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:44.393+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 8",
|
||||
"images": "uploads/posts/post_8_80cbb5.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 8.",
|
||||
"slug": "seed-post-8"
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"CreatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.483+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 21",
|
||||
"images": "uploads/posts/post_21_626d54.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 21.",
|
||||
"slug": "seed-post-21"
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"CreatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.611+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 22",
|
||||
"images": "uploads/posts/post_22_2aa79a.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 22.",
|
||||
"slug": "seed-post-22"
|
||||
},
|
||||
{
|
||||
"ID": 23,
|
||||
"CreatedAt": "2026-02-15T07:43:46.742+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:46.742+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 23",
|
||||
"images": "uploads/posts/post_23_4ff46d.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 23.",
|
||||
"slug": "seed-post-23"
|
||||
},
|
||||
{
|
||||
"ID": 28,
|
||||
"CreatedAt": "2026-02-15T07:43:47.546+03:00",
|
||||
"UpdatedAt": "2026-02-15T07:43:47.546+03:00",
|
||||
"DeletedAt": null,
|
||||
"title": "Seed Post 28",
|
||||
"images": "uploads/posts/post_28_a10a99.jpg",
|
||||
"content": "Bu bir test icerigidir. Gonderi numarasi 28.",
|
||||
"slug": "seed-post-28"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total": 13
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 16263
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:56:17 GMT
|
||||
|
||||
##############
|
||||
|
||||
listele sadece sotf delete
|
||||
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/admin/tags?trashed=only' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/tags?trashed=only
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"ID": 13,
|
||||
"CreatedAt": "2026-02-17T12:50:12.778+03:00",
|
||||
"UpdatedAt": "2026-02-17T12:51:54.295+03:00",
|
||||
"DeletedAt": "2026-02-17T12:55:04.871+03:00",
|
||||
"name": "test4444_update"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 219
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:57:29 GMT
|
||||
|
||||
Responses
|
||||
|
||||
######
|
||||
|
||||
hard delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/admin/tags/13/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/tags/13/hard
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "tag permanently deleted",
|
||||
"tag_id": 13
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 49
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:58:06 GMT
|
||||
vary: Origin
|
||||
|
||||
Responses
|
||||
|
||||
####################
|
||||
|
||||
restore
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/admin/tags/14/restore' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMzI1MjM0LCJpYXQiOjE3NzEzMTgwMzR9.PlL8aXxN-6U6yZE1nNQJ_sTdnzwni12p_JxoB1RRfy0' \
|
||||
-d ''
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/admin/tags/14/restore
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "tag restored successfully",
|
||||
"tag_id": 14
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 51
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Tue,17 Feb 2026 09:59:31 GMT
|
||||
vary: Origin
|
||||
|
||||
Responses
|
||||
Code Description
|
||||
305
content/admin_users.md
Normal file
305
content/admin_users.md
Normal file
@@ -0,0 +1,305 @@
|
||||
admin users List
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/users/list' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/list
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"users": [
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T19:38:23.59+03:00",
|
||||
"UpdatedAt": "2026-02-15T19:38:23.59+03:00",
|
||||
"DeletedAt": null,
|
||||
"username": "beyhano",
|
||||
"email": "beyhan@beyhan.dev",
|
||||
"email_verified": true,
|
||||
"email_verified_at": "2026-02-18T19:39:41+03:00",
|
||||
"is_admin": true,
|
||||
"profiles": [
|
||||
{
|
||||
"ID": 1,
|
||||
"CreatedAt": "2026-02-15T19:38:23.602+03:00",
|
||||
"UpdatedAt": "2026-02-15T19:38:23.602+03:00",
|
||||
"DeletedAt": null,
|
||||
"user_id": 1,
|
||||
"first_name": "Beyhan",
|
||||
"last_name": "Oğur"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 449
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 21:11:44 GMT
|
||||
|
||||
user add
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/auth/register' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"email": "test@test.com",
|
||||
"first_name": "test",
|
||||
"last_name": "tset",
|
||||
"password": "password",
|
||||
"username": "testuser"
|
||||
}'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/auth/register
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
201
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "registration successful, please verify your email before login",
|
||||
"user": {
|
||||
"email": "test@test.com",
|
||||
"email_verified": false,
|
||||
"first_name": "test",
|
||||
"id": 2,
|
||||
"is_admin": false,
|
||||
"last_name": "tset",
|
||||
"username": "testuser"
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 217
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 21:14:11 GMT
|
||||
vary: Origin
|
||||
|
||||
user soft delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/users/2' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/2
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "user soft-deleted successfully",
|
||||
"user_id": 2
|
||||
}
|
||||
|
||||
user soft delete list
|
||||
|
||||
curl -X 'GET' \
|
||||
'http://localhost:8080/api/v1/users/list/deleted' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/list/deleted
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"users": [
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-16T00:14:11.53+03:00",
|
||||
"UpdatedAt": "2026-02-16T00:14:11.53+03:00",
|
||||
"DeletedAt": "2026-02-16T00:15:34.342+03:00",
|
||||
"username": "testuser",
|
||||
"email": "test@test.com",
|
||||
"email_verified": false,
|
||||
"is_admin": false,
|
||||
"profiles": [
|
||||
{
|
||||
"ID": 2,
|
||||
"CreatedAt": "2026-02-16T00:14:11.546+03:00",
|
||||
"UpdatedAt": "2026-02-16T00:14:11.546+03:00",
|
||||
"DeletedAt": null,
|
||||
"user_id": 2,
|
||||
"first_name": "test",
|
||||
"last_name": "tset"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
content-length: 424
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 21:16:16 GMT
|
||||
|
||||
soft delete user restore
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/api/v1/users/2/restore' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-d ''
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/2/restore
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "user restored successfully",
|
||||
"user_id": 2
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 52
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 21:17:10 GMT
|
||||
vary: Origin
|
||||
|
||||
user hard delete
|
||||
|
||||
curl -X 'DELETE' \
|
||||
'http://localhost:8080/api/v1/users/2/hard' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/2/hard
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "user permanently deleted",
|
||||
"user_id": 2
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 50
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 21:18:01 GMT
|
||||
vary: Origin
|
||||
|
||||
user update
|
||||
|
||||
|
||||
curl -X 'PUT' \
|
||||
'http://localhost:8080/api/v1/users/3' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJlbWFpbCI6ImJleWhhbkBiZXloYW4uZGV2IiwiaXNfYWRtaW4iOnRydWUsImZpcnN0X25hbWUiOiJCZXloYW4iLCJsYXN0X25hbWUiOiJPxJ91ciIsInRva2VuX3R5cGUiOiJhY2Nlc3MiLCJzdWIiOiIxIiwiZXhwIjoxNzcxMTk0OTI4LCJpYXQiOjE3NzExODc3Mjh9.E6Kd65yQoIysJEDoHA-pVqLi4JvG4FBUeRdv8RiVh4E' \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F 'username=Username' \
|
||||
-F 'email=ewrwerwrwer@fgddfg.com' \
|
||||
-F 'is_admin=false' \
|
||||
-F 'password=12345678' \
|
||||
-F 'first_name=First Name' \
|
||||
-F 'last_name=Last Name' \
|
||||
-F 'email_verified=true' \
|
||||
-F 'avatar=@1632286445-en-sqdgame-main-playgrou-5BVA_cover.jpg;type=image/jpeg'
|
||||
|
||||
Request URL
|
||||
|
||||
http://localhost:8080/api/v1/users/3
|
||||
|
||||
Server response
|
||||
Code Details
|
||||
200
|
||||
Response body
|
||||
Download
|
||||
|
||||
{
|
||||
"message": "user updated",
|
||||
"user": {
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-16T00:23:49.301+03:00",
|
||||
"UpdatedAt": "2026-02-16T01:05:17.776+03:00",
|
||||
"DeletedAt": null,
|
||||
"username": "Username",
|
||||
"email": "ewrwerwrwer@fgddfg.com",
|
||||
"email_verified": true,
|
||||
"email_verified_at": "2026-02-16T01:05:17.698+03:00",
|
||||
"is_admin": false,
|
||||
"profiles": [
|
||||
{
|
||||
"ID": 3,
|
||||
"CreatedAt": "2026-02-16T00:23:49.315+03:00",
|
||||
"UpdatedAt": "2026-02-16T01:05:17.808+03:00",
|
||||
"DeletedAt": null,
|
||||
"user_id": 3,
|
||||
"avatar_url": "/uploads/avatars/1771193117_1632286445-en-sqdgame-main-playgrou-5BVA_cover.jpg",
|
||||
"first_name": "First Name",
|
||||
"last_name": "Last Name"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Response headers
|
||||
|
||||
access-control-allow-credentials: true
|
||||
access-control-allow-headers: Authorization,Content-Type,Accept,Origin,X-Requested-With
|
||||
access-control-allow-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
access-control-allow-origin: http://localhost:8080
|
||||
access-control-max-age: 600
|
||||
content-length: 576
|
||||
content-type: application/json; charset=utf-8
|
||||
date: Sun,15 Feb 2026 22:05:17 GMT
|
||||
vary: Origin
|
||||
1
content/index.md
Normal file
1
content/index.md
Normal file
@@ -0,0 +1 @@
|
||||
## index MD
|
||||
6
eslint.config.mjs
Normal file
6
eslint.config.mjs
Normal file
@@ -0,0 +1,6 @@
|
||||
// @ts-check
|
||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||
|
||||
export default withNuxt(
|
||||
// Your custom configs here
|
||||
)
|
||||
111
nuxt.config.ts
Normal file
111
nuxt.config.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
srcDir: 'app',
|
||||
devtools: { enabled: true },
|
||||
auth: {
|
||||
// Full auth endpoint URL (origin + /api/auth). This prevents /session recursion.
|
||||
// Prefer setting AUTH_ORIGIN in your environment (e.g. https://example.com)
|
||||
baseURL: `${(
|
||||
process.env.AUTH_ORIGIN ||
|
||||
process.env.BASE_SITE_URL ||
|
||||
`http://localhost:${process.env.PORT || 3000}`
|
||||
).replace(/\/$/, '')}/api/auth`,
|
||||
},
|
||||
turnstile: {
|
||||
siteKey: process.env.CLOUD_FLARE_SITE_KEY,
|
||||
},
|
||||
runtimeConfig: {
|
||||
//private (server-side only - güvenli)
|
||||
turnstile: {
|
||||
// This can be overridden at runtime via the NUXT_TURNSTILE_SECRET_KEY
|
||||
// environment variable.
|
||||
secretKey: process.env.CLOUD_FLARE_SECRET,
|
||||
},
|
||||
yourOrigin: "",
|
||||
apiSecret: "",
|
||||
authOrigin: process.env.AUTH_ORIGIN,
|
||||
jwtSecret: process.env.JWT_SECRET,
|
||||
googleToken: process.env.NUXT_GOOGLE_TOKEN,
|
||||
authSecret: process.env.NUXT_AUTH_SECRET,
|
||||
githubClientId: process.env.GITHUB_CLIENT_ID,
|
||||
githubClientSecret: process.env.GITHUB_CLIENT_SECRET,
|
||||
googleClientId: process.env.GOOGLE_CLIENT_ID,
|
||||
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
public: {
|
||||
//public (client-side accessible)
|
||||
BASE_API_URL: process.env.NUXT_PUBLIC_API_BASE,
|
||||
BASE_SITE_URL: process.env.NUXT_PUBLIC_API_BASE,
|
||||
yourOrigin: "",
|
||||
apiBase: "",
|
||||
},
|
||||
},
|
||||
modules: [
|
||||
//'@nuxt/content',
|
||||
'@nuxt/a11y',
|
||||
'@nuxt/eslint',
|
||||
'@nuxt/fonts',
|
||||
'@nuxt/hints',
|
||||
'@nuxt/icon',
|
||||
'@nuxt/image',
|
||||
'@nuxt/scripts',
|
||||
"@sidebase/nuxt-auth",
|
||||
"@pinia/nuxt",
|
||||
'@nuxtjs/turnstile',
|
||||
],
|
||||
app: {
|
||||
head: {
|
||||
title: 'Avigo Multipurpose Theme',
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
|
||||
],
|
||||
link: [
|
||||
{ rel: 'stylesheet', href: '/assets/css/bootstrap.min.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/font-awesome-pro.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/magnific-popup.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/owl.carousel.min.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/slick-slider.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/meanmenu.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/typography.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/preloader.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/mobile-menu.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/header.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/footer.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/aos.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/fonts.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/blog-page.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/nice-select.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/modal-video.min.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/responsive.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/comon.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/avigo-unit.css' },
|
||||
{ rel: 'stylesheet', href: '/assets/css/avigo-core.css' },
|
||||
{ rel: 'stylesheet', href: '/style.css' }
|
||||
],
|
||||
script: [
|
||||
{ src: '/assets/js/jquery-3-6-0.min.js', defer: true },
|
||||
{ src: '/assets/js/bootstrap.min.js', defer: true },
|
||||
// fontawesome will be loaded client-side via a plugin to avoid SSR hydration mismatches
|
||||
{ src: '/assets/js/owl.carousel.min.js', defer: true },
|
||||
{ src: 'https://unpkg.com/aos@next/dist/aos.js', defer: true, crossorigin: 'anonymous' },
|
||||
{ src: '/assets/js/jquery.magnific-popup.min.js', defer: true },
|
||||
{ src: 'https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js', defer: true, crossorigin: 'anonymous' },
|
||||
{ src: 'https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js', defer: true, integrity: 'sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3', crossorigin: 'anonymous' },
|
||||
{ src: '/assets/js/slick-slider.js', defer: true },
|
||||
{ src: '/assets/js/mobile-menu.js', defer: true },
|
||||
{ src: '/assets/js/tilt.jquery.js', defer: true },
|
||||
{ src: '/assets/js/jquery.lineProgressbar.js', defer: true },
|
||||
{ src: '/assets/js/jquery.nice-select.js', defer: true },
|
||||
{ src: '/assets/js/mobile-meanmenu.js', defer: true },
|
||||
{ src: '/assets/js/modal-video.min.js', defer: true },
|
||||
{ src: '/assets/js/main.js', defer: true },
|
||||
]
|
||||
}
|
||||
},
|
||||
vite: {
|
||||
build: {
|
||||
sourcemap: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
44
package.json
Normal file
44
package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "dj_nuxt",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/a11y": "^1.0.0-alpha.1",
|
||||
"@nuxt/content": "^3.11.2",
|
||||
"@nuxt/eslint": "^1.15.1",
|
||||
"@nuxt/fonts": "^0.13.0",
|
||||
"@nuxt/hints": "^1.0.0-alpha.6",
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"@nuxt/image": "^2.0.0",
|
||||
"@nuxt/scripts": "^0.13.2",
|
||||
"@nuxtjs/turnstile": "^1.1.1",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@sidebase/nuxt-auth": "^1.2.0",
|
||||
"@unhead/vue": "^2.1.4",
|
||||
"better-sqlite3": "^12.6.2",
|
||||
"next-auth": "~4.21.1",
|
||||
"nuxt": "^4.3.1",
|
||||
"pinia": "^3.0.4",
|
||||
"sharp": "^0.34.5",
|
||||
"sweetalert2": "^11.26.18",
|
||||
"typescript": "^5.9.3",
|
||||
"vue": "^3.5.28",
|
||||
"vue-router": "^4.6.4",
|
||||
"vue-tsc": "^3.2.4",
|
||||
"zod": "^4.3.6",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.0",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.0-4",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.33",
|
||||
"@types/node": "^25.2.3"
|
||||
}
|
||||
}
|
||||
1
public/assets/css/aos.css
Normal file
1
public/assets/css/aos.css
Normal file
File diff suppressed because one or more lines are too long
5318
public/assets/css/avigo-core.css
Normal file
5318
public/assets/css/avigo-core.css
Normal file
File diff suppressed because it is too large
Load Diff
1131
public/assets/css/avigo-unit.css
Normal file
1131
public/assets/css/avigo-unit.css
Normal file
File diff suppressed because it is too large
Load Diff
873
public/assets/css/blog-page.css
Normal file
873
public/assets/css/blog-page.css
Normal file
@@ -0,0 +1,873 @@
|
||||
.breadcrumb-area{
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
/*Pagination*/
|
||||
.theme-pagination ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.theme-pagination li{
|
||||
display: inline-block;
|
||||
}
|
||||
.theme-pagination li a {
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
text-align: center;
|
||||
line-height: 55px;
|
||||
border: 1px solid #E1E3E8;
|
||||
border-radius: 8px;
|
||||
margin: 0 4px;
|
||||
transition: all 0.3s;
|
||||
display: block;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.theme-pagination li a:hover, .theme-pagination li a.active {
|
||||
background: #7977C6;
|
||||
transition: all 0.3s;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/*Common Widget*/
|
||||
.single-widget {
|
||||
padding: 32px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 0px 48px rgba(0, 0, 0, 0.09);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.single-widget ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.single-widget li a {
|
||||
background: transparent;
|
||||
border-radius: 7px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
/* display: inline-block; */
|
||||
align-items: center;
|
||||
color: #161540;
|
||||
justify-content: space-between;
|
||||
padding: 17px 20px;
|
||||
transition: all 0.3s;
|
||||
background: #F6F7FA;
|
||||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
transition: all.4s;
|
||||
}
|
||||
.single-widget li a:hover {
|
||||
background-color: #006fff;
|
||||
color: #fff;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.single-widget li a span {
|
||||
transform: rotate(90deg);
|
||||
transition: all.3s;
|
||||
}
|
||||
.single-widget li:hover span {
|
||||
transform: rotate(0);
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.single-widget h3 {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
color: #202C4A;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding-left: 10px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* .single-widget h3:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background: #7977C6;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
} */
|
||||
|
||||
.widgets {
|
||||
position: sticky;
|
||||
top: 74px;
|
||||
}
|
||||
|
||||
|
||||
/*Search widget*/
|
||||
.search-form-widget form{
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-radius: 7px;
|
||||
overflow: hidden;
|
||||
background:#fff;
|
||||
border: none;
|
||||
}
|
||||
.search-form-widget form input{
|
||||
width: 90%;
|
||||
padding: 14px;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
}
|
||||
.search-form-widget form input::placeholder{
|
||||
color: #000
|
||||
}
|
||||
.search-form-widget form input:focus{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button.search-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 10%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*recent post */
|
||||
|
||||
.recent-post {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.recent-post {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
|
||||
.recent-img img {
|
||||
object-fit: cover;
|
||||
height: 70px;
|
||||
width: 100px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.recent-post-content a {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #202C4A;
|
||||
}
|
||||
|
||||
.blog-date-time ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.blog-date-time ul li a {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
color: #161540;
|
||||
}
|
||||
|
||||
|
||||
/*Blog posts*/
|
||||
|
||||
|
||||
|
||||
.blog-date-time ul {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.blog-date-time ul li a {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: #161540;
|
||||
}
|
||||
|
||||
.author-bio {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.author-name, .blog-category, .blog-date, .blog-coments {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.author-name a, .blog-category a, .blog-date a, .blog-coments a {
|
||||
color: #202C4A;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.author-name a svg, .blog-category a svg, .blog-date a svg, .blog-coments a svg {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
|
||||
.post-format-video .blog-img {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.post-format-quote {
|
||||
background: #e7e8f4;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.post-format-quote p {font-size: 20px;line-height: 32px;}
|
||||
|
||||
.post-audio iframe{
|
||||
width: 100%;
|
||||
}
|
||||
.video-btn {
|
||||
position: absolute;
|
||||
top: calc(50% - 50px);
|
||||
left: calc(50% - 50px);
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.video-btn a {
|
||||
font-size: 30px;
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: #7977C6;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.video-btn a:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.post-format-gallery .owl-nav button {
|
||||
font-size: 30px;
|
||||
display: block;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: #2F80ED !important;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
color: #ffffff !important;
|
||||
border-radius:15px;
|
||||
position: absolute;
|
||||
top: calc(50% - 35px);
|
||||
left: 10px;
|
||||
z-index: 9;
|
||||
}
|
||||
.post-format-gallery .owl-nav button.owl-next {
|
||||
left: auto;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.blog-date-time {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.single-blog-contents h3 {
|
||||
font-weight: 400;
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
color: #161540;
|
||||
margin: 30px 0 20px;
|
||||
}
|
||||
.single-blog-contents p {
|
||||
margin-bottom: 30px;
|
||||
font-size: 20px;
|
||||
line-height: 34px;
|
||||
color: #5C5B79;
|
||||
}
|
||||
|
||||
.single-blog-quote {
|
||||
background: rgba(242, 57, 54, 0.03);
|
||||
border-radius: 8px;
|
||||
padding: 30px 120px 30px 30px;
|
||||
}
|
||||
.single-blog-quote h4 {
|
||||
font-weight: 400;
|
||||
font-size: 24px;
|
||||
line-height: 34px;
|
||||
color: #161540;
|
||||
}
|
||||
.single-blog-quote a {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
color: #5C5B79;
|
||||
}
|
||||
|
||||
.theme-border {
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #E1E3E8;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.single-blog h3 a {
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
line-height: 34px;
|
||||
color: #161540;
|
||||
margin-bottom: 0;
|
||||
transition: all 0.3s;
|
||||
display: block;
|
||||
}
|
||||
.single-blog p {
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
color: #5C5B79;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.post-blog{
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.post-blog:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.post-format-gallery .owl-nav button {
|
||||
font-size: 30px;
|
||||
display: block;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: #2F80ED !important;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
color: #ffffff !important;
|
||||
border-radius: 7px;
|
||||
position: absolute;
|
||||
top: calc(50% - 35px);
|
||||
left: 10px;
|
||||
z-index: 9;
|
||||
}
|
||||
.post-format-gallery .owl-nav button.owl-next {
|
||||
left: auto;
|
||||
right: 10px;
|
||||
}
|
||||
.theme-btn-14 {
|
||||
background: #7977C6;
|
||||
box-shadow: 0 4px 25px rgba(121, 119, 198, 0.2);
|
||||
border-radius: 7px;
|
||||
font-family: "satoshi";
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
padding: 13px 24px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====blog page all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
|
||||
.coffee-nav ul li a {
|
||||
color: #2F80ED;
|
||||
text-decoration: none;
|
||||
background: rgba(47, 128, 237, 0.2);
|
||||
border-radius: 7px;
|
||||
/* padding: 13px 20px; */
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
transition: all.6s;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
min-height: 50px;
|
||||
min-width: 165px;
|
||||
/* width: 200px; */
|
||||
text-align: start;
|
||||
line-height: 50px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.coffee-nav ul li a:hover,
|
||||
.coffee-nav ul li a.active {
|
||||
background: #2F80ED;
|
||||
box-shadow: 0px 4px 10px rgba(47, 128, 237, 0.2);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.coffee-nav ul {
|
||||
list-style: none;
|
||||
padding: 15px 0 25px 0;
|
||||
justify-content: center;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
.coffee-nav ul li {
|
||||
display: inline-block;
|
||||
margin: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.coffee-nav {
|
||||
background-color: #fff;
|
||||
margin: 0 auto;
|
||||
border-radius: 5px;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.shop-1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul.nav.nav-tabs {
|
||||
background: #F6F7FA;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.faq-massge-box-all {
|
||||
background: #2F80ED;
|
||||
border-radius: 7px;
|
||||
padding: 50px 48px;
|
||||
margin: 0 90px;
|
||||
}
|
||||
|
||||
.massge-single-inputs input {
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid #fff;
|
||||
width: 100%;
|
||||
padding: 17px;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
.massge-single-inputs input::placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
.massge-single-inputs textarea {
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid #fff;
|
||||
width: 100%;
|
||||
padding: 17px;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
.massge-single-inputs textarea::placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.massge-btn a {
|
||||
color: #0072ff;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
padding: 15px 20px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 16px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.massge-button {
|
||||
text-align: end;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.about-slider-box.about-slider-box2 {
|
||||
background-color: #F6F7FA;
|
||||
}
|
||||
|
||||
.accordion-button.accordion-button2.accordion-button3 {
|
||||
background-color: #fff;
|
||||
}
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====blog page all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====blog details all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
.author-bio > div {
|
||||
padding: 0 20px 0 0;
|
||||
}
|
||||
|
||||
p.details-p-hadding {
|
||||
color: #202C4A;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.blog-massge-box {
|
||||
background-color: #202C4A;
|
||||
border-radius: 15px;
|
||||
padding: 32px 24px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.blog-massge-box p {
|
||||
color: #fff;
|
||||
line-height: 30px;
|
||||
font-size: 18px;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.blog-post-img img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.border-details {
|
||||
border: 1px solid #1c243923;
|
||||
}
|
||||
|
||||
.details-tag-list ul li a {
|
||||
padding: 15px 20px;
|
||||
border-radius: 7px;
|
||||
background: rgba(32, 44, 74, 0.1);
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #202C4A;
|
||||
line-height: 16px;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.details-tag-list ul li a:hover {
|
||||
padding: 15px 20px;
|
||||
border-radius: 7px;
|
||||
background: #202C4A;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.details-tag-list ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.blog-details-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.blog-details-tags {
|
||||
padding: 40px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.blog-details-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.blogp-details-icon-list ul li a {
|
||||
background: #2f81ed20;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
color: #202C4A;
|
||||
border-radius: 50%;
|
||||
transition: all.3s;
|
||||
}
|
||||
.blogp-details-icon-list ul li a:hover {
|
||||
color: #fff;
|
||||
background-color: #006fff;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.blogp-details-icon-list ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.commet-single-box {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
padding: 40px 24px;
|
||||
background-color: #F6F7FA;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.single-commet-img {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.replly-btn a {
|
||||
display: inline-block;
|
||||
background-color: #202C4A;
|
||||
padding: 12px 14px;
|
||||
border-radius: 7px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
.replly-btn a:hover {
|
||||
background-color: #006fff;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
.replly-btn {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.contact-input input {
|
||||
width: 49%;
|
||||
padding: 13px;
|
||||
border: none;
|
||||
background-color: #F6F7FA;
|
||||
border-radius: 4px;
|
||||
margin-top: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.contact-input textarea {
|
||||
width: 99%;
|
||||
padding: 13px;
|
||||
border: none;
|
||||
background-color: #F6F7FA;
|
||||
border-radius: 4px;
|
||||
margin-top: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.details-form-btn {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.search-form-widget form {
|
||||
border: none;
|
||||
background: #F3F3F3;
|
||||
}
|
||||
|
||||
.search-form-widget form input {
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
ul.blog-date li {
|
||||
color: #525975;
|
||||
line-height: 16px;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
ul.blog-date li img {
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.recent-img {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.tagcloud a {
|
||||
padding: 16px 20px;
|
||||
background: rgba(32, 44, 74, 0.1);
|
||||
border-radius: 7px;
|
||||
color: #202C4A;
|
||||
}
|
||||
.tagcloud a:hover {
|
||||
background-color: #202C4A;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sidebar-img-box-all {
|
||||
background: #202C4A;
|
||||
box-shadow: 0px 0px 48px rgba(0, 0, 0, 0.09);
|
||||
border-radius: 15px;
|
||||
padding: 32px;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
.sidebar-box-hadding h4 a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.details-side-box-icon ul li a {
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #f6f7fa2b;
|
||||
color: #fff;
|
||||
transition: all.3s;
|
||||
}
|
||||
.details-side-box-icon ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.details-side-box-icon ul li a:hover {
|
||||
background-color: #006fff;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.blog-realeted {
|
||||
margin-top: 120px;
|
||||
}
|
||||
|
||||
.blog-boxs-img img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.blog-page-boxs.blog-page-boxs1 {
|
||||
margin-bottom: 45px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 769px) {
|
||||
.blog-page-boxs.blog-page-boxs1 {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.blog-page-boxs {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 426px) {
|
||||
.blog-details-tags {
|
||||
padding: 40px 0;
|
||||
display: block;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.blog-details-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-details-img img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====blog details all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
|
||||
.video-play-button2 {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
box-sizing: content-box;
|
||||
display: block;
|
||||
width: 32px;
|
||||
height: 44px;
|
||||
/* background: #fa183d; */
|
||||
border-radius: 50%;
|
||||
padding: 18px 20px 18px 28px;
|
||||
}
|
||||
|
||||
.video-play-button2:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
display: block;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #2F80ED;
|
||||
border-radius: 50%;
|
||||
animation: pulse-border 1500ms ease-out infinite;
|
||||
}
|
||||
|
||||
.video-play-button2:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
display: block;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
background: #2F80ED;
|
||||
border-radius: 50%;
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
.video-play-button2:hover:after {
|
||||
background-color: darken(#fa183d, 10%);
|
||||
}
|
||||
|
||||
.video-play-button2 img {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.video-play-button2 span {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 13px solid #fff;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
margin-top: 11px;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
@keyframes pulse-border {
|
||||
0% {
|
||||
transform: translateX(-50%) translateY(-50%) translateZ(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%) translateY(-50%) translateZ(0) scale(1.5);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.space-left-30 {
|
||||
padding-left: 30px;
|
||||
}
|
||||
7
public/assets/css/bootstrap.min.css
vendored
Normal file
7
public/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/assets/css/bootstrap.min.css.map
Normal file
1
public/assets/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
840
public/assets/css/comon.css
Normal file
840
public/assets/css/comon.css
Normal file
@@ -0,0 +1,840 @@
|
||||
/*----- all-button -----*/
|
||||
.button1 button {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
background: #0263e0;
|
||||
line-height: 16px;
|
||||
padding: 20px 30px;
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
font-weight: 700;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 20px 40px rgba(2, 99, 224, 0.15);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.button1 button:hover {
|
||||
transition: all 0.3s;
|
||||
transform: scale(1.01);
|
||||
}
|
||||
.shopes1 {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50px;
|
||||
}
|
||||
.shopes2 {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 50px;
|
||||
}
|
||||
/*----- all-button -----*/
|
||||
|
||||
.hadding2 h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #202c4a;
|
||||
}
|
||||
.hadding2 h1,
|
||||
a h2,
|
||||
a h3,
|
||||
a h4,
|
||||
a h5,
|
||||
a h6 a {
|
||||
color: #202c4a;
|
||||
}
|
||||
|
||||
.hadding2 h4 a {
|
||||
color: #202c4a;
|
||||
}
|
||||
|
||||
.hadding2 p {
|
||||
color: #525975;
|
||||
}
|
||||
|
||||
.hadding2 span.after {
|
||||
position: relative;
|
||||
}
|
||||
.hadding2 span.after::after {
|
||||
content: "";
|
||||
}
|
||||
.img-border15 img {
|
||||
border-radius: 15px;
|
||||
}
|
||||
.img100 img {
|
||||
width: 100%;
|
||||
}
|
||||
a.home2-a {
|
||||
color: #202c4a;
|
||||
}
|
||||
.home2-btn a:hover {
|
||||
color: #fff;
|
||||
transform: scale(1.03);
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.hadding3 h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #09100e;
|
||||
}
|
||||
.hadding3 p.p3 {
|
||||
color: #5e6261;
|
||||
}
|
||||
|
||||
.hadding3 p.p4 {
|
||||
color: #4D4B51;
|
||||
}
|
||||
|
||||
.hadding3 p {
|
||||
color: #747474;
|
||||
}
|
||||
.hadding3 h4 a {
|
||||
color: #09100e;
|
||||
}
|
||||
.hadding3 span {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
img.img-border {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.hadding4 h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #030406;
|
||||
}
|
||||
|
||||
.hadding4 h1 {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
p.hadding4-p1 p {
|
||||
color: rgba(3, 4, 6, 0.7);
|
||||
}
|
||||
p.hadding4-p2 p {
|
||||
color: #4f4f51;
|
||||
}
|
||||
.hadding4 h4 a {
|
||||
color: #030406;
|
||||
}
|
||||
|
||||
.hadding5 span.after {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.hadding5 h1 span.after::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 16px;
|
||||
z-index: -2;
|
||||
background-image: url(../img/shapes/hadding5-span.svg);
|
||||
}
|
||||
.bg5 {
|
||||
|
||||
}
|
||||
|
||||
/*------------------------------------------
|
||||
------------ all buttons--------------------
|
||||
-------------------------------- */
|
||||
|
||||
.home4-button a {
|
||||
display: inline-block;
|
||||
padding: 16px 25px;
|
||||
color: #fff;
|
||||
background-color: #006fff;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.home4-button a:nth {
|
||||
margin-left: 10px;
|
||||
}
|
||||
a.home4-btn2 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.home4-button a:hover::after {
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
transition: all.4s;
|
||||
}
|
||||
.home4-button a:hover {
|
||||
background: #fff;
|
||||
transition: all.4s;
|
||||
color: #030406;
|
||||
}
|
||||
a.home4-btn-f {
|
||||
position: relative;
|
||||
}
|
||||
a.home4-btn-f::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #0072ff;
|
||||
z-index: -2;
|
||||
border-radius: 5px;
|
||||
transition: all.4s;
|
||||
}
|
||||
a.home4-btn-f:hover::after {
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
transition: all.4s;
|
||||
}
|
||||
a.cta-btn4 {
|
||||
background: none;
|
||||
}
|
||||
a.cta-btn4:hover {
|
||||
background: none;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.home4-btn-plan {
|
||||
position: relative;
|
||||
}
|
||||
a.home4-btn-plan::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #030406;
|
||||
z-index: -2;
|
||||
border-radius: 5px;
|
||||
transition: all.4s;
|
||||
}
|
||||
a.home4-btn-plan:hover::after {
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
.home4-button.home4-pricing-btn a {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.home4-pricing-main-img {
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.home2-pricing-box::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
#030406;
|
||||
border-radius: 10px;
|
||||
z-index: -5;
|
||||
transition: all.3s;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.home2-pricing-box:hover::before {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: all.3s;
|
||||
top: 10px;
|
||||
left: 10px;;
|
||||
}
|
||||
|
||||
.home2-pricing-box.active::before {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: all.3s;
|
||||
top: 10px;
|
||||
left: 10px;;
|
||||
}
|
||||
|
||||
.home2-pricing-box:hover {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.button5 a {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #24BA96;
|
||||
line-height: 16px;
|
||||
color: #fff;
|
||||
padding: 16px 24px;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.button5 a:hover {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #fff;
|
||||
line-height: 16px;
|
||||
color: #24BA96;
|
||||
padding: 16px 24px;
|
||||
border-radius: 4px;
|
||||
transition: all.3s;
|
||||
box-shadow: 4px 4px 48px rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
|
||||
.button5 a:hover svg {
|
||||
color: #Fff;
|
||||
}
|
||||
.button5 a:hover span {
|
||||
background-color: #24BA96;
|
||||
}
|
||||
|
||||
.button5 a svg {
|
||||
color: #24BA96;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.button5 a span {
|
||||
background-color: #fff;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
transform: rotate(-45deg);
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.button5-btn2 a:hover {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #24BA96;
|
||||
line-height: 16px;
|
||||
color: #fff;
|
||||
padding: 16px 24px;
|
||||
border-radius: 4px;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.button5-btn2 a {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #fff;
|
||||
line-height: 16px;
|
||||
color: #24BA96;
|
||||
padding: 16px 24px;
|
||||
border-radius: 4px;
|
||||
transition: all.3s;
|
||||
box-shadow: 4px 4px 48px rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
|
||||
.button5-btn2 a svg {
|
||||
color: #Fff;
|
||||
}
|
||||
|
||||
.d-none.d-md-block.button5-btn2:hover a svg {
|
||||
color: #24BA96;
|
||||
}
|
||||
.button5-btn2 a:hover span {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.button5-btn2 a span {
|
||||
background-color: #24BA96;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
transform: rotate(-45deg);
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.button5 button {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #24BA96;
|
||||
line-height: 16px;
|
||||
color: #fff;
|
||||
padding: 16px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.button5 button:hover {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
background-color: #fff;
|
||||
line-height: 16px;
|
||||
color: #24BA96;
|
||||
padding: 16px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
box-shadow: 4px 4px 48px rgba(0, 0, 0, 0.14);
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.button5 button svg {
|
||||
|
||||
color: #24BA96;
|
||||
transition: all.3s;
|
||||
}
|
||||
.button5 button:hover svg {
|
||||
color: #fff;
|
||||
transition: all.3s;
|
||||
}
|
||||
|
||||
.button5 button span {
|
||||
background-color: #fff;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
transition: all.3s;
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
transform: rotate(-45deg);
|
||||
margin-left: 3px;
|
||||
}
|
||||
.button5 button:hover span {
|
||||
background-color: #24BA96;
|
||||
}
|
||||
/*------------------------------------------
|
||||
------------ all buttons--------------------
|
||||
-------------------------------- */
|
||||
|
||||
.video-play-button {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
top: 8px;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
box-sizing: content-box;
|
||||
display: block;
|
||||
width: 32px;
|
||||
height: 44px;
|
||||
/* background: #fa183d; */
|
||||
border-radius: 50%;
|
||||
padding: 18px 20px 18px 28px;
|
||||
}
|
||||
|
||||
.video-play-button:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: #24BA96;
|
||||
border-radius: 50%;
|
||||
animation: pulse-border 1500ms ease-out infinite;
|
||||
}
|
||||
.padding50 {
|
||||
padding: 20px 0 80px 0;
|
||||
}
|
||||
.video-play-button:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
display: block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: #24BA96;
|
||||
border-radius: 50%;
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
.video-play-button:hover:after {
|
||||
background-color: darken(#fa183d, 10%);
|
||||
}
|
||||
|
||||
.video-play-button img {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.video-play-button span {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 13px solid #fff;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
margin-top: 11px;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
@keyframes pulse-border {
|
||||
0% {
|
||||
transform: translateX(-50%) translateY(-50%) translateZ(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%) translateY(-50%) translateZ(0) scale(1.5);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.video-overlay {
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0,0,0,0.80);
|
||||
opacity: 0;
|
||||
transition: all ease 500ms;
|
||||
}
|
||||
|
||||
.video-overlay.open {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.video-overlay-close {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 15px;
|
||||
right: 20px;
|
||||
font-size: 36px;
|
||||
line-height: 1;
|
||||
font-weight: 400;
|
||||
color: #24BA96;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
.video-overlay-close:hover {
|
||||
color: #24BA96;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*============================
|
||||
++++PAGE-PROGRESS-SATRT+++++
|
||||
=============================*/
|
||||
|
||||
.blok:nth-of-type(odd) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.blok:nth-of-type(even) {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@-webkit-keyframes border-transform {
|
||||
0%,
|
||||
100% {
|
||||
border-radius: 63% 37% 54% 46% / 55% 48% 52% 45%;
|
||||
}
|
||||
14% {
|
||||
border-radius: 40% 60% 54% 46% / 49% 60% 40% 51%;
|
||||
}
|
||||
28% {
|
||||
border-radius: 54% 46% 38% 62% / 49% 70% 30% 51%;
|
||||
}
|
||||
42% {
|
||||
border-radius: 61% 39% 55% 45% / 61% 38% 62% 39%;
|
||||
}
|
||||
56% {
|
||||
border-radius: 61% 39% 67% 33% / 70% 50% 50% 30%;
|
||||
}
|
||||
70% {
|
||||
border-radius: 50% 50% 34% 66% / 56% 68% 32% 44%;
|
||||
}
|
||||
84% {
|
||||
border-radius: 46% 54% 50% 50% / 35% 61% 39% 65%;
|
||||
}
|
||||
}
|
||||
|
||||
/* #Progress
|
||||
================================================== */
|
||||
|
||||
/*============================
|
||||
++++PAGE-PROGRESS-SATRT+++++
|
||||
=============================*/
|
||||
|
||||
.blok:nth-of-type(odd) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.blok:nth-of-type(even) {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@-webkit-keyframes border-transform {
|
||||
0%,
|
||||
100% {
|
||||
border-radius: 63% 37% 54% 46% / 55% 48% 52% 45%;
|
||||
}
|
||||
14% {
|
||||
border-radius: 40% 60% 54% 46% / 49% 60% 40% 51%;
|
||||
}
|
||||
28% {
|
||||
border-radius: 54% 46% 38% 62% / 49% 70% 30% 51%;
|
||||
}
|
||||
42% {
|
||||
border-radius: 61% 39% 55% 45% / 61% 38% 62% 39%;
|
||||
}
|
||||
56% {
|
||||
border-radius: 61% 39% 67% 33% / 70% 50% 50% 30%;
|
||||
}
|
||||
70% {
|
||||
border-radius: 50% 50% 34% 66% / 56% 68% 32% 44%;
|
||||
}
|
||||
84% {
|
||||
border-radius: 46% 54% 50% 50% / 35% 61% 39% 65%;
|
||||
}
|
||||
}
|
||||
|
||||
/* #Progress
|
||||
================================================== */
|
||||
|
||||
.progress-wrap {
|
||||
position: fixed;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
border-radius: 50px;
|
||||
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
|
||||
z-index: 10000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transform: translateY(15px);
|
||||
-webkit-transition: all 200ms linear;
|
||||
transition: all 200ms linear;
|
||||
}
|
||||
.progress-wrap.active-progress {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateY(0);
|
||||
}
|
||||
.progress-wrap::after {
|
||||
position: absolute;
|
||||
font-family: "FontAwesome";
|
||||
content: "\f062";
|
||||
text-align: center;
|
||||
line-height: 56px;
|
||||
font-size: 18px;
|
||||
color: #03256c;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
z-index: 1;
|
||||
-webkit-transition: all 200ms linear;
|
||||
transition: all 200ms linear;
|
||||
}
|
||||
.progress-wrap:hover::after {
|
||||
opacity: 0;
|
||||
}
|
||||
.progress-wrap::before {
|
||||
position: absolute;
|
||||
font-family: "FontAwesome";
|
||||
content: "\f062";
|
||||
text-align: center;
|
||||
line-height: 56px;
|
||||
font-size: 18px;
|
||||
opacity: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
z-index: 2;
|
||||
-webkit-transition: all 200ms linear;
|
||||
transition: all 200ms linear;
|
||||
}
|
||||
.progress-wrap:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
.progress-wrap svg path {
|
||||
fill: none;
|
||||
}
|
||||
.progress-wrap svg.progress-circle path {
|
||||
stroke: #03256c; /* --- Lijn progres kleur --- */
|
||||
stroke-width: 4;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition: all 200ms linear;
|
||||
transition: all 200ms linear;
|
||||
}
|
||||
|
||||
/*============================
|
||||
++++PAGE-PROGRESS-END+++++
|
||||
=============================*/
|
||||
|
||||
|
||||
|
||||
/*========+ PRELOADER +=========*/
|
||||
|
||||
#preloader {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #061a45;
|
||||
z-index: 9999;
|
||||
}
|
||||
#loader {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: -75px 0 0 -75px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #B1C8E8;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
#loader:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #B1C8E8;
|
||||
-webkit-animation: spin 3s linear infinite;
|
||||
animation: spin 3s linear infinite;
|
||||
}
|
||||
#loader:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #B1C8E8;
|
||||
-webkit-animation: spin 1.5s linear infinite;
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*========+ PRELOADER +=========*/
|
||||
|
||||
.border15 {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.border15 img {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
|
||||
.theme-pagination ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.theme-pagination li{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.theme-pagination li a {
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
text-align: center;
|
||||
line-height: 55px;
|
||||
border: 1px solid #E1E3E8;
|
||||
background: var(--background, #F4F8F7);
|
||||
border-radius: 8px;
|
||||
margin: 0 4px;
|
||||
transition: all 0.3s;
|
||||
display: block;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.theme-pagination li a:hover, .theme-pagination li a.active {
|
||||
background: var(--business-consulting, #029AFF);
|
||||
transition: all 0.3s;
|
||||
color: #ffffff;
|
||||
}
|
||||
6
public/assets/css/font-awesome-pro.css
Normal file
6
public/assets/css/font-awesome-pro.css
Normal file
File diff suppressed because one or more lines are too long
366
public/assets/css/fonts.css
Normal file
366
public/assets/css/fonts.css
Normal file
@@ -0,0 +1,366 @@
|
||||
/*! Generated by Font Squirrel (https://www.fontsquirrel.com) on March 28, 2023 */
|
||||
|
||||
/* -------basier font------- */
|
||||
|
||||
@font-face {
|
||||
font-family: "basier";
|
||||
src: url("../fonts/") format("woff2"),
|
||||
url("../fonts/basiersquare-regular-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "basier";
|
||||
src: url("../fonts/basiercircle-regular-webfont.woff2") format("woff2"),
|
||||
url("../fonts/basiercircle-regular-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* -------basier font------- */
|
||||
|
||||
/* -------butler font------- */
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_extrabold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_extrabold-webfont.woff") format("woff");
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_light-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_light-webfont.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_medium-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_medium-webfont.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_regular-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_regular-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_ultra_light-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_ultra_light-webfont.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_black-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_black-webfont.woff") format("woff");
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "butler";
|
||||
src: url("../fonts/butler_bold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/butler_bold-webfont.woff") format("woff");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* -------butler font------- */
|
||||
|
||||
/* -------samsung_sharp font------- */
|
||||
|
||||
@font-face {
|
||||
font-family: "samsung_sharp";
|
||||
src: url("../fonts/") format("woff2"),
|
||||
url("../fonts/samsungsharpsans-medium-webfont.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "samsung_sharp";
|
||||
src: url("../fonts/samsungsharpsans-webfont.woff2") format("woff2"),
|
||||
url("../fonts/samsungsharpsans-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "samsung_sharp";
|
||||
src: url("../fonts/samsungsharpsans-bold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/samsungsharpsans-bold-webfont.woff") format("woff");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* -------samsung_sharp font------- */
|
||||
|
||||
/* -------gilroy font------- */
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-extrabold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-extrabold-webfont.woff") format("woff");
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-extrabolditalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-extrabolditalic-webfont.woff") format("woff");
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-heavy-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-heavy-webfont.woff") format("woff");
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-heavyitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-heavyitalic-webfont.woff") format("woff");
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-light-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-light-webfont.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-lightitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-lightitalic-webfont.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-medium-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-medium-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-mediumitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-mediumitalic-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-black-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-black-webfont.woff") format("woff");
|
||||
font-weight: 1000;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("gilroy-blackitalic-webfont.woff2") format("woff2"),
|
||||
url("gilroy-blackitalic-webfont.woff") format("woff");
|
||||
font-weight: 1000;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-bold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-bold-webfont.woff") format("woff");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-bolditalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-bolditalic-webfont.woff") format("woff");
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-semibold-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-semibold-webfont.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-semibolditalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-semibolditalic-webfont.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-thin-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-thin-webfont.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-thinitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-thinitalic-webfont.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-ultralight-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-ultralight-webfont.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-ultralightitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-ultralightitalic-webfont.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-regular-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-regular-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "gilroy";
|
||||
src: url("../fonts/gilroy-regularitalic-webfont.woff2") format("woff2"),
|
||||
url("../fonts/gilroy-regularitalic-webfont.woff") format("woff");
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* -------CircularStd font------- */
|
||||
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-Black.eot");
|
||||
src: url("../fonts/CircularStd-Black.eot?#iefix") format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-Black.woff") format("woff"),
|
||||
url("../fonts/CircularStd-Black.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-Black.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-BlackItalic.eot");
|
||||
src: url("../fonts/CircularStd-BlackItalic.eot?#iefix")
|
||||
format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-BlackItalic.woff") format("woff"),
|
||||
url("../fonts/CircularStd-BlackItalic.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-BlackItalic.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-Bold.eot");
|
||||
src: url("../fonts/CircularStd-Bold.eot?#iefix") format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-Bold.woff") format("woff"),
|
||||
url("../fonts/CircularStd-Bold.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-Bold.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-BoldItalic.eot");
|
||||
src: url("../fonts/CircularStd-BoldItalic.eot?#iefix")
|
||||
format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-BoldItalic.woff") format("woff"),
|
||||
url("../fonts/CircularStd-BoldItalic.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-BoldItalic.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-Medium.eot");
|
||||
src: url("../fonts/CircularStd-Medium.eot?#iefix") format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-Medium.woff") format("woff"),
|
||||
url("../fonts/CircularStd-Medium.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-Medium.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-MediumItalic.eot");
|
||||
src: url("../fonts/CircularStd-MediumItalic.eot?#iefix")
|
||||
format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-MediumItalic.woff") format("woff"),
|
||||
url("../fonts/CircularStd-MediumItalic.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-MediumItalic.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-Book.eot");
|
||||
src: url("../fonts/CircularStd-Book.eot?#iefix") format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-Book.woff") format("woff"),
|
||||
url("../fonts/CircularStd-Book.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-Book.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "CircularStd";
|
||||
src: url("../fonts/CircularStd-BookItalic.eot");
|
||||
src: url("../fonts/CircularStd-BookItalic.eot?#iefix")
|
||||
format("embedded-opentype"),
|
||||
url("../fonts/CircularStd-BookItalic.woff") format("woff"),
|
||||
url("../fonts/CircularStd-BookItalic.ttf") format("truetype"),
|
||||
url("../fonts/CircularStd-BookItalic.svg#bcc26993292869431e54c666aafa8fcd")
|
||||
format("svg");
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
241
public/assets/css/footer.css
Normal file
241
public/assets/css/footer.css
Normal file
@@ -0,0 +1,241 @@
|
||||
/*----===========FOOTER AREA CSS----============*/
|
||||
.single-footer ul {
|
||||
list-style: none;
|
||||
}
|
||||
.single-footer ul li a {
|
||||
color: #09120e;
|
||||
font-size: 16px;
|
||||
padding: 10px 0;
|
||||
display: inline-block;
|
||||
transition: all.3s;
|
||||
}
|
||||
.single-footer ul li a:hover {
|
||||
color: #006fff;
|
||||
transition: all.3s;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.footer-area3 .single-footer ul li a:hover {
|
||||
color: #ff008a;
|
||||
}
|
||||
|
||||
.single-footer h3 {
|
||||
margin-left: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.copyright2 {
|
||||
border-top: 1px solid #E9ECEA;
|
||||
padding: 16px 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.copyright4 {
|
||||
border-top: 1px solid #737373;
|
||||
padding: 16px 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.copyright5 {
|
||||
border-top: 1px solid #192D6A;
|
||||
padding: 16px 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.social1 ul {
|
||||
list-style: none;
|
||||
}
|
||||
.social1 ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.social1 ul li a {
|
||||
background: #f2f2f2;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
display: inherit;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
color: #006fff;
|
||||
line-height: 40px;
|
||||
transition: all.4s;
|
||||
}
|
||||
.social1 ul li a:hover {
|
||||
background-color: #006fff;
|
||||
color: #fff;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 426px) {
|
||||
.social.social1 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.social1.comon-footer-icons {
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.foonter-contact-icon-1 > div {
|
||||
background: #2f81ed17;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
.foonter-contact-p a {
|
||||
color: #525975;
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.foonter-contact-1 {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
}
|
||||
.foonter-contact-p {
|
||||
padding-left: 8px;
|
||||
}
|
||||
.foonter-contact-1 {
|
||||
padding-top: 24px;
|
||||
}
|
||||
/*----===========FOOTER AREA CSS----============*/
|
||||
|
||||
/*----===========HOME4 FOOTER AREA CSS----============*/
|
||||
.footer-area4 {
|
||||
background-image: url(../img/footer/footer4.png);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.single-footer4 ul li a {
|
||||
color: #B2B4B7;
|
||||
}
|
||||
.single-footer4 p {
|
||||
color: #B2B4B7;
|
||||
}
|
||||
|
||||
.social.social4 ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.social.social4 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.social.social4 ul li a {
|
||||
font-size: 20px;
|
||||
color: #000410;
|
||||
background: #fff;
|
||||
/* padding: 5px; */
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
transition: all.3s;
|
||||
}
|
||||
.social.social4 ul li a:hover {
|
||||
transition: all.3s;
|
||||
background-color: #006fff;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.social.social4 ul li {
|
||||
display: inline-block;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
|
||||
/*----===========HOME4 FOOTER AREA CSS----============*/
|
||||
|
||||
/*----===========HOME5 FOOTER AREA CSS----============*/
|
||||
|
||||
.footer-area5 {
|
||||
background-image: url(../img/bg/footer5-bg.png);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.footer5-p {
|
||||
color: #CCD0DE;
|
||||
}
|
||||
|
||||
.footer5-from {
|
||||
position: relative;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
|
||||
.social1 ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.social.social1.social5.text-start ul li a {
|
||||
background-color: #192D6A;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.social.social1.social5.text-start ul li a:hover {
|
||||
background-color: #24BA96;
|
||||
}
|
||||
|
||||
.foorer5-list li a {
|
||||
color: rgba(255, 255, 255, 0.90);
|
||||
transition: all.3s;
|
||||
display: block;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.foorer5-list li a:hover {
|
||||
color: #fff;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
ul.foorer5-list {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.foonter-contact-p.foonter-contact-p5 a {
|
||||
color: rgba(255, 255, 255, 0.90);
|
||||
}
|
||||
|
||||
.foonter-contact-p.foonter-contact-p5 a {
|
||||
display: block;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.footer5-from-input input {
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 13px;
|
||||
border-bottom: 1px solid #fff;
|
||||
color: #fff;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.button5.button5-footer5 {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.footer5-p p {
|
||||
color: rgba(255, 255, 255, 0.90);
|
||||
|
||||
}
|
||||
|
||||
.foonter-contact-icon-1 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/*----===========HOME5 FOOTER AREA CSS----============*/
|
||||
|
||||
|
||||
640
public/assets/css/header.css
Normal file
640
public/assets/css/header.css
Normal file
@@ -0,0 +1,640 @@
|
||||
.header-area {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.main-menu ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.main-menu li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.site-logo {
|
||||
max-width: 280px;
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.site-logo a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.main-menu li a {
|
||||
color: #000;
|
||||
padding: 10px 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav > ul {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.main-menu ul li {
|
||||
display: inline-block;
|
||||
margin-right: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.home1-site-logo span {
|
||||
background: #cce4ff;
|
||||
padding: 6px 8px;
|
||||
font-size: 13px;
|
||||
line-height: 13px;
|
||||
margin-left: 8px;
|
||||
color: #0263e0;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 992px) and (max-width: 1199px) {
|
||||
.main-menu ul li {
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
.main-menu ul li:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.main-menu ul li.has-dropdown > a {
|
||||
padding-right: 14px;
|
||||
}
|
||||
.main-menu ul li.has-dropdown > a::after {
|
||||
position: absolute;
|
||||
content: "\f107";
|
||||
right: -4px;
|
||||
top: 22px;
|
||||
font-size: 14px;
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
font-family: "Font Awesome 6 Pro";
|
||||
}
|
||||
.main-menu ul li a {
|
||||
color: #0f1826;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
font-weight: 450;
|
||||
padding: 20px 0;
|
||||
display: inline-block;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.main-menu ul li .active {
|
||||
color: #f9f9f9;
|
||||
}
|
||||
.main-menu ul li:hover > a {
|
||||
color: #000;
|
||||
}
|
||||
.main-menu ul li:hover > a::after {
|
||||
color: #000;
|
||||
}
|
||||
.main-menu ul li:hover .sub-menu {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
top: 100%;
|
||||
}
|
||||
.main-menu ul li .sub-menu {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 110%;
|
||||
min-width: 220px;
|
||||
background-color: #fff;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
z-index: 99;
|
||||
-webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.16);
|
||||
-moz-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.16);
|
||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.16);
|
||||
padding: 20px 0px 15px;
|
||||
transition: 0.3s;
|
||||
border-top: 4px solid #000;
|
||||
}
|
||||
|
||||
.main-menu ul li .sub-menu li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.main-menu ul li .sub-menu li a {
|
||||
font-size: 16px;
|
||||
font-weight: 450;
|
||||
display: block;
|
||||
padding: 10px 25px;
|
||||
transition: 0.3s;
|
||||
color: #000;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.main-menu ul li .sub-menu li .active {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.main-menu ul li .sub-menu li:hover > a {
|
||||
color: #0263e0;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.main-menu ul li .sub-menu li > .sub-menu {
|
||||
left: 120%;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
.main-menu ul li .sub-menu li:hover > .sub-menu {
|
||||
left: 100%;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.meanmenu-reveal {
|
||||
display: none !important;
|
||||
}
|
||||
.mean-container .mean-nav {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.mean-container .mean-bar {
|
||||
padding: 0 0 !important;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.slidebar-content {
|
||||
padding: 20px 40px;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sidebar-logo {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.sidebar-close {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.sidebar-logo {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.sidebar-close {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.sidebar-socials ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.sidebar-socials li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sidebar-socials {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.sidebar-socials li a {
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.sidebar-socials li a:hover {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.sidebar-single-contact-info {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding-left: 80px;
|
||||
min-height: 60px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.sidebar-contact-info-icon {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background: #f9f9f9;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.mobile-menu.fix.mean-container {
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-main {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f1f1f1;
|
||||
transition: all 0.3s;
|
||||
right: -100%;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
.sidebar-main.active {
|
||||
transition: all 0.3s;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.mobile-menu-bar {
|
||||
height: 30px;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.sidebar-contact-info-title p {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sidebar-contact-info-title a {
|
||||
font-size: 20px;
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
}
|
||||
.sidebar-single-contact-info {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
a.cta-btn {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
line-height: 14px;
|
||||
padding: 17px 20px;
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0px 20px 40px rgba(2, 99, 224, 0.15);
|
||||
}
|
||||
|
||||
a.cta-btn::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: #0263e0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -2;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
a.cta-btn::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: #202C4A;
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
border-radius: 7px;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
a.cta-btn:hover::after {
|
||||
width: 100%;
|
||||
transition: all.4s;
|
||||
}
|
||||
|
||||
a.cta-btn:hover {
|
||||
transition: all 0.3s;
|
||||
transform: translatey(-5px);
|
||||
}
|
||||
a.login-btn {
|
||||
color: #0263e0;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
/*------------------------ home 2 -------------------------*/
|
||||
a.home2-site-btn-1 {
|
||||
color: #202c4a;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
/*------------------------ home 2 -------------------------*/
|
||||
|
||||
.main-menu3 ul li a {
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
color: #fff;
|
||||
}
|
||||
.main-menu3 ul li.has-dropdown > a::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
right: -4px;
|
||||
top: 22px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
font-family: "Font Awesome 6 Pro";
|
||||
}
|
||||
.main-menu3 ul li a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
a.home3-cta {
|
||||
background: #ff008a;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
padding: 17px 50px;
|
||||
border-radius: 5px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====nav menu all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
.main-menu-ex li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.main-menu-ex li a {
|
||||
color: #000;
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
padding: 10px 15px;
|
||||
transition: all.3s;
|
||||
}
|
||||
.main-menu-ex li a:hover {
|
||||
color: #0263e0;
|
||||
transition: all.3s;
|
||||
}
|
||||
.main-menu-ex li {
|
||||
position: relative;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.main-menu-ex li ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50px;
|
||||
background: #fff;
|
||||
width: 200px;
|
||||
border-radius: 4px;
|
||||
box-shadow: rgb(0 0 0 / 20%) 0px 20px 30px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.main-menu-ex li li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.main-menu-ex li li a {
|
||||
padding: 10px 20px;
|
||||
color: #0e1124;
|
||||
font-weight: 500;
|
||||
transition: all.4s;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-menu-ex li li a:hover {
|
||||
color: #fff;
|
||||
transition: all.4s;
|
||||
}
|
||||
.main-menu-ex li li a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: rotatey(60deg);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
transition: all.4s;
|
||||
z-index: -1;
|
||||
}
|
||||
.main-menu-ex li li a:hover::after {
|
||||
transform: rotatey(0deg);
|
||||
background-color:
|
||||
#2F80ED;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.main-menu-ex li li a .main-menu-ex li li a:hover {
|
||||
background-color: #00bf71;
|
||||
transform: rotatey(0deg);
|
||||
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.main-menu-ex li > ul {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
.main-menu-ex li li > ul {
|
||||
left: 100%;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.main-menu-ex li li:hover > ul {
|
||||
top: 0;
|
||||
}
|
||||
.main-menu-ex li:hover > ul {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
top: 50px;
|
||||
transition: all 0.3s;
|
||||
z-index: 99;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.main-menu-ex.home4-menu li li a {
|
||||
padding: 10px 20px;
|
||||
color: #0e1124;
|
||||
font-weight: 500;
|
||||
transition: all.4s;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-menu-ex.home4-menu li li a:hover {
|
||||
color: #fff;
|
||||
transition: all.4s;
|
||||
}
|
||||
.main-menu-ex.home4-menu li li a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translateY(-10px);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
transition: all.4s;
|
||||
z-index: -1;
|
||||
}
|
||||
.main-menu-ex.home4-menu li li a:hover::after {
|
||||
transform: translateY(0);
|
||||
background-color: #ff3e55;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.main-menu-ex.home2-menu li li a {
|
||||
padding: 10px 20px;
|
||||
color: #0e1124;
|
||||
font-weight: 500;
|
||||
transition: all.4s;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-menu-ex.home2-menu li li a:hover {
|
||||
color: #fff;
|
||||
transition: all.4s;
|
||||
}
|
||||
.main-menu-ex.home2-menu li li a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translateY(-10px);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
transition: all.4s;
|
||||
z-index: -1;
|
||||
}
|
||||
.main-menu-ex.home2-menu li li a:hover::after {
|
||||
transform: translateY(0);
|
||||
background-color: #00bf71;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
li.has-dropdown1 {
|
||||
position: relative;
|
||||
}
|
||||
li.has-dropdown1 span {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
|
||||
.main-menu-ex.main-menu-ex3 li a:hover {
|
||||
color: #ff008a;
|
||||
}
|
||||
|
||||
.main-menu-ex.main-menu-ex3 li li a:hover {
|
||||
color: #fff;
|
||||
background-color: #ff008a;
|
||||
}
|
||||
|
||||
.main-menu-ex.main-menu-ex4 li a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.main-menu-ex.main-menu-ex4 li a:hover {
|
||||
color: #2F80ED;
|
||||
}
|
||||
|
||||
.main-menu-ex.main-menu-ex4 li li a {
|
||||
color: #0e1124;
|
||||
}
|
||||
|
||||
.main-menu-ex.main-menu-ex4 li li a:hover {
|
||||
background-color: #0263e0;
|
||||
}
|
||||
.main-menu-ex.main-menu-ex4 li li a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.main-menu-ex.main-menu-ex5 li li a:hover {
|
||||
background-color: #24BA96;
|
||||
}
|
||||
.main-menu-ex.main-menu-ex5 li li a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.main-menu-ex.main-menu-ex5 li a:hover {
|
||||
color: #00bf71;
|
||||
}
|
||||
/*
|
||||
++++++++++++++++++++++++++++++++++
|
||||
==== =====nav menu all ====== ======
|
||||
+++++++++++++++++++++++++++++++++
|
||||
*/
|
||||
|
||||
.header-area {
|
||||
transition: all.6s;
|
||||
}
|
||||
.header-area.sticky {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translate3d(0, 0, 0);
|
||||
z-index: 111;
|
||||
-webkit-animation-name: fade-in-down;
|
||||
animation-name: fade-in-down;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
background-color: #ffffff;
|
||||
transition: all 0.3s ease-in-out;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.header-area.header-area2.sticky {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translate3d(0, 0, 0);
|
||||
z-index: 111;
|
||||
-webkit-animation-name: fade-in-down;
|
||||
animation-name: fade-in-down;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
background-color: #0A122A;
|
||||
transition: all 0.3s ease-in-out;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.header-site-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
351
public/assets/css/magnific-popup.css
Normal file
351
public/assets/css/magnific-popup.css
Normal file
@@ -0,0 +1,351 @@
|
||||
/* Magnific Popup CSS */
|
||||
.mfp-bg {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1042;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
background: #0b0b0b;
|
||||
opacity: 0.8; }
|
||||
|
||||
.mfp-wrap {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1043;
|
||||
position: fixed;
|
||||
outline: none !important;
|
||||
-webkit-backface-visibility: hidden; }
|
||||
|
||||
.mfp-container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0 8px;
|
||||
box-sizing: border-box; }
|
||||
|
||||
.mfp-container:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle; }
|
||||
|
||||
.mfp-align-top .mfp-container:before {
|
||||
display: none; }
|
||||
|
||||
.mfp-content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
z-index: 1045; }
|
||||
|
||||
.mfp-inline-holder .mfp-content,
|
||||
.mfp-ajax-holder .mfp-content {
|
||||
width: 100%;
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-ajax-cur {
|
||||
cursor: progress; }
|
||||
|
||||
.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close {
|
||||
cursor: -moz-zoom-out;
|
||||
cursor: -webkit-zoom-out;
|
||||
cursor: zoom-out; }
|
||||
|
||||
.mfp-zoom {
|
||||
cursor: pointer;
|
||||
cursor: -webkit-zoom-in;
|
||||
cursor: -moz-zoom-in;
|
||||
cursor: zoom-in; }
|
||||
|
||||
.mfp-auto-cursor .mfp-content {
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-close,
|
||||
.mfp-arrow,
|
||||
.mfp-preloader,
|
||||
.mfp-counter {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none; }
|
||||
|
||||
.mfp-loading.mfp-figure {
|
||||
display: none; }
|
||||
|
||||
.mfp-hide {
|
||||
display: none !important; }
|
||||
|
||||
.mfp-preloader {
|
||||
color: #CCC;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
margin-top: -0.8em;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
z-index: 1044; }
|
||||
.mfp-preloader a {
|
||||
color: #CCC; }
|
||||
.mfp-preloader a:hover {
|
||||
color: #FFF; }
|
||||
|
||||
.mfp-s-ready .mfp-preloader {
|
||||
display: none; }
|
||||
|
||||
.mfp-s-error .mfp-content {
|
||||
display: none; }
|
||||
|
||||
button.mfp-close,
|
||||
button.mfp-arrow {
|
||||
overflow: visible;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
z-index: 1046;
|
||||
box-shadow: none;
|
||||
touch-action: manipulation; }
|
||||
|
||||
button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0; }
|
||||
|
||||
.mfp-close {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
opacity: 0.65;
|
||||
padding: 0 0 18px 10px;
|
||||
color: #FFF;
|
||||
font-style: normal;
|
||||
font-size: 28px;
|
||||
font-family: Arial, Baskerville, monospace; }
|
||||
.mfp-close:hover,
|
||||
.mfp-close:focus {
|
||||
opacity: 1; }
|
||||
.mfp-close:active {
|
||||
top: 1px; }
|
||||
|
||||
.mfp-close-btn-in .mfp-close {
|
||||
color: #333; }
|
||||
|
||||
.mfp-image-holder .mfp-close,
|
||||
.mfp-iframe-holder .mfp-close {
|
||||
color: #FFF;
|
||||
right: -6px;
|
||||
text-align: right;
|
||||
padding-right: 6px;
|
||||
width: 100%; }
|
||||
|
||||
.mfp-counter {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: #CCC;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap; }
|
||||
|
||||
.mfp-arrow {
|
||||
position: absolute;
|
||||
opacity: 0.65;
|
||||
margin: 0;
|
||||
top: 50%;
|
||||
margin-top: -55px;
|
||||
padding: 0;
|
||||
width: 90px;
|
||||
height: 110px;
|
||||
-webkit-tap-highlight-color: transparent; }
|
||||
.mfp-arrow:active {
|
||||
margin-top: -54px; }
|
||||
.mfp-arrow:hover,
|
||||
.mfp-arrow:focus {
|
||||
opacity: 1; }
|
||||
.mfp-arrow:before,
|
||||
.mfp-arrow:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin-top: 35px;
|
||||
margin-left: 35px;
|
||||
border: medium inset transparent; }
|
||||
.mfp-arrow:after {
|
||||
border-top-width: 13px;
|
||||
border-bottom-width: 13px;
|
||||
top: 8px; }
|
||||
.mfp-arrow:before {
|
||||
border-top-width: 21px;
|
||||
border-bottom-width: 21px;
|
||||
opacity: 0.7; }
|
||||
|
||||
.mfp-arrow-left {
|
||||
left: 0; }
|
||||
.mfp-arrow-left:after {
|
||||
border-right: 17px solid #FFF;
|
||||
margin-left: 31px; }
|
||||
.mfp-arrow-left:before {
|
||||
margin-left: 25px;
|
||||
border-right: 27px solid #3F3F3F; }
|
||||
|
||||
.mfp-arrow-right {
|
||||
right: 0; }
|
||||
.mfp-arrow-right:after {
|
||||
border-left: 17px solid #FFF;
|
||||
margin-left: 39px; }
|
||||
.mfp-arrow-right:before {
|
||||
border-left: 27px solid #3F3F3F; }
|
||||
|
||||
.mfp-iframe-holder {
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px; }
|
||||
.mfp-iframe-holder .mfp-content {
|
||||
line-height: 0;
|
||||
width: 100%;
|
||||
max-width: 900px; }
|
||||
.mfp-iframe-holder .mfp-close {
|
||||
top: -40px; }
|
||||
|
||||
.mfp-iframe-scaler {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 56.25%; }
|
||||
.mfp-iframe-scaler iframe {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
background: #000; }
|
||||
|
||||
/* Main image in popup */
|
||||
img.mfp-img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
line-height: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 40px 0 40px;
|
||||
margin: 0 auto; }
|
||||
|
||||
/* The shadow behind the image */
|
||||
.mfp-figure {
|
||||
line-height: 0; }
|
||||
.mfp-figure:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
bottom: 40px;
|
||||
display: block;
|
||||
right: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
z-index: -1;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
background: #444; }
|
||||
.mfp-figure small {
|
||||
color: #BDBDBD;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 14px; }
|
||||
.mfp-figure figure {
|
||||
margin: 0; }
|
||||
|
||||
.mfp-bottom-bar {
|
||||
margin-top: -36px;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-title {
|
||||
text-align: left;
|
||||
line-height: 18px;
|
||||
color: #F3F3F3;
|
||||
word-wrap: break-word;
|
||||
padding-right: 36px; }
|
||||
|
||||
.mfp-image-holder .mfp-content {
|
||||
max-width: 100%; }
|
||||
|
||||
.mfp-gallery .mfp-image-holder .mfp-figure {
|
||||
cursor: pointer; }
|
||||
|
||||
@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) {
|
||||
/**
|
||||
* Remove all paddings around the image on small screen
|
||||
*/
|
||||
.mfp-img-mobile .mfp-image-holder {
|
||||
padding-left: 0;
|
||||
padding-right: 0; }
|
||||
.mfp-img-mobile img.mfp-img {
|
||||
padding: 0; }
|
||||
.mfp-img-mobile .mfp-figure:after {
|
||||
top: 0;
|
||||
bottom: 0; }
|
||||
.mfp-img-mobile .mfp-figure small {
|
||||
display: inline;
|
||||
margin-left: 5px; }
|
||||
.mfp-img-mobile .mfp-bottom-bar {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
top: auto;
|
||||
padding: 3px 5px;
|
||||
position: fixed;
|
||||
box-sizing: border-box; }
|
||||
.mfp-img-mobile .mfp-bottom-bar:empty {
|
||||
padding: 0; }
|
||||
.mfp-img-mobile .mfp-counter {
|
||||
right: 5px;
|
||||
top: 3px; }
|
||||
.mfp-img-mobile .mfp-close {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
padding: 0; } }
|
||||
|
||||
@media all and (max-width: 900px) {
|
||||
.mfp-arrow {
|
||||
-webkit-transform: scale(0.75);
|
||||
transform: scale(0.75); }
|
||||
.mfp-arrow-left {
|
||||
-webkit-transform-origin: 0;
|
||||
transform-origin: 0; }
|
||||
.mfp-arrow-right {
|
||||
-webkit-transform-origin: 100%;
|
||||
transform-origin: 100%; }
|
||||
.mfp-container {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px; } }
|
||||
175
public/assets/css/meanmenu.css
Normal file
175
public/assets/css/meanmenu.css
Normal file
@@ -0,0 +1,175 @@
|
||||
|
||||
/*! #######################################################################
|
||||
|
||||
MeanMenu 2.0.7
|
||||
--------
|
||||
|
||||
To be used with jquery.meanmenu.js by Chris Wharton (http://www.meanthemes.com/plugins/meanmenu/)
|
||||
|
||||
####################################################################### */
|
||||
|
||||
/* hide the link until viewport size is reached */
|
||||
a.meanmenu-reveal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* when under viewport size, .mean-container is added to body */
|
||||
.mean-container .mean-bar {
|
||||
float: left;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: #f9f9f9;
|
||||
padding: 4px 0;
|
||||
min-height: 42px;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.mean-container a.meanmenu-reveal {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 13px 13px 11px 13px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
text-indent: -9999em;
|
||||
line-height: 22px;
|
||||
font-size: 1px;
|
||||
display: block;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.mean-container a.meanmenu-reveal span {
|
||||
display: block;
|
||||
background: #000;
|
||||
height: 3px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav {
|
||||
float: left;
|
||||
width: 100%;
|
||||
background: #f9f9f9;
|
||||
margin-top: 44px;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li a {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 90%;
|
||||
padding: 1em 5%;
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
color: #000;
|
||||
border-top: 1px solid #383838;
|
||||
border-top: 1px solid #f1f1f1;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li li a {
|
||||
width: 80%;
|
||||
padding: 1em 10%;
|
||||
border-top: 1px solid #f1f1f1;
|
||||
border-top: 1px solid #f1f1f1;
|
||||
opacity: 0.75;
|
||||
filter: alpha(opacity=75);
|
||||
text-shadow: none !important;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li.mean-last a {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li li li a {
|
||||
width: 70%;
|
||||
padding: 1em 15%;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li li li li a {
|
||||
width: 60%;
|
||||
padding: 1em 20%;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li li li li li a {
|
||||
width: 50%;
|
||||
padding: 1em 25%;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li a:hover {
|
||||
background: #252525;
|
||||
background: rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li a.mean-expand {
|
||||
margin-top: 1px;
|
||||
width: 26px;
|
||||
height: 32px;
|
||||
padding: 12px !important;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
font-weight: 700;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border: none !important;
|
||||
border-left: 1px solid rgba(255,255,255,0.4) !important;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.2) !important;
|
||||
}
|
||||
|
||||
.mean-container .mean-nav ul li a.mean-expand:hover {
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
.mean-container .mean-nav ul li a.mean-expand{
|
||||
border: 1px solid #f1f1f1 !important;
|
||||
}
|
||||
.mean-container .mean-push {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.mean-nav .wrapper {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mobile-menu.fix.mean-container {
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
/* Fix for box sizing on Foundation Framework etc. */
|
||||
.mean-container .mean-bar, .mean-container .mean-bar * {
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
|
||||
.mean-remove {
|
||||
display: none !important;
|
||||
}
|
||||
224
public/assets/css/mobile-menu.css
Normal file
224
public/assets/css/mobile-menu.css
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
|
||||
Plugin Name: Multi Drop Down Mobile menu
|
||||
version: 1.0
|
||||
Author: Sujon Mahamud
|
||||
Desc:
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*Base css*/
|
||||
|
||||
@media screen and (max-width:769px) {
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body{
|
||||
font-size: 16px;
|
||||
font-family: 'arial', sans-serif;
|
||||
}
|
||||
|
||||
a, a:hover{
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul, li{
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*Menu Css*/
|
||||
|
||||
.mobile-logo a{
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
.mobile-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 17px 0;
|
||||
z-index: 9;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.mobile-header-elements {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.mobile-nav-icon {
|
||||
font-size: 23px;
|
||||
border: 1px solid;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.mobile-sidebar {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background:#000;
|
||||
z-index: 99;
|
||||
padding: 40px 30px;
|
||||
left: -100%;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all .3s;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.mobile-sidebar .contact-icon{
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
||||
.mobile-sidebar.mobile-menu-active{
|
||||
left: 0;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.menu-close {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
font-size: 25px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile-nav li a {
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
padding: 10px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul.mobile-nav-list {
|
||||
margin-bottom: 40px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
li.has-children {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
span.mobile-nav-menu-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.mobile-menu-sub {
|
||||
display: none;
|
||||
position: relative;
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
ul.mobile-menu-sub.sub-menu-active{
|
||||
display: block;
|
||||
position: relative;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.mobile-nav li {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
span.submenu-button {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
span.submenu-button:after, span.submenu-button:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 20px;
|
||||
width: 2px;
|
||||
background: #fff;
|
||||
top: 12px;
|
||||
right: 9px;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
span.submenu-button:before {
|
||||
height: 2px;
|
||||
width: 20px;
|
||||
right: 0px;
|
||||
top: 22px;
|
||||
}
|
||||
|
||||
span.submenu-button.submenu-opened:after {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sub-menu{
|
||||
display: none;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
|
||||
span.multi-drop-icon {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
|
||||
ul.mobile-nav-list {
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
1
public/assets/css/modal-video.min.css
vendored
Normal file
1
public/assets/css/modal-video.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
@keyframes modal-video{from{opacity:0}to{opacity:1}}@keyframes modal-video-inner{from{transform:translate(0, 100px)}to{transform:translate(0, 0)}}.modal-video{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.5);z-index:1000000;cursor:pointer;opacity:1;animation-timing-function:ease-out;animation-duration:.3s;animation-name:modal-video;-webkit-transition:opacity .3s ease-out;-moz-transition:opacity .3s ease-out;-ms-transition:opacity .3s ease-out;-o-transition:opacity .3s ease-out;transition:opacity .3s ease-out}.modal-video-close{opacity:0}.modal-video-close .modal-video-movie-wrap{-webkit-transform:translate(0, 100px);-moz-transform:translate(0, 100px);-ms-transform:translate(0, 100px);-o-transform:translate(0, 100px);transform:translate(0, 100px)}.modal-video-body{max-width:960px;width:100%;height:100%;margin:0 auto;padding:0 10px;display:flex;justify-content:center;box-sizing:border-box}.modal-video-inner{display:flex;justify-content:center;align-items:center;width:100%;height:100%}@media (orientation: landscape){.modal-video-inner{padding:10px 60px;box-sizing:border-box}}.modal-video-movie-wrap{width:100%;height:0;position:relative;padding-bottom:56.25%;background-color:#333;animation-timing-function:ease-out;animation-duration:.3s;animation-name:modal-video-inner;-webkit-transform:translate(0, 0);-moz-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-ms-transition:-ms-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal-video-movie-wrap iframe{position:absolute;top:0;left:0;width:100%;height:100%}.modal-video-close-btn{position:absolute;z-index:2;top:-45px;right:0;display:inline-block;width:35px;height:35px;overflow:hidden;border:none;background:transparent}@media (orientation: landscape){.modal-video-close-btn{top:0;right:-45px}}.modal-video-close-btn:before{transform:rotate(45deg)}.modal-video-close-btn:after{transform:rotate(-45deg)}.modal-video-close-btn:before,.modal-video-close-btn:after{content:'';position:absolute;height:2px;width:100%;top:50%;left:0;margin-top:-1px;background:#fff;border-radius:5px;margin-top:-6px}
|
||||
138
public/assets/css/nice-select.css
Normal file
138
public/assets/css/nice-select.css
Normal file
@@ -0,0 +1,138 @@
|
||||
.nice-select {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
border: solid 1px #e8e8e8;
|
||||
box-sizing: border-box;
|
||||
clear: both;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
height: 42px;
|
||||
line-height: 40px;
|
||||
outline: none;
|
||||
padding-left: 18px;
|
||||
padding-right: 30px;
|
||||
position: relative;
|
||||
text-align: left !important;
|
||||
-webkit-transition: all 0.2s ease-in-out;
|
||||
transition: all 0.2s ease-in-out;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
width: auto; }
|
||||
.nice-select:hover {
|
||||
border-color: #dbdbdb; }
|
||||
.nice-select:active, .nice-select.open, .nice-select:focus {
|
||||
border-color: #999; }
|
||||
.nice-select:after {
|
||||
border-bottom: 2px solid #999;
|
||||
border-right: 2px solid #999;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 5px;
|
||||
margin-top: -4px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
-webkit-transform-origin: 66% 66%;
|
||||
-ms-transform-origin: 66% 66%;
|
||||
transform-origin: 66% 66%;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
-webkit-transition: all 0.15s ease-in-out;
|
||||
transition: all 0.15s ease-in-out;
|
||||
width: 5px; }
|
||||
.nice-select.open:after {
|
||||
-webkit-transform: rotate(-135deg);
|
||||
-ms-transform: rotate(-135deg);
|
||||
transform: rotate(-135deg); }
|
||||
.nice-select.open .list {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
-webkit-transform: scale(1) translateY(0);
|
||||
-ms-transform: scale(1) translateY(0);
|
||||
transform: scale(1) translateY(0); }
|
||||
.nice-select.disabled {
|
||||
border-color: #ededed;
|
||||
color: #999;
|
||||
pointer-events: none; }
|
||||
.nice-select.disabled:after {
|
||||
border-color: #cccccc; }
|
||||
.nice-select.wide {
|
||||
width: 100%; }
|
||||
.nice-select.wide .list {
|
||||
left: 0 !important;
|
||||
right: 0 !important; }
|
||||
.nice-select.right {
|
||||
float: right; }
|
||||
.nice-select.right .list {
|
||||
left: auto;
|
||||
right: 0; }
|
||||
.nice-select.small {
|
||||
font-size: 12px;
|
||||
height: 36px;
|
||||
line-height: 34px; }
|
||||
.nice-select.small:after {
|
||||
height: 4px;
|
||||
width: 4px; }
|
||||
.nice-select.small .option {
|
||||
line-height: 34px;
|
||||
min-height: 34px; }
|
||||
.nice-select .list {
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 0 1px rgba(68, 68, 68, 0.11);
|
||||
box-sizing: border-box;
|
||||
margin-top: 4px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
-webkit-transform-origin: 50% 0;
|
||||
-ms-transform-origin: 50% 0;
|
||||
transform-origin: 50% 0;
|
||||
-webkit-transform: scale(0.75) translateY(-21px);
|
||||
-ms-transform: scale(0.75) translateY(-21px);
|
||||
transform: scale(0.75) translateY(-21px);
|
||||
-webkit-transition: all 0.2s cubic-bezier(0.5, 0, 0, 1.25), opacity 0.15s ease-out;
|
||||
transition: all 0.2s cubic-bezier(0.5, 0, 0, 1.25), opacity 0.15s ease-out;
|
||||
z-index: 9; }
|
||||
.nice-select .list:hover .option:not(:hover) {
|
||||
background-color: transparent !important; }
|
||||
.nice-select .option {
|
||||
cursor: pointer;
|
||||
font-weight: 400;
|
||||
line-height: 40px;
|
||||
list-style: none;
|
||||
min-height: 40px;
|
||||
outline: none;
|
||||
padding-left: 18px;
|
||||
padding-right: 29px;
|
||||
text-align: left;
|
||||
-webkit-transition: all 0.2s;
|
||||
transition: all 0.2s; }
|
||||
.nice-select .option:hover, .nice-select .option.focus, .nice-select .option.selected.focus {
|
||||
background-color: #f6f6f6; }
|
||||
.nice-select .option.selected {
|
||||
font-weight: bold; }
|
||||
.nice-select .option.disabled {
|
||||
background-color: transparent;
|
||||
color: #999;
|
||||
cursor: default; }
|
||||
|
||||
.no-csspointerevents .nice-select .list {
|
||||
display: none; }
|
||||
|
||||
.no-csspointerevents .nice-select.open .list {
|
||||
display: block; }
|
||||
6
public/assets/css/owl.carousel.min.css
vendored
Normal file
6
public/assets/css/owl.carousel.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Owl Carousel v2.3.4
|
||||
* Copyright 2013-2018 David Deutsch
|
||||
* Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
|
||||
*/
|
||||
.owl-carousel,.owl-carousel .owl-item{-webkit-tap-highlight-color:transparent;position:relative}.owl-carousel{display:none;width:100%;z-index:1}.owl-carousel .owl-stage{position:relative;-ms-touch-action:pan-Y;touch-action:manipulation;-moz-backface-visibility:hidden}.owl-carousel .owl-stage:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}.owl-carousel .owl-stage-outer{position:relative;overflow:hidden;-webkit-transform:translate3d(0,0,0)}.owl-carousel .owl-item,.owl-carousel .owl-wrapper{-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}.owl-carousel .owl-item{min-height:1px;float:left;-webkit-backface-visibility:hidden;-webkit-touch-callout:none}.owl-carousel .owl-item img{display:block;width:100%}.owl-carousel .owl-dots.disabled,.owl-carousel .owl-nav.disabled{display:none}.no-js .owl-carousel,.owl-carousel.owl-loaded{display:block}.owl-carousel .owl-dot,.owl-carousel .owl-nav .owl-next,.owl-carousel .owl-nav .owl-prev{cursor:pointer;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel .owl-nav button.owl-next,.owl-carousel .owl-nav button.owl-prev,.owl-carousel button.owl-dot{background:0 0;color:inherit;border:none;padding:0!important;font:inherit}.owl-carousel.owl-loading{opacity:0;display:block}.owl-carousel.owl-hidden{opacity:0}.owl-carousel.owl-refresh .owl-item{visibility:hidden}.owl-carousel.owl-drag .owl-item{-ms-touch-action:pan-y;touch-action:pan-y;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel.owl-grab{cursor:move;cursor:grab}.owl-carousel.owl-rtl{direction:rtl}.owl-carousel.owl-rtl .owl-item{float:right}.owl-carousel .animated{animation-duration:1s;animation-fill-mode:both}.owl-carousel .owl-animated-in{z-index:0}.owl-carousel .owl-animated-out{z-index:1}.owl-carousel .fadeOut{animation-name:fadeOut}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.owl-height{transition:height .5s ease-in-out}.owl-carousel .owl-item .owl-lazy{opacity:0;transition:opacity .4s ease}.owl-carousel .owl-item .owl-lazy:not([src]),.owl-carousel .owl-item .owl-lazy[src^=""]{max-height:0}.owl-carousel .owl-item img.owl-lazy{transform-style:preserve-3d}.owl-carousel .owl-video-wrapper{position:relative;height:100%;background:#000}.owl-carousel .owl-video-play-icon{position:absolute;height:80px;width:80px;left:50%;top:50%;margin-left:-40px;margin-top:-40px;background:url(owl.video.play.png) no-repeat;cursor:pointer;z-index:1;-webkit-backface-visibility:hidden;transition:transform .1s ease}.owl-carousel .owl-video-play-icon:hover{-ms-transform:scale(1.3,1.3);transform:scale(1.3,1.3)}.owl-carousel .owl-video-playing .owl-video-play-icon,.owl-carousel .owl-video-playing .owl-video-tn{display:none}.owl-carousel .owl-video-tn{opacity:0;height:100%;background-position:center center;background-repeat:no-repeat;background-size:contain;transition:opacity .4s ease}.owl-carousel .owl-video-frame{position:relative;z-index:1;height:100%;width:100%}
|
||||
0
public/assets/css/preloader.css
Normal file
0
public/assets/css/preloader.css
Normal file
16
public/assets/css/responsive.css
Normal file
16
public/assets/css/responsive.css
Normal file
@@ -0,0 +1,16 @@
|
||||
/*=================
|
||||
home1-start
|
||||
===================*/
|
||||
@media screen and (max-width: 768px) {
|
||||
.home1-hero-hadding {
|
||||
padding: 150px 0 20px 0;
|
||||
}
|
||||
.home1-main-hero-img {
|
||||
padding-top: 75px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/*=================
|
||||
home1-end
|
||||
===================*/
|
||||
119
public/assets/css/slick-slider.css
Normal file
119
public/assets/css/slick-slider.css
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Slider */
|
||||
.slick-slider
|
||||
{
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-khtml-user-select: none;
|
||||
-ms-touch-action: pan-y;
|
||||
touch-action: pan-y;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.slick-list
|
||||
{
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.slick-list:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
.slick-list.dragging
|
||||
{
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
.slick-slider .slick-track,
|
||||
.slick-slider .slick-list
|
||||
{
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
-moz-transform: translate3d(0, 0, 0);
|
||||
-ms-transform: translate3d(0, 0, 0);
|
||||
-o-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.slick-track
|
||||
{
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.slick-track:before,
|
||||
.slick-track:after
|
||||
{
|
||||
display: table;
|
||||
|
||||
content: '';
|
||||
}
|
||||
.slick-track:after
|
||||
{
|
||||
clear: both;
|
||||
}
|
||||
.slick-loading .slick-track
|
||||
{
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.slick-slide
|
||||
{
|
||||
display: none;
|
||||
float: left;
|
||||
|
||||
height: 100%;
|
||||
min-height: 1px;
|
||||
}
|
||||
[dir='rtl'] .slick-slide
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
.slick-slide img
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
.slick-slide.slick-loading img
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
.slick-slide.dragging img
|
||||
{
|
||||
pointer-events: none;
|
||||
}
|
||||
.slick-initialized .slick-slide
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
.slick-loading .slick-slide
|
||||
{
|
||||
visibility: hidden;
|
||||
}
|
||||
.slick-vertical .slick-slide
|
||||
{
|
||||
display: block;
|
||||
|
||||
height: auto;
|
||||
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.slick-arrow.slick-hidden {
|
||||
display: none;
|
||||
}
|
||||
1386
public/assets/css/typography.css
Normal file
1386
public/assets/css/typography.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/assets/fonts/CircularStd-Black.eot
Normal file
BIN
public/assets/fonts/CircularStd-Black.eot
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Black.otf
Normal file
BIN
public/assets/fonts/CircularStd-Black.otf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Black.ttf
Normal file
BIN
public/assets/fonts/CircularStd-Black.ttf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Black.woff
Normal file
BIN
public/assets/fonts/CircularStd-Black.woff
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Black.woff2
Normal file
BIN
public/assets/fonts/CircularStd-Black.woff2
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BlackItalic.eot
Normal file
BIN
public/assets/fonts/CircularStd-BlackItalic.eot
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BlackItalic.otf
Normal file
BIN
public/assets/fonts/CircularStd-BlackItalic.otf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BlackItalic.ttf
Normal file
BIN
public/assets/fonts/CircularStd-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BlackItalic.woff
Normal file
BIN
public/assets/fonts/CircularStd-BlackItalic.woff
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BlackItalic.woff2
Normal file
BIN
public/assets/fonts/CircularStd-BlackItalic.woff2
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Bold.eot
Normal file
BIN
public/assets/fonts/CircularStd-Bold.eot
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Bold.otf
Normal file
BIN
public/assets/fonts/CircularStd-Bold.otf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Bold.ttf
Normal file
BIN
public/assets/fonts/CircularStd-Bold.ttf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Bold.woff
Normal file
BIN
public/assets/fonts/CircularStd-Bold.woff
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Bold.woff2
Normal file
BIN
public/assets/fonts/CircularStd-Bold.woff2
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BoldItalic.eot
Normal file
BIN
public/assets/fonts/CircularStd-BoldItalic.eot
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BoldItalic.otf
Normal file
BIN
public/assets/fonts/CircularStd-BoldItalic.otf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BoldItalic.ttf
Normal file
BIN
public/assets/fonts/CircularStd-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BoldItalic.woff
Normal file
BIN
public/assets/fonts/CircularStd-BoldItalic.woff
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-BoldItalic.woff2
Normal file
BIN
public/assets/fonts/CircularStd-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
public/assets/fonts/CircularStd-Book.eot
Normal file
BIN
public/assets/fonts/CircularStd-Book.eot
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user