forked from cms/tibi-svelte-starter
Erste kleine Anpassungen am Tibi-Svelte-Starter um später mehr Zeit in neuen Projekten zu sparen. Hier werden noch weitere Anpassungen folgen, die grundlegend in den meisten Projekten benötigt werden.
This commit is contained in:
parent
75a8906d4a
commit
5caa62eb7e
10
.prettierrc
10
.prettierrc
@ -1,16 +1,18 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 80,
|
"printWidth": 120,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"newline-before-return": true,
|
"newline-before-return": true,
|
||||||
"no-duplicate-variable": [true, "check-parameters"],
|
"no-duplicate-variable": [
|
||||||
|
true,
|
||||||
|
"check-parameters"
|
||||||
|
],
|
||||||
"no-var-keyword": true,
|
"no-var-keyword": true,
|
||||||
|
|
||||||
"svelteSortOrder": "scripts-styles-markup",
|
"svelteSortOrder": "scripts-styles-markup",
|
||||||
"svelteStrictMode": true,
|
"svelteStrictMode": true,
|
||||||
"svelteBracketNewLine": true,
|
"svelteBracketNewLine": true,
|
||||||
"svelteAllowShorthand": true,
|
"svelteAllowShorthand": true,
|
||||||
"svelteIndentScriptAndStyle": true
|
"svelteIndentScriptAndStyle": true
|
||||||
}
|
}
|
150
api/collections/articles.yml
Normal file
150
api/collections/articles.yml
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
########################################################################
|
||||||
|
# Articles
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
name: articles
|
||||||
|
uploadPath: ../media/articles
|
||||||
|
meta:
|
||||||
|
# Navigationseintrag in der Admin-UI
|
||||||
|
label: { de: "Artikel auf der Seite", en: "Page articles" }
|
||||||
|
# Icon (Material UI) für den Navigationseintrag
|
||||||
|
muiIcon: file-document-edit-outline
|
||||||
|
# Standardsortierung der Liste
|
||||||
|
defaultSort: { field: "name", order: "ASC" }
|
||||||
|
# Admin-Backend Ansichten
|
||||||
|
defaultImageFilter: s
|
||||||
|
views:
|
||||||
|
# Mobile Darstellung
|
||||||
|
- type: simpleList
|
||||||
|
mediaQuery: "(max-width:599px)"
|
||||||
|
primaryText: path
|
||||||
|
columns:
|
||||||
|
- public
|
||||||
|
- image
|
||||||
|
- title
|
||||||
|
- position
|
||||||
|
# Desktop
|
||||||
|
- type: table
|
||||||
|
mediaQuery: "(min-width:600px)"
|
||||||
|
columns:
|
||||||
|
- public
|
||||||
|
- image
|
||||||
|
- title
|
||||||
|
- position
|
||||||
|
|
||||||
|
imageFilter:
|
||||||
|
xs:
|
||||||
|
- fit: true
|
||||||
|
height: 90
|
||||||
|
width: 90
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
s:
|
||||||
|
- fit: true
|
||||||
|
height: 300
|
||||||
|
width: 300
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
m:
|
||||||
|
- fit: true
|
||||||
|
height: 600
|
||||||
|
width: 600
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
l:
|
||||||
|
- fit: true
|
||||||
|
height: 1200
|
||||||
|
width: 1200
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
xl:
|
||||||
|
- fit: true
|
||||||
|
height: 2000
|
||||||
|
width: 2000
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
public:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
user:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: true
|
||||||
|
delete: true
|
||||||
|
# token als Zusatzsicherung gegen Spam, mehr siehe Hook
|
||||||
|
"token:${PUBLIC_TOKEN}":
|
||||||
|
methods:
|
||||||
|
get: false
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
|
||||||
|
# hooks:
|
||||||
|
# post:
|
||||||
|
# create:
|
||||||
|
# type: javascript
|
||||||
|
# file: hooks/article/post_create.js
|
||||||
|
# put:
|
||||||
|
# update:
|
||||||
|
# type: javascript
|
||||||
|
# file: hooks/article/put_return.js
|
||||||
|
# delete:
|
||||||
|
# return:
|
||||||
|
# type: javascript
|
||||||
|
# file: hooks/article/delete_return.js
|
||||||
|
|
||||||
|
fields:
|
||||||
|
- name: articleTabs
|
||||||
|
type: tabs
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Informationen zu einem Artikel
|
||||||
|
en: Article Information
|
||||||
|
activeTab: 0
|
||||||
|
subFields:
|
||||||
|
- name: articleTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Artikel
|
||||||
|
en: Article
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: articleLayoutTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Layout
|
||||||
|
en: Layout
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: articleMediaTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Bilder
|
||||||
|
en: Images
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: articleAttachmentsTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Anhänge / Downloads
|
||||||
|
en: Attachments / Downloads
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: articleMetaTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Meta
|
||||||
|
en: Meta
|
||||||
|
css:
|
||||||
|
subFields:
|
306
api/collections/general.yml
Normal file
306
api/collections/general.yml
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
########################################################################
|
||||||
|
# General Information
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
name: general
|
||||||
|
uploadPath: ../media/general
|
||||||
|
meta:
|
||||||
|
# Navigationseintrag in der Admin-UI
|
||||||
|
label: { de: "Allgemeine Informationen", en: "General Information" }
|
||||||
|
# Icon (Material UI) für den Navigationseintrag
|
||||||
|
muiIcon: information-outline
|
||||||
|
# Identifizierung eines Eintrags für z.B. Select-Boxen in der Admin-UI
|
||||||
|
rowIdentTpl: { twig: "{{ email }} - {{ subject }}" }
|
||||||
|
# Standardsortierung der Liste
|
||||||
|
defaultSort: { field: "path", order: "ASC" }
|
||||||
|
# Admin-Backend Ansichten
|
||||||
|
defaultImageFilter: s
|
||||||
|
views:
|
||||||
|
# Mobile Darstellung
|
||||||
|
- type: simpleList
|
||||||
|
mediaQuery: "(max-width:599px)"
|
||||||
|
primaryText: firstname
|
||||||
|
columns:
|
||||||
|
- public
|
||||||
|
- firstname
|
||||||
|
- lastname
|
||||||
|
- companyName
|
||||||
|
# Desktop
|
||||||
|
- type: table
|
||||||
|
mediaQuery: "(min-width:600px)"
|
||||||
|
columns:
|
||||||
|
- public
|
||||||
|
- firstname
|
||||||
|
- lastname
|
||||||
|
- companyName
|
||||||
|
|
||||||
|
imageFilter:
|
||||||
|
xs:
|
||||||
|
- fit: true
|
||||||
|
height: 90
|
||||||
|
width: 90
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
s:
|
||||||
|
- fit: true
|
||||||
|
height: 300
|
||||||
|
width: 300
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
m:
|
||||||
|
- fit: true
|
||||||
|
height: 600
|
||||||
|
width: 600
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
l:
|
||||||
|
- fit: true
|
||||||
|
height: 1200
|
||||||
|
width: 1200
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
xl:
|
||||||
|
- fit: true
|
||||||
|
height: 2000
|
||||||
|
width: 2000
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
public:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
user:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: true
|
||||||
|
delete: true
|
||||||
|
# token als Zusatzsicherung gegen Spam, mehr siehe Hook
|
||||||
|
"token:${PUBLIC_TOKEN}":
|
||||||
|
methods:
|
||||||
|
get: false
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
|
||||||
|
fields:
|
||||||
|
- name: generalInformationTabs
|
||||||
|
type: tabs
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Allgemeine Information
|
||||||
|
en: General Information
|
||||||
|
activeTab: 0
|
||||||
|
subFields:
|
||||||
|
- name: generalInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Allgemein
|
||||||
|
en: General
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: public
|
||||||
|
type: boolean
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Veröffentlicht
|
||||||
|
en: Public
|
||||||
|
helperText:
|
||||||
|
de: "Alle allgemeinen Informationen werden auf der Seite angezeigt."
|
||||||
|
en: "All general information are displayed on the page."
|
||||||
|
- name: metaInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Meta / SEO
|
||||||
|
en: Meta / SEO
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: metaTitle
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Titel der Webseite", en: "Page Title" }
|
||||||
|
- name: metaDescription
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Beschreibung der Webseite", en: "Page Description" }
|
||||||
|
- name: metaTagRobots
|
||||||
|
type: string[]
|
||||||
|
meta:
|
||||||
|
widget: chipArray
|
||||||
|
label:
|
||||||
|
de: Robots
|
||||||
|
en: Robots
|
||||||
|
inputProps:
|
||||||
|
placeholder: "nofollow"
|
||||||
|
defaultValue: []
|
||||||
|
autocomplete: true
|
||||||
|
choices:
|
||||||
|
- { id: "noindex", name: "noindex" }
|
||||||
|
- { id: "index", name: "index" }
|
||||||
|
- { id: "follow", name: "follow" }
|
||||||
|
- { id: "nofollow", name: "nofollow" }
|
||||||
|
- { id: "noimageindex", name: "noimageindex" }
|
||||||
|
- { id: "none", name: "none" }
|
||||||
|
- { id: "noarchive", name: "noarchive" }
|
||||||
|
- { id: "nocache", name: "nocache" }
|
||||||
|
- { id: "nosnippet", name: "nosnippet" }
|
||||||
|
- { id: "nnavailable_after", name: "nnavailable_after" }
|
||||||
|
helperText:
|
||||||
|
de: "<strong>Noindex</strong>: Weist eine Suchmaschine an, eine Seite nicht zu indizieren.<br/><strong>index</strong>: Weist eine Suchmaschine an, eine Seite zu indizieren. Beachten Sie, dass Sie dieses Meta-Tag nicht hinzufügen müssen; es ist die Voreinstellung.<br/><strong>follow</strong>: Auch wenn die Seite nicht indexiert ist, sollte der Crawler allen Links auf einer Seite folgen und Eigenkapital an die verlinkten Seiten weitergeben.<br/><strong>nofollow</strong>: Weist einen Crawler an, keinen Links auf einer Seite zu folgen oder Link-Equity weiterzugeben.<br/><strong>noimageindex</strong>: Weist einen Crawler an, keine Bilder auf einer Seite zu indizieren.<br/><strong>none</strong>: Entspricht der gleichzeitigen Verwendung der noindex- und nofollow-Tags.<br/><strong>noarchive</strong>: Suchmaschinen sollten keinen zwischengespeicherten Link zu dieser Seite auf einem SERP anzeigen.<br/><strong>nocache</strong>: Wie noarchive, aber nur von Internet Explorer und Firefox verwendet.<br/><strong>nosnippet</strong>: Weist eine Suchmaschine an, kein Snippet dieser Seite (d. h. Meta-Beschreibung) dieser Seite auf einem SERP anzuzeigen.<br/><strong>nnavailable_after</strong>: Suchmaschinen sollen diese Seite nach einem bestimmten Datum nicht mehr indexieren.<br/>"
|
||||||
|
en: "<strong>Noindex</strong>: Tells a search engine not to index a page.<br/><strong>index</strong>: Tells a search engine to index a page. Note that you don’t need to add this meta tag; it’s the default.<br/><strong>follow</strong>: Even if the page isn’t indexed, the crawler should follow all the links on a page and pass equity to the linked pages.<br/><strong>nofollow</strong>: Tells a crawler not to follow any links on a page or pass along any link equity.<br/><strong>noimageindex</strong>: Tells a crawler not to index any images on a page.<br/><strong>none</strong>: Equivalent to using both the noindex and nofollow tags simultaneously.<br/><strong>noarchive</strong>: Search engines should not show a cached link to this page on a SERP.<br/><strong>nocache</strong>: Same as noarchive, but only used by Internet Explorer and Firefox.<br/><strong>nosnippet</strong>: Tells a search engine not to show a snippet of this page (i.e. meta description) of this page on a SERP.<br/><strong>nnavailable_after</strong>: Search engines should no longer index this page after a particular date.<br/>"
|
||||||
|
- name: metaKeywords
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "SEO / Schlüsselwörter", en: "SEO / Keywords" }
|
||||||
|
helperText:
|
||||||
|
de: "Beispiel: Stichwort1, Stichwort2, Stichwort3"
|
||||||
|
en: "Example: keyword1, keyword2, keyword3"
|
||||||
|
- name: personalInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Personendaten
|
||||||
|
en: Personal Data
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: firstname
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Vorname", en: "Firstname" }
|
||||||
|
- name: lastname
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Nachname", en: "Lastname" }
|
||||||
|
- name: street
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Straße", en: "Street" }
|
||||||
|
- name: postcode
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Postleitzahl", en: "Postcode" }
|
||||||
|
- name: city
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Ort", en: "City" }
|
||||||
|
- name: tel
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Telefonnummer", en: "Phone number" }
|
||||||
|
- name: mobile
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Handynummer", en: "Mobile number" }
|
||||||
|
- name: email
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "E-Mail", en: "E-Mail" }
|
||||||
|
- name: companyInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Unternehmensdaten
|
||||||
|
en: Company Data
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: companyName
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Name des Unternehmens", en: "Company Name" }
|
||||||
|
- name: companyWebUrl
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "URL zur Webseite", en: "Website URL" }
|
||||||
|
- name: companyAddresses
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Adresse
|
||||||
|
en: Adresse
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: street
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Straße", en: "Street" }
|
||||||
|
- name: houseNr
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Hausnummer", en: "House number" }
|
||||||
|
- name: postcode
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "PLZ", en: "ZIP" }
|
||||||
|
- name: city
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Ort", en: "City" }
|
||||||
|
- name: tel
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Telefon", en: "Phone number" }
|
||||||
|
- name: fax
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Fax", en: "Fax" }
|
||||||
|
- name: email
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "E-Mail", en: "E-Mail" }
|
||||||
|
- name: mediaInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Media
|
||||||
|
en: Media
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: favicon
|
||||||
|
type: file
|
||||||
|
meta:
|
||||||
|
label: { de: "Favicon", en: "Favicon" }
|
||||||
|
helperText:
|
||||||
|
de: "Ein Favicon ist ein kleines Icon, Symbol oder Logo, das von Webbrowsern verwendet wird, um eine Website auf wiedererkennbare Weise zu kennzeichnen."
|
||||||
|
en: "A favicon is a small icon, symbol, or logo used by web browsers to identify a website in a recognizable way."
|
||||||
|
- name: favicon
|
||||||
|
type: file
|
||||||
|
meta:
|
||||||
|
label: { de: "Logo / Brand", en: "Logo / Brand" }
|
||||||
|
helperText:
|
||||||
|
de: "Logo der Seite"
|
||||||
|
en: "Page Logo"
|
||||||
|
- name: mediaFiles
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label: { de: "Dateien", en: "Files" }
|
||||||
|
subFields:
|
||||||
|
- name: title
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Datei-Titel", en: "File Title" }
|
||||||
|
- name: id
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Technischer Name / ID", en: "Technical name / ID" }
|
||||||
|
- name: file
|
||||||
|
type: file
|
||||||
|
meta:
|
||||||
|
label: { de: "", en: "" }
|
||||||
|
- name: copyrightInformationTab
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Copyright
|
||||||
|
en: Copyright
|
||||||
|
css:
|
||||||
|
subFields:
|
||||||
|
- name: copyright
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label: { de: "Copyright Text", en: "Copyright Text" }
|
@ -7,6 +7,8 @@ meta:
|
|||||||
|
|
||||||
# Liste aller möglichen Kollektionen (Listen, Seiten...) zum Projekt
|
# Liste aller möglichen Kollektionen (Listen, Seiten...) zum Projekt
|
||||||
collections:
|
collections:
|
||||||
|
- !include collections/general.yml
|
||||||
|
- !include collections/articles.yml
|
||||||
- !include collections/content.yml
|
- !include collections/content.yml
|
||||||
- !include collections/contact_form.yml
|
- !include collections/contact_form.yml
|
||||||
- !include collections/ssr.yml
|
- !include collections/ssr.yml
|
||||||
|
@ -5,8 +5,7 @@ const resolvePlugin = {
|
|||||||
// url in css does not resolve via esbuild-svelte correctly
|
// url in css does not resolve via esbuild-svelte correctly
|
||||||
build.onResolve({ filter: /.*/, namespace: "fakecss" }, (args) => {
|
build.onResolve({ filter: /.*/, namespace: "fakecss" }, (args) => {
|
||||||
// console.log(args)
|
// console.log(args)
|
||||||
if (args.path.match(/^\./))
|
if (args.path.match(/^\./)) return { path: path.dirname(args.importer) + "/" + args.path }
|
||||||
return { path: path.dirname(args.importer) + "/" + args.path }
|
|
||||||
// return { path: path.join(args.resolveDir, "public", args.path) }
|
// return { path: path.join(args.resolveDir, "public", args.path) }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -54,6 +53,8 @@ const options = {
|
|||||||
".eot": "file",
|
".eot": "file",
|
||||||
".svg": "file",
|
".svg": "file",
|
||||||
".ttf": "file",
|
".ttf": "file",
|
||||||
|
".png": "file",
|
||||||
|
".jpg": "file",
|
||||||
},
|
},
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
||||||
@ -63,9 +64,7 @@ const bsMiddleware = []
|
|||||||
|
|
||||||
if (process.argv[2] == "start") {
|
if (process.argv[2] == "start") {
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware")
|
const { createProxyMiddleware } = require("http-proxy-middleware")
|
||||||
const apiBase =
|
const apiBase = process.env.API_BASE || "http://localhost:8080/api/v1/_/" + process.env.NAMESPACE
|
||||||
process.env.API_BASE ||
|
|
||||||
"http://localhost:8080/api/v1/_/" + process.env.NAMESPACE
|
|
||||||
bsMiddleware.push(
|
bsMiddleware.push(
|
||||||
createProxyMiddleware("/api", {
|
createProxyMiddleware("/api", {
|
||||||
target: apiBase,
|
target: apiBase,
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"validate": "svelte-check && tsc --noEmit",
|
"validate": "svelte-check && tsc --noEmit",
|
||||||
"start": "node scripts/esbuild-wrapper.js start",
|
"start": "NAMESPACE=__NAMESPACE__ node scripts/esbuild-wrapper.js start",
|
||||||
"start:localapi": "API_BASE=http://localhost:8080 node scripts/esbuild-wrapper.js start",
|
"start:remoteapi": "API_BASE=https://login.tibicms.de/api/v1/_/__NAMESPACE__ node scripts/esbuild-wrapper.js start",
|
||||||
"dev": "node scripts/esbuild-wrapper.js watch",
|
"dev": "node scripts/esbuild-wrapper.js watch",
|
||||||
"build": "node scripts/esbuild-wrapper.js build",
|
"build": "node scripts/esbuild-wrapper.js build",
|
||||||
"build:legacy": "node scripts/esbuild-wrapper.js build esbuild.config.legacy.js && babel _temp/index.js -o _temp/index.babeled.js && esbuild _temp/index.babeled.js --outfile=dist/_dist_/index.es5.js --target=es5 --bundle --minify --sourcemap",
|
"build:legacy": "node scripts/esbuild-wrapper.js build esbuild.config.legacy.js && babel _temp/index.js -o _temp/index.babeled.js && esbuild _temp/index.babeled.js --outfile=dist/_dist_/index.es5.js --target=es5 --bundle --minify --sourcemap",
|
||||||
@ -62,4 +62,4 @@
|
|||||||
"live-server": "^1.2.1",
|
"live-server": "^1.2.1",
|
||||||
"mongodb": "^4.3.1"
|
"mongodb": "^4.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
48
src/api.ts
48
src/api.ts
@ -43,9 +43,7 @@ const _f = function (url, options): Promise<Response> {
|
|||||||
.replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => {
|
.replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => {
|
||||||
keys.push((key = key.toLowerCase()))
|
keys.push((key = key.toLowerCase()))
|
||||||
all.push([key, value])
|
all.push([key, value])
|
||||||
headers[key] = headers[key]
|
headers[key] = headers[key] ? `${headers[key]},${value}` : value
|
||||||
? `${headers[key]},${value}`
|
|
||||||
: value
|
|
||||||
})
|
})
|
||||||
resolve(response())
|
resolve(response())
|
||||||
}
|
}
|
||||||
@ -62,12 +60,7 @@ const _f = function (url, options): Promise<Response> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const _fetch =
|
const _fetch = typeof fetch === "undefined" ? (typeof window === "undefined" ? _f : window.fetch || _f) : fetch
|
||||||
typeof fetch === "undefined"
|
|
||||||
? typeof window === "undefined"
|
|
||||||
? _f
|
|
||||||
: window.fetch || _f
|
|
||||||
: fetch
|
|
||||||
|
|
||||||
export const api = async <T>(
|
export const api = async <T>(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
@ -107,8 +100,7 @@ export const api = async <T>(
|
|||||||
let method = "GET"
|
let method = "GET"
|
||||||
|
|
||||||
let query = "&count=1"
|
let query = "&count=1"
|
||||||
if (options?.filter)
|
if (options?.filter) query += "&filter=" + encodeURIComponent(JSON.stringify(options.filter))
|
||||||
query += "&filter=" + encodeURIComponent(JSON.stringify(options.filter))
|
|
||||||
if (options?.sort) query += "&sort=" + options.sort + "&sort=_id"
|
if (options?.sort) query += "&sort=" + options.sort + "&sort=_id"
|
||||||
if (options?.limit) query += "&limit=" + options.limit
|
if (options?.limit) query += "&limit=" + options.limit
|
||||||
if (options?.offset) query += "&offset=" + options.offset
|
if (options?.offset) query += "&offset=" + options.offset
|
||||||
@ -149,8 +141,7 @@ export const api = async <T>(
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let data = (await response?.json()) || null
|
let data = (await response?.json()) || null
|
||||||
|
|
||||||
if (response?.status < 200 || response?.status >= 400)
|
if (response?.status < 200 || response?.status >= 400) throw { response, data }
|
||||||
throw { response, data }
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return { data, count: response?.headers?.get("x-results-count") || 0 }
|
return { data, count: response?.headers?.get("x-results-count") || 0 }
|
||||||
@ -163,3 +154,34 @@ export const getContent = async (path: string): Promise<Content> => {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getGeneralInformation = async (): Promise<GeneralInformation[]> => {
|
||||||
|
try {
|
||||||
|
let response = await api<GeneralInformation[]>("general", {
|
||||||
|
method: "get",
|
||||||
|
offset: 0,
|
||||||
|
limit: 1,
|
||||||
|
filter: {
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return response.data
|
||||||
|
} catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getArticles = async (): Promise<TibiArticle[]> => {
|
||||||
|
try {
|
||||||
|
let response = await api<TibiArticle[]>("articles", {
|
||||||
|
method: "get",
|
||||||
|
offset: 0,
|
||||||
|
filter: {
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return response.data
|
||||||
|
} catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
35
src/store.ts
35
src/store.ts
@ -1,4 +1,5 @@
|
|||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
import { getGeneralInformation, getArticles } from "./api"
|
||||||
|
|
||||||
const initLoc = {
|
const initLoc = {
|
||||||
path: (typeof window !== "undefined" && window.location?.pathname) || "/",
|
path: (typeof window !== "undefined" && window.location?.pathname) || "/",
|
||||||
@ -10,3 +11,37 @@ const initLoc = {
|
|||||||
initLoc.categoryPath = initLoc.path.replace(/\/\d{4,99}[^\/]+$/, "")
|
initLoc.categoryPath = initLoc.path.replace(/\/\d{4,99}[^\/]+$/, "")
|
||||||
|
|
||||||
export const location = writable(initLoc)
|
export const location = writable(initLoc)
|
||||||
|
|
||||||
|
// General Information
|
||||||
|
|
||||||
|
export const generalInformation = writable<GeneralInformation>()
|
||||||
|
const getGeneralProjectInformation = async () => {
|
||||||
|
const infos = await getGeneralInformation()
|
||||||
|
if (infos && infos.length) {
|
||||||
|
generalInformation.set(infos[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getGeneralProjectInformation()
|
||||||
|
|
||||||
|
// Articles
|
||||||
|
|
||||||
|
export const articles = writable<TibiArticle[]>()
|
||||||
|
const getAllArticles = async () => {
|
||||||
|
const list = await getArticles()
|
||||||
|
articles.set(list)
|
||||||
|
}
|
||||||
|
getAllArticles()
|
||||||
|
|
||||||
|
// Cookies - Webmakers Cookie Bar
|
||||||
|
|
||||||
|
export const ccTags = writable<string[]>([])
|
||||||
|
|
||||||
|
const updateCcTtags = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
ccTags.set(window.ccLoadedTags || [])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.addEventListener("ccInit", updateCcTtags)
|
||||||
|
window.addEventListener("ccAccept", updateCcTtags)
|
||||||
|
}
|
||||||
|
45
types/global.d.ts
vendored
45
types/global.d.ts
vendored
@ -8,9 +8,52 @@ interface ContentBlock {
|
|||||||
images?: ImageEntry[]
|
images?: ImageEntry[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface Content {
|
interface Content {
|
||||||
id: string
|
id: string
|
||||||
path: string
|
path: string
|
||||||
blocks: ContentBlock[]
|
blocks: ContentBlock[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GeneralInformation {
|
||||||
|
id: string
|
||||||
|
active: boolean
|
||||||
|
firstname: string
|
||||||
|
lastname: string
|
||||||
|
street: string
|
||||||
|
postcode: number
|
||||||
|
city: string
|
||||||
|
tel: string
|
||||||
|
mobile: string
|
||||||
|
email: string
|
||||||
|
images: GeneralImage[]
|
||||||
|
insertTime: string
|
||||||
|
updateTime: string
|
||||||
|
lastPageUpdate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneralImage {
|
||||||
|
file: File[]
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TibiArticle {
|
||||||
|
id: string
|
||||||
|
active: boolean
|
||||||
|
content: string
|
||||||
|
details: string
|
||||||
|
image: File
|
||||||
|
insertTime: string
|
||||||
|
position: string
|
||||||
|
subtitle: string
|
||||||
|
title: string
|
||||||
|
updateTime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface File {
|
||||||
|
lastModified?: number
|
||||||
|
path: string
|
||||||
|
size?: string
|
||||||
|
src: string
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user