removed
This commit is contained in:
@@ -1,375 +0,0 @@
|
||||
<template>
|
||||
<router-link :to="to" class="sm-panel">
|
||||
<div v-if="image" class="sm-panel-image" :style="styleObject">
|
||||
<div v-if="dateInImage && date" class="sm-panel-image-date">
|
||||
<div class="sm-panel-image-date-day">
|
||||
{{ computedDay }}
|
||||
</div>
|
||||
<div class="sm-panel-image-date-month">
|
||||
{{ computedMonth }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm-panel-body">
|
||||
<h3 class="sm-panel-title">{{ title }}</h3>
|
||||
<div v-if="showDate && date" class="sm-panel-date">
|
||||
<ion-icon
|
||||
v-if="showTime == false && endDate.length == 0"
|
||||
name="calendar-outline"
|
||||
class="icon" />
|
||||
<ion-icon v-else name="time-outline" class="icon" />
|
||||
<p>{{ computedDate }}</p>
|
||||
</div>
|
||||
<div v-if="location" class="sm-panel-location">
|
||||
<ion-icon class="icon" name="location-outline" />
|
||||
<p>{{ location }}</p>
|
||||
</div>
|
||||
<div v-if="ages" class="sm-panel-ages">
|
||||
<ion-icon class="icon" name="body-outline" />
|
||||
<p>{{ ages }}</p>
|
||||
</div>
|
||||
<div v-if="price" class="sm-panel-price">
|
||||
<span class="icon">$</span>
|
||||
<p>{{ computedPrice }}</p>
|
||||
</div>
|
||||
<div v-if="content" class="sm-panel-content">
|
||||
{{ computedContent }}
|
||||
</div>
|
||||
<div v-if="button.length > 0" class="sm-panel-button">
|
||||
<SMButton
|
||||
:to="to"
|
||||
:type="buttonType"
|
||||
:block="true"
|
||||
:label="button" />
|
||||
</div>
|
||||
<div
|
||||
v-if="banner"
|
||||
:class="['sm-panel-banner', `sm-panel-banner-${bannerType}`]">
|
||||
{{ banner }}
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import { SMDate } from "../helpers/datetime";
|
||||
import {
|
||||
excerpt,
|
||||
replaceHtmlEntites,
|
||||
stringToNumber,
|
||||
stripHtmlTags,
|
||||
} from "../helpers/string";
|
||||
import SMButton from "./SMButton.vue";
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: true,
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
to: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
dateInImage: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
required: false,
|
||||
},
|
||||
showTime: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
showDate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
required: false,
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
button: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
buttonType: {
|
||||
type: String,
|
||||
default: "primary",
|
||||
required: false,
|
||||
},
|
||||
banner: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
bannerType: {
|
||||
type: String,
|
||||
default: "primary",
|
||||
required: false,
|
||||
},
|
||||
price: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
ages: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
let styleObject = {
|
||||
backgroundImage: `url('${props.image}')`,
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a human readable date based on props.date and props.endDate.
|
||||
*/
|
||||
const computedDate = computed(() => {
|
||||
let str = "";
|
||||
|
||||
if (props.date.length > 0) {
|
||||
if (
|
||||
(props.endDate.length > 0 &&
|
||||
props.date.substring(0, props.date.indexOf(" ")) !=
|
||||
props.endDate.substring(0, props.endDate.indexOf(" "))) ||
|
||||
props.showTime == false
|
||||
) {
|
||||
str = new SMDate(props.date, { format: "yMd" }).format(
|
||||
"dd/MM/yyyy"
|
||||
);
|
||||
if (props.endDate.length > 0) {
|
||||
str =
|
||||
str +
|
||||
" - " +
|
||||
new SMDate(props.endDate, { format: "yMd" }).format(
|
||||
"dd/MM/yyyy"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
str = new SMDate(props.date, { format: "yMd" }).format(
|
||||
"dd/MM/yyyy @ h:mm aa"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the content string cleaned from HTML.
|
||||
*/
|
||||
const computedContent = computed(() => {
|
||||
return excerpt(replaceHtmlEntites(stripHtmlTags(props.content)), 200);
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a computed day number from props.date
|
||||
*/
|
||||
const computedDay = computed(() => {
|
||||
return new SMDate(props.date, { format: "yMd" }).format("dd");
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a computed month name from props.date
|
||||
*/
|
||||
const computedMonth = computed(() => {
|
||||
return new SMDate(props.date, { format: "yMd" }).format("MMM");
|
||||
});
|
||||
|
||||
/**
|
||||
* Return a computed price amount, if a form of 0, return "Free"
|
||||
*/
|
||||
const computedPrice = computed(() => {
|
||||
const parsedPrice = stringToNumber(props.price);
|
||||
if (parsedPrice == 0) {
|
||||
return "Free";
|
||||
}
|
||||
|
||||
return props.price;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sm-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 28px rgba(0, 0, 0, 0.05);
|
||||
max-width: 21rem;
|
||||
width: 100%;
|
||||
color: $font-color !important;
|
||||
margin-bottom: map-get($spacer, 5);
|
||||
transition: box-shadow 0.2s ease-in-out;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
color: $font-color;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 0 14px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.sm-panel-image {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: map-get($spacer, 5) * 4;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
background-color: #eee;
|
||||
|
||||
.sm-panel-image-loader {
|
||||
font-size: 5rem;
|
||||
color: $secondary-color;
|
||||
}
|
||||
|
||||
.sm-panel-image-date {
|
||||
background-color: #fff;
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 4px 4px 15px rgba(0, 0, 0, 0.2);
|
||||
text-align: center;
|
||||
|
||||
.sm-panel-image-date-day {
|
||||
font-weight: bold;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
.sm-panel-image-date-month {
|
||||
text-transform: uppercase;
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sm-panel-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 0 map-get($spacer, 3) map-get($spacer, 3) map-get($spacer, 3);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.sm-panel-title {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sm-panel-date,
|
||||
.sm-panel-location,
|
||||
.sm-panel-price,
|
||||
.sm-panel-ages {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: top;
|
||||
font-size: 80%;
|
||||
margin-bottom: 0rem;
|
||||
|
||||
.icon {
|
||||
flex: 0 1 1rem;
|
||||
margin-right: map-get($spacer, 1);
|
||||
padding-top: 0.1rem;
|
||||
height: 1rem;
|
||||
padding: 0.25rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sm-panel-content {
|
||||
margin-top: 1rem;
|
||||
line-height: 130%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sm-panel-button {
|
||||
margin-top: map-get($spacer, 4);
|
||||
}
|
||||
|
||||
.sm-panel-banner {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
top: 65px;
|
||||
right: -10px;
|
||||
height: 20px;
|
||||
width: 120px;
|
||||
font-size: 70%;
|
||||
text-transform: uppercase;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
background-color: $primary-color;
|
||||
transform-origin: 100%;
|
||||
transform: rotateZ(45deg);
|
||||
|
||||
&.sm-panel-banner-success {
|
||||
background-color: $success-color;
|
||||
}
|
||||
|
||||
&.sm-panel-banner-danger {
|
||||
background-color: $danger-color;
|
||||
font-size: 60%;
|
||||
}
|
||||
|
||||
&.sm-panel-banner-warning {
|
||||
background-color: $warning-color-darker;
|
||||
color: $font-color;
|
||||
font-size: 60%;
|
||||
}
|
||||
|
||||
&.sm-panel-banner-expired {
|
||||
background-color: purple;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<div class="sm-panel-list">
|
||||
<div v-if="loading" class="sm-panel-list-loading">
|
||||
<SMLoadingIcon />
|
||||
</div>
|
||||
<div v-else-if="notFound" class="sm-panel-list-not-found">
|
||||
<ion-icon name="alert-circle-outline" />
|
||||
<p>{{ notFoundText }}</p>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SMLoadingIcon from "./SMLoadingIcon.vue";
|
||||
|
||||
defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
notFound: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
notFoundText: {
|
||||
type: String,
|
||||
default: "No items found",
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sm-panel-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
.sm-panel-list-loading {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sm-panel-list-not-found {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
ion-icon {
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
font-size: 130%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user