return $this->name;
}
+ public function fileByRef($refs)
+ {
+ $results = $this->files()->whereIn('id', $refs)
+ ->get(['id', 'title', 'file_slug', 'cover_url']);
+
+ return response()->json($results);
+ }
+
}
namespace App\Http\Controllers;
use App\FileCollection;
+use App\PdfFile;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
->get()
);
}
+
+ public function getPdfBySlug() {
+ $refs = request('refs', []);
+ $pdfFile = new PdfFile();
+ return $pdfFile->whereIn('slug', $refs)->get()->toArray();
+ }
}
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
+use Typesense\LaravelTypesense\Tests\Fixtures\SearchableUserModel;
/**
* Class SearchableText
protected $guarded = [];
- public function toSearchableArray()
+ public function toSearchableArray(): array
{
return [
- 'file' => [
- 'slug' => $this->file->slug,
- 'tags' => $this->file->fileTags()->pluck('content')->toArray(),
- 'collection' => (string) $this->file->collection,
- 'collection_slug' => $this->file->collection->slug,
- 'visible' => $this->file->is_visible && $this->file->published,
- 'title' => $this->file->title,
- 'cover' => $this->file->coverUrl,
- 'created_at' => $this->file->created_at->format('U'),
- ],
+ 'id' => (string) $this->file->id,
+ 'file_slug' => $this->file->slug,
+ 'file_tags' => $this->file->fileTags()->pluck('content')->toArray(),
+ 'file_collection' => "fluidbooks",
+ 'file_collection_slug' => $this->file->collection->slug,
+ 'file_visible' => $this->file->is_visible && $this->file->published,
+ 'file_title' => $this->file->title,
+ 'file_cover' => $this->file->coverUrl,
+ 'file_created_at' => $this->file->created_at->format('U'),
'content' => $this->content,
'page' => $this->page,
];
}
+
+ public function getCollectionSchema(): array
+ {
+ return [
+ 'name' => 'prod_searchable_texts',
+ 'fields' => [
+ [
+ 'name' => '.*',
+ ],
+ ],
+ 'default_sorting_field' => 'created_at',
+ ];
+ }
+
+ public function typesenseQueryBy(): array
+ {
+ return [
+ 'title',
+ ];
+ }
}
<?php
+use App\SearchableText;
+
return [
/*
'nodes' => [
[
'host' => env('TYPESENSE_HOST', 'localhost'),
- 'port' => env('TYPESENSE_PORT', '8108'),
- 'path' => env('TYPESENSE_PATH', ''),
- 'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
+ 'port' => '',
+ 'protocol' => env('TYPESENSE_PROTOCOL', 'https'),
],
],
'nearest_node' => [
'host' => env('TYPESENSE_HOST', 'localhost'),
- 'port' => env('TYPESENSE_PORT', '8108'),
+ 'port' => '',
'path' => env('TYPESENSE_PATH', ''),
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
],
'healthcheck_interval_seconds' => 30,
'num_retries' => 3,
'retry_interval_seconds' => 1,
+ 'model-settings' => [
+ User::class => [
+ 'collection-schema' => [
+ 'name' => 'prod_searchable_texts',
+ 'fields' => [
+ ['name' => 'id', 'type' => 'int32' ],
+ ['name' => 'file_slug', 'type' => 'string' ],
+ ['name' => 'file_tags', 'type' => 'string[]' ], // tableau de strings
+ ['name' => 'file_collection', 'type' => 'string' ],
+ ['name' => 'file_collection_slug','type' => 'string' ],
+ ['name' => 'file_visible', 'type' => 'bool' ],
+ ['name' => 'file_title', 'type' => 'string' ],
+ ['name' => 'file_cover', 'type' => 'string' ],
+ ['name' => 'file_created_at', 'type' => 'int64' ],
+ ['name' => 'content', 'type' => 'string' ],
+ ['name' => 'page', 'type' => 'int32' ],
+ ],
+ 'default_sorting_field' => 'id',
+ ],
+ 'search-parameters' => [
+ 'query_by' => 'email',
+ ],
+ ]
+ ],
],
-
];
window.Vue = require('vue');
/** @todo fix vue material design issue */
-
-
import 'selectize/dist/js/standalone/selectize.min.js';
import 'selectize/dist/css/selectize.css';
import '@fortawesome/fontawesome-free/css/all.min.css';
},
});
+$("#search").on("keydown", function(){
+ console.log($(this).val())
+})
+
document.addEventListener("DOMContentLoaded", () => {
const el = document.getElementById("openmenu")
el.addEventListener("click", () => {
<template>
<div class="card w-100">
- <img class="card-img-top" :src="hit.file.cover" alt="Cover">
+ <img class="card-img-top" :src="hit.coverUrl" alt="Cover">
<div class="card-body">
- <h5 class="card-title text-center" v-text="hit.file.title"></h5>
-
- <p class="card-text">
- <span class="badge badge-light mr-1" v-for="tag in hit.file.tags">
- <i class="fas fa-tag"></i> {{tag}}
- </span>
- </p>
- <p class="card-text">
- <ais-snippet attribute="content" :hit="hit" v-if="hit._highlightResult.content.matchLevel !== 'none'"/>
- </p>
+ <h5 class="card-title text-center" v-text="hit.title"></h5>
</div>
<a :href="viewLink" class="btn btn-big mb-0" target="_blank"><i class="fas fa-book-open mr-1"></i> Lire cette édition</a>
-
-
-
-
-
</div>
</template>
<template>
<div>
+ <template>
+ <ais-instant-search :search-client="searchClient" index-name="fluidbooks">
+ <ais-search-box/>
+ <ais-hits v-slot="{items}">
+ <div class="item-pdf-archive" v-for="item in items" :key="item.id">
+ <div class="cover">
+ <a class="img-link cursor-pointer" href="" target="_blank">
+ <img class="d-block cover-over box-shadow-cover" :src="item.document.coverUrl" alt="">
+ <div class="shadowcover">
+ <img class="max-h-[39px]" src="" />
+ </div>
+ </a>
+ <div class="cover-title text-left bg-transparent max-xs:!-mt-1">
+ <p class="font-bold bg-transparent">{{item.document.title}}</p>
+ <a href="" class="underline font-medium">Lire cette édition</a>
+ </div>
+ </div>
+ </div>
+ </ais-hits>
+ </ais-instant-search>
+ </template>
+ </div>
- <ais-instant-search
- :search-client="searchClient"
- :index-name="prefix+'searchable_texts'"
- >
- <ais-configure
- :hits-per-page.camel="12"
- :filters="filters"
- />
- <div class="row">
+</template>
+<script>
+import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter";
+import axios from "axios";
- <div class="col-md-12">
- <div class="px-3">
- <ais-search-box placeholder="Rechercher..." class="searchbox " />
+const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
+ server: {
+ apiKey: process.env.MIX_TYPESENSE_API_KEY,
+ nodes: [
+ {
+ host: process.env.MIX_TYPESENSE_HOST,
+ port: "",
+ protocol: "https",
+ },
+ ],
+ cacheSearchResultsForSeconds: 2 * 60,
+ },
+ additionalSearchParameters: {
+ query_by: "text",
+ },
+});
+const searchClient = typesenseInstantsearchAdapter.searchClient;
- </div>
- <ais-stats class="mt-2 ml-3"></ais-stats>
+const originalSearch = searchClient.search.bind(searchClient);
+searchClient.search = async function(queries) {
+ const startTime = performance.now();
- <div class="my-4">
- <ais-infinite-hits :class-names="{
- 'ais-InfiniteHits-list': 'row',
- 'ais-InfiniteHits-item' : 'col-sm-3 mb-3'
- }">
+ const tsResults = await originalSearch(queries);
+ const refs = tsResults.results[0].hits.map(h => h.reference)
+ const res = await axios.post("/retrieveLetter", { refs });
+ tsResults.results[0].hits = res.data.map(doc => ({ document: doc }));
- <file-hit
- slot="item"
- slot-scope="{item, index}"
- :key="index"
- :hit="item"
- >
- </file-hit>
+ const endTime = performance.now();
- <button
- slot="loadMore"
- slot-scope="{ page, isLastPage, refineNext }"
- :disabled="isLastPage"
- @click="refineNext"
- class="btn btn-big mt-5"
- >
- <i class="far fa-plus-square mr-1"></i>Voir plus
- </button>
- </ais-infinite-hits>
- </div>
- </div>
- </div>
- </ais-instant-search>
- </div>
+ const elapsedTime = endTime - startTime;
-</template>
+ console.log(`Le temps écoulé est de ${elapsedTime} ms`);
+
+ return tsResults;
+};
-<script>
-import Search from '../../mixins/SearchMixin';
export default {
- mixins: [Search],
data(){
return{
- filters: "file.collection_slug:'psq' AND file.visible:true"
+ searchClient
}
},
mounted(){
},
computed: {
-
- }
-
-
+ },
};
</script>
--- /dev/null
+<template>
+ <input v-model="text" class="color-blue w-100 outline-0 font-medium" type="text" placeholder="Recherche..."/>
+</template>
+<script>
+import Typesense from 'typesense'
+
+export default {
+ name: "Search",
+ data() {
+ return {
+ text: '',
+ client: null
+ }
+ },
+ watch: {
+ text(newText) {
+ console.log(newText)
+ let searchParameters = {
+ 'q' : newText,
+ 'query_by' : 'text',
+ 'per_page': 20,
+ 'page': 1
+ }
+ this.client.collections('fluidbooks')
+ .documents()
+ .search(searchParameters)
+ .then(function (searchResults) {
+ console.log(searchResults)
+ })
+ }
+ },
+ mounted() {
+ this.client = new Typesense.Client({
+ 'nodes': [{
+ 'host': process.env.MIX_TYPESENSE_HOST, // For Typesense Cloud use xxx.a1.typesense.net
+ 'port': '', // For Typesense Cloud use 443
+ 'protocol': 'https' // For Typesense Cloud use https
+ }],
+ 'apiKey': process.env.MIX_TYPESENSE_API_KEY,
+ 'connectionTimeoutSeconds': 3600
+ })
+ }
+}
+</script>
}),
computed: {
dimensions() {
-
-
-
return {
width: this.width,
height: Math.round(this.c_height)+'px'
@font-face {
font-family: 'Poppins';
- src: url('public/fonts/poppins/Poppins-SemiBold.woff2') format('woff2'),
- url('public/fonts/poppins/Poppins-SemiBold.woff') format('woff');
+ src: url('../../public/fonts/poppins/Poppins-SemiBold.woff2') format('woff2'),
+ url('../../public/fonts/poppins/Poppins-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
@font-face {
font-family: 'Poppins';
- src: url('public/fonts/poppins/Poppins-Medium.woff2') format('woff2'),
- url('public/fonts/poppins/Poppins-Medium.woff') format('woff');
+ src: url('../../public/fonts/poppins/Poppins-Medium.woff2') format('woff2'),
+ url('../../public/fonts/poppins/Poppins-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
@font-face {
font-family: 'Poppins';
- src: url('public/fonts/poppins/Poppins-Regular.woff2') format('woff2'),
- url('public/fonts/poppins/Poppins-Regular.woff') format('woff');
+ src: url('../../public/fonts/poppins/Poppins-Regular.woff2') format('woff2'),
+ url('../../public/fonts/poppins/Poppins-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
@font-face {
font-family: 'Poppins';
- src: url('public/fonts/poppins/Poppins-Bold.woff2') format('woff2'),
- url('public/fonts/poppins/Poppins-Bold.woff') format('woff');
+ src: url('../../public/fonts/poppins/Poppins-Bold.woff2') format('woff2'),
+ url('../../public/fonts/poppins/Poppins-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
@font-face {
font-family: 'Poppins';
- src: url('public/fonts/poppins/Poppins-Light.woff2') format('woff2'),
- url('public/fonts/poppins/Poppins-Light.woff') format('woff');
+ src: url('../../public/fonts/poppins/Poppins-Light.woff2') format('woff2'),
+ url('../../public/fonts/poppins/Poppins-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
font-display: swap;
}
.embla__viewport {
overflow: hidden;
+ max-width: 1280px;
}
.embla__container {
display: flex;
@import "tailwindcss";
@import 'mixins';
@import "ais";
-//@import "fonts";
+@import "fonts";
@import "colors";
@import "nav";
@import "footer";
<div>
<img src="{{ @asset('img/search_icon.svg') }}" alt="Lancer la recherche" />
</div>
- <input class="color-blue w-100 outline-0 font-medium" type="text" placeholder="Recherche..."/>
+ <!--<input class="color-blue w-100 outline-0 font-medium" type="text" placeholder="Recherche..."/>-->
</form>
</div>
</div>
@endsection
@section('main')
- <div class="container mb-16">
+ {{--<div class="container mb-16">
<div class="flex flex-wrap gap-x-[16px] md:gap-x-[32px] gap-y-7 md:gap-y-16">
@foreach($all_pdf as $key => $pdf)
<div class="item-pdf-archive">
</div>
@endforeach
</div>
- </div>
+ </div>--}}
+ <file-instant-search></file-instant-search>
@endsection
+
+<script>
+ import Search from "../../js/components/FileSearch/Search";
+ import FileInstantSearchSearch from "../../js/components/FileSearch/FileInstantSearch.vue";
+ export default {
+ components: {FileInstantSearchSearch}
+ }
+</script>
<div class="grid-1 gap-0">
<h1 class="bigtitle">{!! $settings->byKey('main_title') !!}</h1>
<p class="date !mt-6 xl:!mt-8">{{ ucfirst($last_pdf->first()->created_at->translatedFormat('l d F Y')) }}</p>
- <a href="/view/{{ $last_pdf->first()['slug'] }}" class="btnorange mt-4">Lire le quotidien</a>
+ {{-- /view/{{ $last_pdf->first()['slug'] }} --}}
+ <a href="https://hosting.fluidbook.com/psq-1952a" class="btnorange mt-4 {{ !Auth::check() ? 'notConnected' : '' }}" target="_blank">Lire le quotidien</a>
</div>
<x-cover :pdf="$last_pdf->first()" type="3" linkTo="read">
</x-cover>
<p class="font-semibold !mb-3">{!! $settings->byKey('subtitle_bloc_image_home') !!}</p>
{!! $settings->byKey('text_bloc_image_home') !!}
</div>
- <a href="#" class="linkunderline">{!! $settings->byKey('not_register_link') !!}</a>
+ <a href="{{ route('contact.subscribe') }}" class="linkunderline">{!! $settings->byKey('not_register_link') !!}</a>
</div>
</div>
<div class="w-full max-xl:h-[398px] xl:w-[384px] shrink-0 overflow-hidden bg-blue relative radius">
<div class="p-64 flex flex-col justify-between items-center pdf-block relative h-full z-1">
<h3 class="title-feuilleter regulartitle">{{ $settings->byKey('title_quotidien_home') }}</h3>
- <a href="/view/{{ $last_pdf->first()['slug'] }}" class="btnorange fw-normal relative">Feuilleter un quotidien</a>
+ {{-- /view/{{ $last_pdf->first()['slug'] }} --}}
+ <a href="https://hosting.fluidbook.com/psq-1952a" class="btnorange fw-normal relative" target="_blank">Feuilleter un quotidien</a>
</div>
<img class="absolute max-xl:h-full xl:w-100 left-1/2 top-[45%] xl:top-[48%] -translate-1/2" src="{{ asset('/img/quotidien.jpg') }}" alt="" />
</div>
Route::get('devenez-annonceurs', 'AdvertisersController@index')->name('annonceurs.index');
Route::post('devenez-annonceurs', 'AdvertisersController@requestMail')->name('annonceurs.store');
+
+ Route::post('retrieveLetter', 'Controller@getPdfBySlug');
});
/** Public routes + NGROK routes */