lots o updates
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
DB::table('users')->whereNull('phone')->update(['phone' => '']);
|
||||||
|
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('phone')->default("")->nullable(false)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('phone')->nullable(true)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('display_name')->default("");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update existing rows with display_name
|
||||||
|
DB::table('users')->select('id', 'username')->orderBy('id')->chunk(100, function ($users) {
|
||||||
|
foreach ($users as $user) {
|
||||||
|
DB::table('users')->where('id', $user->id)->update(['display_name' => $user->username]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('display_name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -79,6 +79,13 @@ a:visited {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
li,
|
||||||
|
.html {
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
@@ -91,30 +98,6 @@ li {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
font-family: var(--header-font-family);
|
|
||||||
font-weight: 800;
|
|
||||||
padding: 16px 32px 16px 32px;
|
|
||||||
border: 0;
|
|
||||||
background-color: var(--base-color-light);
|
|
||||||
-webkit-backdrop-filter: blur(4px);
|
|
||||||
backdrop-filter: blur(4px);
|
|
||||||
color: var(--link-color);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
filter: brightness(85%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Who knows why ion-icon randomally sets this to hidden.....
|
// Who knows why ion-icon randomally sets this to hidden.....
|
||||||
// ion-icon {
|
// ion-icon {
|
||||||
// visibility: visible;
|
// visibility: visible;
|
||||||
@@ -190,23 +173,23 @@ li {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// /* SM Dialog */
|
/* SM Dialog */
|
||||||
// .sm-dialog-outer {
|
.dialog-outer {
|
||||||
// position: fixed;
|
position: fixed;
|
||||||
// display: flex;
|
display: flex;
|
||||||
// top: 0;
|
top: 0;
|
||||||
// left: 0;
|
left: 0;
|
||||||
// bottom: 0;
|
bottom: 0;
|
||||||
// right: 0;
|
right: 0;
|
||||||
// flex-direction: column;
|
flex-direction: column;
|
||||||
// align-items: center;
|
align-items: center;
|
||||||
// justify-content: center;
|
justify-content: center;
|
||||||
// z-index: 1000;
|
z-index: 1000;
|
||||||
// padding: 1rem;
|
padding: 1rem;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// .sm-dialog-outer:last-of-type {
|
.dialog-outer:last-of-type {
|
||||||
// background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
// backdrop-filter: blur(2px);
|
backdrop-filter: blur(2px);
|
||||||
// -webkit-backdrop-filter: blur(2px);
|
-webkit-backdrop-filter: blur(2px);
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
:root {
|
:root {
|
||||||
// yes
|
// yes
|
||||||
--default-font-size: 18px;
|
--default-font-size: 18px;
|
||||||
--default-font-family: "Nunito", "Nunito override", "Arial", "Helvetica",
|
--default-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
sans-serif;
|
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
// --default-font-family: "Nunito", "Nunito override", "Arial", "Helvetica",
|
||||||
|
// sans-serif;
|
||||||
|
|
||||||
// yes
|
// yes
|
||||||
--base-color: #eee;
|
--base-color: #eee;
|
||||||
--base-color-text: rgba(0, 0, 0, 0.8);
|
--base-color-text: #456;
|
||||||
--base-color-border: #999;
|
--base-color-border: #999;
|
||||||
--base-color-light: #fff;
|
--base-color-light: #fff;
|
||||||
|
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
|
|
||||||
// yes
|
// yes
|
||||||
--primary-color: #35a5f1;
|
--primary-color: #35a5f1;
|
||||||
|
--primary-color-hover: #f1fdff;
|
||||||
|
|
||||||
--primary-color-dark: #0e80ce;
|
--primary-color-dark: #0e80ce;
|
||||||
--primary-color-darker: #095589;
|
--primary-color-darker: #095589;
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
<template>
|
|
||||||
<router-link :to="props.to" :class="['sm-article-card', `${props.type}`]">
|
|
||||||
<div
|
|
||||||
class="thumbnail"
|
|
||||||
:style="[{ backgroundImage: `url('${props.image}')` }]"></div>
|
|
||||||
<div class="content">
|
|
||||||
<h3>{{ props.title }}</h3>
|
|
||||||
<p class="excerpt">{{ props.excerpt }}</p>
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps({
|
|
||||||
to: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: "",
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
excerpt: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.sm-article-card {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 20px;
|
|
||||||
|
|
||||||
.thumbnail {
|
|
||||||
aspect-ratio: 16 / 9;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-color: var(--card-background-color);
|
|
||||||
box-shadow: var(--box-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.row {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -184,7 +184,7 @@ const handleClickItem = (item: string) => {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: var(--header-font-family);
|
font-family: var(--header-font-family);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
padding: 16px 32px 16px 32px;
|
padding: 12px 32px 12px 32px;
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: var(--base-color-light);
|
background-color: var(--base-color-light);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -195,7 +195,11 @@ const handleClickItem = (item: string) => {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
.button-label {
|
.button-label {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 0 3px 0;
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
|
display: inline-block;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
margin: -8px 0;
|
margin: -8px 0;
|
||||||
@@ -240,7 +244,7 @@ const handleClickItem = (item: string) => {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(0, 0, 255, 0.5);
|
background-color: var(--primary-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="['sm-column', { 'flex-fill': fill && width == '' }]"
|
:class="['column', { 'flex-fill': fill && width == '' }]"
|
||||||
:style="styles">
|
:style="styles">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,13 +28,13 @@ if (props.width != "") {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.sm-column {
|
.column {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: map-get($spacer, 2);
|
margin: 0 12px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm-row .sm-row .sm-column {
|
.row .row .column {
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,10 @@ const slots = useSlots();
|
|||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0 16px 0 16px;
|
padding: 0 16px;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
align-items: center;
|
// align-items: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
&.full {
|
&.full {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ const dialogRefs = shallowReactive<DialogInstance[]>([]);
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "SMDialogList",
|
name: "SMDialogList",
|
||||||
template: `
|
template: `
|
||||||
<div class="sm-dialog-list">
|
<div class="dialog-list">
|
||||||
<div v-for="(dialogRef, index) in dialogRefList" :key="index" class="sm-dialog-outer">
|
<div v-for="(dialogRef, index) in dialogRefList" :key="index" class="dialog-outer">
|
||||||
<component
|
<component
|
||||||
:is="dialogRef.dialog"
|
:is="dialogRef.dialog"
|
||||||
v-if="dialogRef && dialogRef.wrapper === name"
|
v-if="dialogRef && dialogRef.wrapper === name"
|
||||||
|
|||||||
@@ -90,7 +90,12 @@
|
|||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="{ name: 'terms' }"
|
<router-link :to="{ name: 'code-of-conduct' }"
|
||||||
|
>Code of Conduct</router-link
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<router-link :to="{ name: 'terms-and-conditions' }"
|
||||||
>Terms & Conditions</router-link
|
>Terms & Conditions</router-link
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
@@ -99,9 +104,6 @@
|
|||||||
>Privacy Policy</router-link
|
>Privacy Policy</router-link
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<router-link :to="{ name: 'rules' }">Rules</router-link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</SMColumn>
|
</SMColumn>
|
||||||
</SMRow>
|
</SMRow>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const computedContent = computed(() => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
template: `<div class="sm-content">${html}</div>`,
|
template: `<div class="html">${html}</div>`,
|
||||||
components: {
|
components: {
|
||||||
SMImageGallery,
|
SMImageGallery,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
name="alert-circle-outline"></ion-icon>
|
name="alert-circle-outline"></ion-icon>
|
||||||
<ion-icon
|
<ion-icon
|
||||||
v-if="
|
v-if="
|
||||||
props.showClear && value.length > 0 && !feedbackInvalid
|
props.showClear && value?.length > 0 && !feedbackInvalid
|
||||||
"
|
"
|
||||||
class="clear-icon"
|
class="clear-icon"
|
||||||
name="close-outline"
|
name="close-outline"
|
||||||
@@ -96,6 +96,11 @@ const props = defineProps({
|
|||||||
default: false,
|
default: false,
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
feedbackInvalid: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
@@ -132,14 +137,22 @@ const id = ref(
|
|||||||
? props.control
|
? props.control
|
||||||
: ""
|
: ""
|
||||||
);
|
);
|
||||||
const feedbackInvalid = ref("");
|
const feedbackInvalid = ref(props.feedbackInvalid);
|
||||||
const active = ref(value.value.length > 0);
|
const active = ref(value.value?.length ?? 0 > 0);
|
||||||
|
const focused = ref(false);
|
||||||
const disabled = ref(props.disabled);
|
const disabled = ref(props.disabled);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => value.value,
|
() => value.value,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
active.value = newValue.length > 0;
|
active.value = newValue.length > 0 || focused.value == true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.feedbackInvalid,
|
||||||
|
(newValue) => {
|
||||||
|
feedbackInvalid.value = newValue;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -174,10 +187,13 @@ if (form) {
|
|||||||
|
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
active.value = true;
|
active.value = true;
|
||||||
|
focused.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlur = async () => {
|
const handleBlur = async () => {
|
||||||
active.value = value.value != "";
|
active.value = value.value?.length ?? 0 > 0;
|
||||||
|
focused.value = false;
|
||||||
|
emits("change");
|
||||||
|
|
||||||
if (control) {
|
if (control) {
|
||||||
await control.validate();
|
await control.validate();
|
||||||
@@ -295,7 +311,7 @@ const handleClear = () => {
|
|||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
padding: 1px;
|
padding: 1px 1px 1px 0px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -310,13 +326,18 @@ const handleClear = () => {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: var(--base-color-light);
|
background-color: var(--base-color-light);
|
||||||
color: var(--base-color-text);
|
color: var(--base-color-text);
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: hsl(0, 0%, 92%);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-help {
|
.input-help {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 85%;
|
font-size: 70%;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
|
||||||
.input-invalid {
|
.input-invalid {
|
||||||
|
|||||||
@@ -51,10 +51,8 @@ const tabGroups = [
|
|||||||
[
|
[
|
||||||
{ title: "Contact", to: "/contact" },
|
{ title: "Contact", to: "/contact" },
|
||||||
{ title: "Code of Conduct", to: "/code-of-conduct" },
|
{ title: "Code of Conduct", to: "/code-of-conduct" },
|
||||||
{ title: "Privacy", to: "/page" },
|
{ title: "Terms and Conditions", to: "/terms-and-conditions" },
|
||||||
{ title: "Governance", to: "/page" },
|
{ title: "Privacy", to: "/privacy" },
|
||||||
{ title: "Teams", to: "/login" },
|
|
||||||
{ title: "License", to: "/page" },
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -115,16 +113,19 @@ const tabs = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
|
display: inline-block;
|
||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.8);
|
||||||
font-family: var(--header-font-family);
|
font-family: var(--header-font-family);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 16px 24px;
|
padding: 16px 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(.active) {
|
||||||
color: rgba(255, 255, 255);
|
color: rgba(255, 255, 255);
|
||||||
background-color: hsla(0, 0%, 100%, 0.1);
|
background-color: hsla(0, 0%, 100%, 0.1);
|
||||||
}
|
}
|
||||||
@@ -132,9 +133,22 @@ const tabs = () => {
|
|||||||
&.active {
|
&.active {
|
||||||
background-color: var(--base-color);
|
background-color: var(--base-color);
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.masthead .tabs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
|
|||||||
@@ -266,7 +266,10 @@ onUnmounted(() => {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0 12px 0;
|
padding: 0 0 12px 0;
|
||||||
|
|
||||||
li a {
|
li {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
a {
|
||||||
color: var(--base-color-text);
|
color: var(--base-color-text);
|
||||||
display: block;
|
display: block;
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
@@ -284,6 +287,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
|
|||||||
32
resources/js/components/SMNoItems.vue
Normal file
32
resources/js/components/SMNoItems.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div class="no-items">
|
||||||
|
<ion-icon name="alert-circle-outline" />
|
||||||
|
<p>{{ props.text }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps({
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: "No items found",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.no-items {
|
||||||
|
margin-top: 32px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
font-size: 400%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 130%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -128,16 +128,15 @@ const handleClickPage = (page: number): void => {
|
|||||||
font-family: var(--header-font-family);
|
font-family: var(--header-font-family);
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 24px;
|
margin: 24px auto;
|
||||||
|
box-shadow: var(--base-shadow);
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: var(--base-color-light);
|
background-color: var(--base-color-light);
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
box-shadow: var(--base-shadow);
|
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
@@ -159,8 +158,8 @@ const handleClickPage = (page: number): void => {
|
|||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(.active) {
|
||||||
filter: brightness(115%);
|
background-color: var(--primary-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="[
|
:class="['row', { 'row-break-lg': breakLarge }, { 'flex-fill': fill }]">
|
||||||
'sm-row',
|
|
||||||
{ 'row-break-lg': breakLarge },
|
|
||||||
{ 'flex-fill': fill },
|
|
||||||
]">
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -25,7 +21,7 @@ defineProps({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.sm-row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -35,7 +31,7 @@ defineProps({
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
@media screen and (max-width: 992px) {
|
||||||
.sm-row.row-break-lg {
|
.row.row-break-lg {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const handleRowClick = (item) => {
|
|||||||
tr {
|
tr {
|
||||||
&:hover {
|
&:hover {
|
||||||
td {
|
td {
|
||||||
background-color: rgba(0, 0, 255, 0.1) !important;
|
background-color: var(--primary-color-hover);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sm-toolbar">
|
<div class="toolbar">
|
||||||
<div v-if="slots.left" class="sm-toolbar-column sm-toolbar-column-left">
|
|
||||||
<slot name="left"></slot>
|
|
||||||
</div>
|
|
||||||
<div v-if="slots.default" class="sm-toolbar-column">
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="slots.right"
|
|
||||||
class="sm-toolbar-column sm-toolbar-column-right">
|
|
||||||
<slot name="right"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useSlots } from "vue";
|
|
||||||
|
|
||||||
const slots = useSlots();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.sm-toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: map-get($spacer, 2);
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
.sm-toolbar-column {
|
align-items: center;
|
||||||
display: flex;
|
gap: 20px;
|
||||||
flex: 1;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
&.sm-toolbar-column-left {
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
margin: 0 map-get($spacer, 1);
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.sm-toolbar-column-right {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.sm-toolbar {
|
|
||||||
.sm-toolbar-column {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export class SMDate {
|
|||||||
parsedMonth: number = 0,
|
parsedMonth: number = 0,
|
||||||
parsedYear: number = 0;
|
parsedYear: number = 0;
|
||||||
|
|
||||||
if (year.length == 3 || year.length >= 5) {
|
if (year == undefined || year.length == 3 || year.length >= 5) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,14 +101,6 @@ export const routes = [
|
|||||||
},
|
},
|
||||||
component: () => import("@/views/Unsubscribe.vue"),
|
component: () => import("@/views/Unsubscribe.vue"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/terms",
|
|
||||||
name: "terms",
|
|
||||||
meta: {
|
|
||||||
title: "Terms and Conditions",
|
|
||||||
},
|
|
||||||
component: () => import("@/views/Terms.vue"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/minecraft",
|
path: "/minecraft",
|
||||||
name: "minecraft",
|
name: "minecraft",
|
||||||
@@ -142,6 +134,10 @@ export const routes = [
|
|||||||
},
|
},
|
||||||
component: () => import("@/views/Contact.vue"),
|
component: () => import("@/views/Contact.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/conduct",
|
||||||
|
redirect: { name: "code-of-conduct" },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/code-of-conduct",
|
path: "/code-of-conduct",
|
||||||
name: "code-of-conduct",
|
name: "code-of-conduct",
|
||||||
@@ -150,6 +146,18 @@ export const routes = [
|
|||||||
},
|
},
|
||||||
component: () => import("@/views/CodeOfConduct.vue"),
|
component: () => import("@/views/CodeOfConduct.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/terms",
|
||||||
|
redirect: { name: "terms-and-conditions" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/terms-and-conditions",
|
||||||
|
name: "terms-and-conditions",
|
||||||
|
meta: {
|
||||||
|
title: "Terms and Conditions",
|
||||||
|
},
|
||||||
|
component: () => import("@/views/TermsAndConditions.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/register",
|
path: "/register",
|
||||||
name: "register",
|
name: "register",
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMPage class="sm-page-post-view" :page-error="pageError">
|
<div
|
||||||
<SMContainer>
|
class="thumbnail"
|
||||||
<div class="sm-post-hero" :style="backgroundStyle"></div>
|
:style="{ backgroundImage: `url('${backgroundImageUrl}')` }"></div>
|
||||||
<div class="sm-heading-info">
|
<SMContainer narrow>
|
||||||
<h1>{{ post.title }}</h1>
|
<h1 class="title">{{ post.title }}</h1>
|
||||||
<div class="sm-date-author small">
|
<div class="author">By {{ post.user.username }}</div>
|
||||||
<ion-icon name="calendar-outline" />
|
<div class="date">{{ formattedDate(post.publish_at) }}</div>
|
||||||
{{ formattedPublishAt(post.publish_at) }}, by
|
<SMHTML :html="post.content" class="content" />
|
||||||
{{ post.user.username }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<SMHTML :html="post.content" />
|
|
||||||
<SMAttachments :attachments="post.attachments || []" />
|
<SMAttachments :attachments="post.attachments || []" />
|
||||||
</SMContainer>
|
</SMContainer>
|
||||||
</SMPage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -52,7 +47,10 @@ let pageLoading = ref(false);
|
|||||||
*/
|
*/
|
||||||
let postUser: User | null = null;
|
let postUser: User | null = null;
|
||||||
|
|
||||||
let backgroundStyle = {};
|
/**
|
||||||
|
* Thumbnail image URL.
|
||||||
|
*/
|
||||||
|
let backgroundImageUrl = ref("");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the page data.
|
* Load the page data.
|
||||||
@@ -81,12 +79,7 @@ const handleLoad = async () => {
|
|||||||
utc: true,
|
utc: true,
|
||||||
}).format("yyyy/MM/dd HH:mm:ss");
|
}).format("yyyy/MM/dd HH:mm:ss");
|
||||||
|
|
||||||
backgroundStyle = {
|
backgroundImageUrl.value = mediaGetVariantUrl(post.value.hero);
|
||||||
backgroundImage: `url('${mediaGetVariantUrl(
|
|
||||||
post.value.hero
|
|
||||||
)}')`,
|
|
||||||
};
|
|
||||||
|
|
||||||
applicationStore.setDynamicTitle(post.value.title);
|
applicationStore.setDynamicTitle(post.value.title);
|
||||||
} else {
|
} else {
|
||||||
pageError.value = 404;
|
pageError.value = 404;
|
||||||
@@ -101,7 +94,13 @@ const handleLoad = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formattedPublishAt = (dateStr) => {
|
/**
|
||||||
|
* Format Date
|
||||||
|
*
|
||||||
|
* @param dateStr Date string.
|
||||||
|
* @returns Formatted date.
|
||||||
|
*/
|
||||||
|
const formattedDate = (dateStr) => {
|
||||||
return new SMDate(dateStr, { format: "yMd" }).format("MMMM d, yyyy");
|
return new SMDate(dateStr, { format: "yMd" }).format("MMMM d, yyyy");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,46 +108,34 @@ handleLoad();
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.sm-page-post-view {
|
.page-article {
|
||||||
.sm-container {
|
.thumbnail {
|
||||||
width: 70%;
|
|
||||||
padding: 64px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm-post-hero {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 480px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
max-height: 640px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm-heading-info {
|
.title {
|
||||||
padding: 0 map-get($spacer, 3);
|
margin-top: 64px;
|
||||||
margin-bottom: map-get($spacer, 4);
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-author {
|
.author {
|
||||||
font-size: 80%;
|
margin-top: 16px;
|
||||||
|
font-weight: 700;
|
||||||
svg {
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm-content {
|
.date {
|
||||||
padding: 0 map-get($spacer, 3);
|
margin-top: 16px;
|
||||||
line-height: 1.5rem;
|
font-weight: 700;
|
||||||
|
filter: brightness(175%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-top: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMMastHead title="Blog" />
|
<SMMastHead title="Blog" />
|
||||||
<SMContainer>
|
<SMContainer>
|
||||||
<SMInput type="text" label="Search articles" v-model="searchInput">
|
<SMInput
|
||||||
|
type="text"
|
||||||
|
label="Search articles"
|
||||||
|
v-model="searchInput"
|
||||||
|
show-clear>
|
||||||
<template #append
|
<template #append
|
||||||
><SMButton
|
><SMButton
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -11,11 +15,13 @@
|
|||||||
/></template>
|
/></template>
|
||||||
</SMInput>
|
</SMInput>
|
||||||
<SMPagination
|
<SMPagination
|
||||||
|
v-if="postsTotal > postsPerPage"
|
||||||
v-model="postsPage"
|
v-model="postsPage"
|
||||||
:total="postsTotal"
|
:total="postsTotal"
|
||||||
:per-page="postsPerPage" />
|
:per-page="postsPerPage" />
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
<article
|
<router-link
|
||||||
|
:to="{ name: 'article', params: { slug: post.slug } }"
|
||||||
class="article-card"
|
class="article-card"
|
||||||
v-for="(post, idx) in posts"
|
v-for="(post, idx) in posts"
|
||||||
:key="idx">
|
:key="idx">
|
||||||
@@ -27,28 +33,30 @@
|
|||||||
'medium'
|
'medium'
|
||||||
)})`,
|
)})`,
|
||||||
}"></div>
|
}"></div>
|
||||||
<div class="content">
|
<div class="info">
|
||||||
{{ post.content }}
|
{{ post.user.username }} -
|
||||||
|
{{ computedDate(post.publish_at) }}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
<h3 class="title">{{ post.title }}</h3>
|
||||||
|
<p class="content">
|
||||||
|
{{ excerpt(post.content) }}
|
||||||
|
</p>
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</SMContainer>
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Ref, ref, watch } from "vue";
|
import { Ref, ref, watch } from "vue";
|
||||||
import SMMessage from "../components/SMMessage.vue";
|
|
||||||
import SMPagination from "../components/SMPagination.vue";
|
import SMPagination from "../components/SMPagination.vue";
|
||||||
import SMPanel from "../components/SMPanel.vue";
|
|
||||||
import SMPanelList from "../components/SMPanelList.vue";
|
|
||||||
import { api } from "../helpers/api";
|
import { api } from "../helpers/api";
|
||||||
import { Post, PostCollection } from "../helpers/api.types";
|
import { Post, PostCollection } from "../helpers/api.types";
|
||||||
import { SMDate } from "../helpers/datetime";
|
import { SMDate } from "../helpers/datetime";
|
||||||
import { mediaGetVariantUrl } from "../helpers/media";
|
import { mediaGetVariantUrl } from "../helpers/media";
|
||||||
import SMMastHead from "../components/SMMastHead.vue";
|
import SMMastHead from "../components/SMMastHead.vue";
|
||||||
import SMInput from "../components/SMInput.vue";
|
import SMInput from "../components/SMInput.vue";
|
||||||
import SMForm from "../components/SMForm.vue";
|
|
||||||
import SMButton from "../components/SMButton.vue";
|
import SMButton from "../components/SMButton.vue";
|
||||||
|
import { excerpt } from "../helpers/string";
|
||||||
|
|
||||||
const message = ref("");
|
const message = ref("");
|
||||||
const pageLoading = ref(true);
|
const pageLoading = ref(true);
|
||||||
@@ -102,6 +110,10 @@ const handleLoad = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const computedDate = (date) => {
|
||||||
|
return new SMDate(date, { format: "yMd" }).format("d MMMM yyyy");
|
||||||
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => postsPage.value,
|
() => postsPage.value,
|
||||||
() => {
|
() => {
|
||||||
@@ -113,31 +125,58 @@ handleLoad();
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.posts {
|
.page-blog {
|
||||||
|
.posts {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
|
|
||||||
.article-card {
|
.article-card {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--base-color-text);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: none;
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
filter: brightness(115%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.thumbnail {
|
.thumbnail {
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 16 / 9;
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-color: var(--card-background-color);
|
background-color: var(--card-background-color);
|
||||||
box-shadow: 0 5px 10px -3px #00000078;
|
box-shadow: var(--base-shadow);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 16px 0;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.posts {
|
.page-blog .posts {
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
.posts {
|
.page-blog .posts {
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMMastHead title="Code of Conduct" />
|
<SMMastHead title="Code of Conduct" />
|
||||||
<SMContainer>
|
<SMContainer narrow>
|
||||||
<div class="container-text">
|
<template #inner>
|
||||||
<p>
|
<p>
|
||||||
STEMMechanics supports the international community open to
|
STEMMechanics supports the international community open to
|
||||||
everyone without discrimination. We want this community to be a
|
everyone without discrimination. We want this community to be a
|
||||||
@@ -12,11 +12,24 @@
|
|||||||
</p>
|
</p>
|
||||||
<h3>Philosophy</h3>
|
<h3>Philosophy</h3>
|
||||||
<p>
|
<p>
|
||||||
If you have a question or would like help with a project, you
|
In the STEMMechanics community, participants from all over the
|
||||||
can send it our way using the form on this page or be emailing
|
world come together to create and work on STEM projects. This is
|
||||||
<a href="mailto:hello@stemmechanics.com.au"
|
made possible by the support, hard work, and enthusiasm of
|
||||||
>hello@stemmechanics.com.au</a
|
people who collaborate towards the common goal of creating great
|
||||||
>.
|
ideas. Cooperation at such a scale requires common guidelines to
|
||||||
|
ensure a positive and inspiring atmosphere in the community.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This is why we have this Code of Conduct: it explains the type
|
||||||
|
of community we want to have. The rules below are not applied to
|
||||||
|
all interactions with a simple matching algorithm. Human
|
||||||
|
interactions happen in context and are complex. Perceived
|
||||||
|
violations are evaluated by real humans who will try to
|
||||||
|
interpret the interactions and the rules with kindness.
|
||||||
|
Accordingly, there is no need to hypothesize on how these rules
|
||||||
|
would affect normal interactions. Be reasonable, the
|
||||||
|
<a href="#coc-team">Code of Conduct team</a> surely will be as
|
||||||
|
well.
|
||||||
</p>
|
</p>
|
||||||
<h3>Application</h3>
|
<h3>Application</h3>
|
||||||
<p>
|
<p>
|
||||||
@@ -47,18 +60,84 @@
|
|||||||
please accept it gracefully.
|
please accept it gracefully.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Code of Conduct team</h3>
|
<h3>Restricted conduct</h3>
|
||||||
|
<p>
|
||||||
|
Participating in restricted conduct will lead to a warning from
|
||||||
|
community moderators and/or the Code of Conduct team and may
|
||||||
|
lead to exclusion from the community in the form of a ban from
|
||||||
|
one or all platforms.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
STEMMechanics is committed to providing a friendly and safe
|
||||||
|
environment for everyone, regardless of level of experience,
|
||||||
|
gender identity and expression, sexual orientation,
|
||||||
|
disability, physical appearance, body size, race, ethnicity,
|
||||||
|
language proficiency, age, political orientation,
|
||||||
|
nationality, religion, or other similar characteristics. We
|
||||||
|
do not tolerate harassment or discrimination of participants
|
||||||
|
in any form.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
In particular, we strive to be welcoming to all and to
|
||||||
|
ensure that anyone can take a more active role in the
|
||||||
|
community and a project. Targeted harassment of minorities
|
||||||
|
or individuals is unacceptable.
|
||||||
|
</li>
|
||||||
|
<li>Aggressive or offensive behavior is not acceptable.</li>
|
||||||
|
<li>
|
||||||
|
You will be excluded from participating in the community if
|
||||||
|
you insult, demean, harass, intentionally make others
|
||||||
|
uncomfortable by any means, or participate in any other
|
||||||
|
hateful conduct, either publicly or privately.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Likewise, any spamming, trolling, flaming, baiting, or other
|
||||||
|
attention-stealing behavior is not welcome and will result
|
||||||
|
in exclusion from the community.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Any form of retaliation against a participant who contacts
|
||||||
|
the Code of Conduct team is completely unacceptable,
|
||||||
|
regardless of the outcome of the complaint. Any such
|
||||||
|
behavior will result in exclusion from the community.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
For certainty, any conduct which could reasonably be
|
||||||
|
considered inappropriate in a professional setting is not
|
||||||
|
acceptable.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Reporting a breach</h3>
|
||||||
|
<p>
|
||||||
|
If you witness or are involved in an interaction with another
|
||||||
|
community member that you think may violate this Code of
|
||||||
|
Conduct, please contact STEMMechanics
|
||||||
|
<a href="#coc-team">Code of Conduct team</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
STEMMechanics recognizes that it can be difficult to come
|
||||||
|
forward in cases of a violation of the Code of Conduct. To make
|
||||||
|
it easier to report violations, we provide a single point of
|
||||||
|
contact via email at:
|
||||||
|
<a href="conduct@stemmechanics.com.au"
|
||||||
|
>conduct@stemmechanics.com.au</a
|
||||||
|
>. If you are more comfortable reaching out to a single person,
|
||||||
|
you are also welcome to contact one or more members of the team
|
||||||
|
using their personal emails listed below, or via direct
|
||||||
|
messaging on community platforms where they are present.
|
||||||
|
</p>
|
||||||
|
<h3 id="coc-item">Code of Conduct team</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>James Collins, james@stemmechanics.com.au</li>
|
<li>James Collins, james@stemmechanics.com.au</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
GitHub / Discord / Reddit:
|
GitHub / Discord / Reddit / Twitter:
|
||||||
<span class="italic">nomadjimbob</span>
|
<span class="italic">nomadjimbob</span>
|
||||||
</li>
|
</li>
|
||||||
<li>Languages: English</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</template>
|
||||||
</SMContainer>
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -67,29 +146,9 @@ import SMMastHead from "../components/SMMastHead.vue";
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.container-text {
|
.page-code-of-conduct {
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
line-height: 1.4em;
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-top: 60px;
|
margin-top: 60px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm-contact-socials {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
font-size: 200%;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 0 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.address {
|
|
||||||
margin-top: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMContainer class="sm-privacy">
|
<SMMastHead title="Privacy Policy" />
|
||||||
<template #container>
|
<SMContainer narrow>
|
||||||
<h1>Privacy Policy</h1>
|
<template #inner>
|
||||||
<h3>We take our customers' privacy & security seriously.</h3>
|
<h3>We take our customers' privacy & security seriously.</h3>
|
||||||
<p>
|
<p>
|
||||||
At STEMMechanics, we take our customers' privacy and security
|
At STEMMechanics, we take our customers' privacy and security
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<p>
|
<p>
|
||||||
By using the Website and our online services, you agree to
|
By using the Website and our online services, you agree to
|
||||||
accept the Privacy Policy and the Site's Terms and Conditions
|
accept the Privacy Policy and the Site's Terms and Conditions
|
||||||
<router-link :to="{ name: 'terms' }"
|
<router-link :to="{ name: 'terms-and-conditions' }"
|
||||||
>https://www.stemmechanics.com.au/terms</router-link
|
>https://www.stemmechanics.com.au/terms-and-conditions</router-link
|
||||||
>
|
>
|
||||||
(Terms and Conditions). Where the Privacy Policy uses a word
|
(Terms and Conditions). Where the Privacy Policy uses a word
|
||||||
starting with a capital letter, that term will be defined in the
|
starting with a capital letter, that term will be defined in the
|
||||||
@@ -336,14 +336,18 @@
|
|||||||
</SMContainer>
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SMMastHead from "../components/SMMastHead.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.sm-privacy {
|
.page-privacy {
|
||||||
h4 {
|
h3 {
|
||||||
margin-bottom: 0.5rem;
|
margin-top: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul li {
|
h4 {
|
||||||
margin-bottom: 0.5rem;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMPage class="sm-page-terms">
|
<SMMastHead title="Terms and Conditions" />
|
||||||
<template #container>
|
<SMContainer narrow>
|
||||||
<h1>Terms and Conditions</h1>
|
<template #inner>
|
||||||
<p>
|
<p>
|
||||||
Please read these terms carefully. By accessing or using our
|
Please read these terms carefully. By accessing or using our
|
||||||
website and online servers, you agree to be bound by these terms
|
website and online servers, you agree to be bound by these terms
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
agrees to indemnify you and STEMMechanics for its violations of
|
agrees to indemnify you and STEMMechanics for its violations of
|
||||||
these Terms.
|
these Terms.
|
||||||
</p>
|
</p>
|
||||||
<h4>1. Eligibility, registration & account</h4>
|
<h3>1. Eligibility, registration & account</h3>
|
||||||
<p>
|
<p>
|
||||||
You must be 18 years of age to use the Website. If you are under
|
You must be 18 years of age to use the Website. If you are under
|
||||||
18 years of age you must have the permission of your parent or
|
18 years of age you must have the permission of your parent or
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
if you discover or otherwise suspect any security breaches
|
if you discover or otherwise suspect any security breaches
|
||||||
related to the Sites.
|
related to the Sites.
|
||||||
</p>
|
</p>
|
||||||
<h4>2. Ownership of site content</h4>
|
<h3>2. Ownership of site content</h3>
|
||||||
<p>
|
<p>
|
||||||
Unless otherwise indicated on our Sites, the Sites and all
|
Unless otherwise indicated on our Sites, the Sites and all
|
||||||
content and materials therein, including but not limited to the
|
content and materials therein, including but not limited to the
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
intellectual property rights, whether by estoppel, implication
|
intellectual property rights, whether by estoppel, implication
|
||||||
or otherwise. This license is revocable at any time.
|
or otherwise. This license is revocable at any time.
|
||||||
</p>
|
</p>
|
||||||
<h4>3. Hyperlinks</h4>
|
<h3>3. Hyperlinks</h3>
|
||||||
<p>
|
<p>
|
||||||
You are granted a limited, non-exclusive right to create a text
|
You are granted a limited, non-exclusive right to create a text
|
||||||
hyperlink to the Sites for non-commercial purposes, provided
|
hyperlink to the Sites for non-commercial purposes, provided
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
including privacy and data gathering practices, of any site to
|
including privacy and data gathering practices, of any site to
|
||||||
which you navigate from the Sites.
|
which you navigate from the Sites.
|
||||||
</p>
|
</p>
|
||||||
<h4>4. User content</h4>
|
<h3>4. User content</h3>
|
||||||
<p>
|
<p>
|
||||||
The Sites may include discussion blogs, profiles, product
|
The Sites may include discussion blogs, profiles, product
|
||||||
reviews or other interactive features or areas (collectively,
|
reviews or other interactive features or areas (collectively,
|
||||||
@@ -223,7 +223,7 @@
|
|||||||
among other things, termination or suspension of your rights to
|
among other things, termination or suspension of your rights to
|
||||||
use the Sites.
|
use the Sites.
|
||||||
</p>
|
</p>
|
||||||
<h4>5. Rights in user content</h4>
|
<h3>5. Rights in user content</h3>
|
||||||
<p>
|
<p>
|
||||||
Except as otherwise provided herein, on the Sites or in a
|
Except as otherwise provided herein, on the Sites or in a
|
||||||
separate agreement with us (such as the rules of a STEMMechanics
|
separate agreement with us (such as the rules of a STEMMechanics
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
guidelines or policies or any applicable law, rule or
|
guidelines or policies or any applicable law, rule or
|
||||||
regulation.
|
regulation.
|
||||||
</p>
|
</p>
|
||||||
<h4>6. Feedback</h4>
|
<h3>6. Feedback</h3>
|
||||||
<p>
|
<p>
|
||||||
Separate and apart from User Content, you have the ability to
|
Separate and apart from User Content, you have the ability to
|
||||||
submit questions, comments suggestions, reviews, ideas, plans,
|
submit questions, comments suggestions, reviews, ideas, plans,
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
idea might be great, but we may have already had the same or a
|
idea might be great, but we may have already had the same or a
|
||||||
similar idea and we do not want disputes.
|
similar idea and we do not want disputes.
|
||||||
</p>
|
</p>
|
||||||
<h4>7. User conduct</h4>
|
<h3>7. User conduct</h3>
|
||||||
<p>
|
<p>
|
||||||
You agree that you will not violate any law, contract or
|
You agree that you will not violate any law, contract or
|
||||||
intellectual property or other third party right or commit a
|
intellectual property or other third party right or commit a
|
||||||
@@ -364,14 +364,14 @@
|
|||||||
before contacting or meeting anyone (online or offline) that is
|
before contacting or meeting anyone (online or offline) that is
|
||||||
unfamiliar to you.
|
unfamiliar to you.
|
||||||
</p>
|
</p>
|
||||||
<h4>8. No third-party beneficiaries</h4>
|
<h3>8. No third-party beneficiaries</h3>
|
||||||
<p>
|
<p>
|
||||||
These Terms are for the benefit of, and will be enforceable by,
|
These Terms are for the benefit of, and will be enforceable by,
|
||||||
the parties only. These Terms are not intended to confer any
|
the parties only. These Terms are not intended to confer any
|
||||||
right or benefit on any third party or to create any obligations
|
right or benefit on any third party or to create any obligations
|
||||||
or liability of a party to any such third party.
|
or liability of a party to any such third party.
|
||||||
</p>
|
</p>
|
||||||
<h4>9. Indemnification</h4>
|
<h3>9. Indemnification</h3>
|
||||||
<p>
|
<p>
|
||||||
To the fullest extent permitted by applicable law, you agree to
|
To the fullest extent permitted by applicable law, you agree to
|
||||||
defend, indemnify and hold harmless STEMMechanics and our
|
defend, indemnify and hold harmless STEMMechanics and our
|
||||||
@@ -385,7 +385,7 @@
|
|||||||
provide; (d) your violation of these Terms; and (e) your
|
provide; (d) your violation of these Terms; and (e) your
|
||||||
violation of any rights of another.
|
violation of any rights of another.
|
||||||
</p>
|
</p>
|
||||||
<h4>10. Disclaimers</h4>
|
<h3>10. Disclaimers</h3>
|
||||||
<p>
|
<p>
|
||||||
Except as expressly provided, the Sites, Site Content, User
|
Except as expressly provided, the Sites, Site Content, User
|
||||||
Content and services provided on or in connection with the Sites
|
Content and services provided on or in connection with the Sites
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
is not a substitute for in-person guidance by a qualified
|
is not a substitute for in-person guidance by a qualified
|
||||||
instructor.
|
instructor.
|
||||||
</p>
|
</p>
|
||||||
<h4>11. Liability</h4>
|
<h3>11. Liability</h3>
|
||||||
<p>
|
<p>
|
||||||
To the fullest extent permitted by applicable law, in no event
|
To the fullest extent permitted by applicable law, in no event
|
||||||
shall the STEMMechanics parties be liable for any special,
|
shall the STEMMechanics parties be liable for any special,
|
||||||
@@ -433,13 +433,13 @@
|
|||||||
access to an STEMMechanics party's records, programs or
|
access to an STEMMechanics party's records, programs or
|
||||||
services.
|
services.
|
||||||
</p>
|
</p>
|
||||||
<h4>12. Modifications to site</h4>
|
<h3>12. Modifications to site</h3>
|
||||||
<p>
|
<p>
|
||||||
STEMMechanics reserves the right to modify or discontinue,
|
STEMMechanics reserves the right to modify or discontinue,
|
||||||
temporarily or permanently, the Sites or any features or
|
temporarily or permanently, the Sites or any features or
|
||||||
portions thereof without prior notice.
|
portions thereof without prior notice.
|
||||||
</p>
|
</p>
|
||||||
<h4>13. Termination</h4>
|
<h3>13. Termination</h3>
|
||||||
<p>
|
<p>
|
||||||
You may terminate the Terms at any time by closing your account,
|
You may terminate the Terms at any time by closing your account,
|
||||||
discontinuing your use of the Sites and providing STEMMechanics
|
discontinuing your use of the Sites and providing STEMMechanics
|
||||||
@@ -449,14 +449,14 @@
|
|||||||
block or prevent your future access to and use of the Sites or
|
block or prevent your future access to and use of the Sites or
|
||||||
any portion of the Sites.
|
any portion of the Sites.
|
||||||
</p>
|
</p>
|
||||||
<h4>14. Severability</h4>
|
<h3>14. Severability</h3>
|
||||||
<p>
|
<p>
|
||||||
If any provision of these Terms shall be deemed unlawful, void
|
If any provision of these Terms shall be deemed unlawful, void
|
||||||
or for any reason unenforceable, then that provision shall be
|
or for any reason unenforceable, then that provision shall be
|
||||||
deemed severable from these Terms and shall not affect the
|
deemed severable from these Terms and shall not affect the
|
||||||
validity and enforceability of any remaining provisions.
|
validity and enforceability of any remaining provisions.
|
||||||
</p>
|
</p>
|
||||||
<h4>15. Ordering online</h4>
|
<h3>15. Ordering online</h3>
|
||||||
<p>
|
<p>
|
||||||
Upon completing your order and submitting it through the
|
Upon completing your order and submitting it through the
|
||||||
checkout system, an order reference number will be issued to you
|
checkout system, an order reference number will be issued to you
|
||||||
@@ -486,7 +486,7 @@
|
|||||||
Digital items cannot be cancelled or edited after receiving
|
Digital items cannot be cancelled or edited after receiving
|
||||||
payment.
|
payment.
|
||||||
</p>
|
</p>
|
||||||
<h4>16. Pricing & availability</h4>
|
<h3>16. Pricing & availability</h3>
|
||||||
<p>
|
<p>
|
||||||
All prices are shown in Australia dollars (AUD). All items are
|
All prices are shown in Australia dollars (AUD). All items are
|
||||||
subject to availability and we reserve the right to impose
|
subject to availability and we reserve the right to impose
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
from those in the store or from store-advertised prices. All
|
from those in the store or from store-advertised prices. All
|
||||||
purchases on applicable products include GST at the rate of 10%.
|
purchases on applicable products include GST at the rate of 10%.
|
||||||
</p>
|
</p>
|
||||||
<h4>17. Errors</h4>
|
<h3>17. Errors</h3>
|
||||||
<p>
|
<p>
|
||||||
We attempt to be as accurate as possible and eliminate errors on
|
We attempt to be as accurate as possible and eliminate errors on
|
||||||
the Sites; however, we do not warrant that any product, service,
|
the Sites; however, we do not warrant that any product, service,
|
||||||
@@ -511,7 +511,7 @@
|
|||||||
any amount charged. Your sole remedy in the event of such error
|
any amount charged. Your sole remedy in the event of such error
|
||||||
is to cancel your order and obtain a refund.
|
is to cancel your order and obtain a refund.
|
||||||
</p>
|
</p>
|
||||||
<h4>18. Out of stock / pre-order items</h4>
|
<h3>18. Out of stock / pre-order items</h3>
|
||||||
<p>
|
<p>
|
||||||
If the colour or size you want is not listed in the "Choose Your
|
If the colour or size you want is not listed in the "Choose Your
|
||||||
Colour/Size" drop-down box on the Product Information page, it
|
Colour/Size" drop-down box on the Product Information page, it
|
||||||
@@ -527,10 +527,10 @@
|
|||||||
the availability of that item. If you have items on pre-order
|
the availability of that item. If you have items on pre-order
|
||||||
that you would like to cancel, please contact us.
|
that you would like to cancel, please contact us.
|
||||||
</p>
|
</p>
|
||||||
<h4>
|
<h3>
|
||||||
19. Agreement to Conduct Transactions Electronically; Recording;
|
19. Agreement to Conduct Transactions Electronically; Recording;
|
||||||
Copies
|
Copies
|
||||||
</h4>
|
</h3>
|
||||||
<p>
|
<p>
|
||||||
You agree that all of your transactions with or through the
|
You agree that all of your transactions with or through the
|
||||||
Sites may, at our option, be conducted electronically from start
|
Sites may, at our option, be conducted electronically from start
|
||||||
@@ -542,7 +542,7 @@
|
|||||||
other contract or disclosure that we are required to provide to
|
other contract or disclosure that we are required to provide to
|
||||||
you.
|
you.
|
||||||
</p>
|
</p>
|
||||||
<h4>20. Payment</h4>
|
<h3>20. Payment</h3>
|
||||||
<p>
|
<p>
|
||||||
We currently accept Visa and Mastercard online. Only valid
|
We currently accept Visa and Mastercard online. Only valid
|
||||||
credit cards or other payment method acceptable to us may be
|
credit cards or other payment method acceptable to us may be
|
||||||
@@ -556,7 +556,7 @@
|
|||||||
otherwise acceptable, your order may be suspended or cancelled
|
otherwise acceptable, your order may be suspended or cancelled
|
||||||
automatically.
|
automatically.
|
||||||
</p>
|
</p>
|
||||||
<h4>21. Third-party sellers / on-sellers (buying & selling)</h4>
|
<h3>21. Third-party sellers / on-sellers (buying & selling)</h3>
|
||||||
<p>
|
<p>
|
||||||
You may not place orders with the intention to immediately
|
You may not place orders with the intention to immediately
|
||||||
on-forward the products to another person in a business
|
on-forward the products to another person in a business
|
||||||
@@ -592,5 +592,17 @@
|
|||||||
but this is allowed under the Law.
|
but this is allowed under the Law.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</SMPage>
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SMMastHead from "../components/SMMastHead.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.page-terms-and-conditions {
|
||||||
|
h3 {
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMMastHead title="Workshops" />
|
<SMMastHead title="Workshops" />
|
||||||
<SMContainer>
|
<SMContainer>
|
||||||
<SMToolbar>
|
<SMToolbar class="align-items-start">
|
||||||
<SMInput
|
<SMInput
|
||||||
v-model="filterKeywords"
|
v-model="filterKeywords"
|
||||||
label="Keywords"
|
label="Keywords"
|
||||||
@@ -10,12 +10,14 @@
|
|||||||
<SMInput
|
<SMInput
|
||||||
v-model="filterLocation"
|
v-model="filterLocation"
|
||||||
label="Location"
|
label="Location"
|
||||||
|
:show-clear="true"
|
||||||
@change="handleFilter" />
|
@change="handleFilter" />
|
||||||
<SMInput
|
<SMInput
|
||||||
v-model="filterDateRange"
|
v-model="filterDateRange"
|
||||||
type="daterange"
|
type="daterange"
|
||||||
label="Date Range"
|
label="Date Range"
|
||||||
:feedback-invalid="dateRangeError"
|
:feedback-invalid="dateRangeError"
|
||||||
|
:show-clear="true"
|
||||||
@change="handleFilter" />
|
@change="handleFilter" />
|
||||||
</SMToolbar>
|
</SMToolbar>
|
||||||
<SMPagination
|
<SMPagination
|
||||||
@@ -30,9 +32,9 @@
|
|||||||
:message="formMessage"
|
:message="formMessage"
|
||||||
class="mt-5" />
|
class="mt-5" />
|
||||||
|
|
||||||
<div class="events-list">
|
<div v-if="postsTotal > 0" class="events">
|
||||||
<router-link
|
<router-link
|
||||||
class="event"
|
class="event-card"
|
||||||
v-for="event in events"
|
v-for="event in events"
|
||||||
:key="event.id"
|
:key="event.id"
|
||||||
:to="{ name: 'event', params: { id: event.id } }">
|
:to="{ name: 'event', params: { id: event.id } }">
|
||||||
@@ -62,6 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
<SMNoItems v-else />
|
||||||
</SMContainer>
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -76,6 +79,7 @@ import { Event, EventCollection } from "../helpers/api.types";
|
|||||||
import { SMDate } from "../helpers/datetime";
|
import { SMDate } from "../helpers/datetime";
|
||||||
import SMMastHead from "../components/SMMastHead.vue";
|
import SMMastHead from "../components/SMMastHead.vue";
|
||||||
import SMContainer from "../components/SMContainer.vue";
|
import SMContainer from "../components/SMContainer.vue";
|
||||||
|
import SMNoItems from "../components/SMNoItems.vue";
|
||||||
|
|
||||||
interface EventData {
|
interface EventData {
|
||||||
event: Event;
|
event: Event;
|
||||||
@@ -87,7 +91,7 @@ const loading = ref(true);
|
|||||||
let events: Event[] = reactive([]);
|
let events: Event[] = reactive([]);
|
||||||
const dateRangeError = ref("");
|
const dateRangeError = ref("");
|
||||||
|
|
||||||
const formMessage = ref("");
|
const formMessage = ref("123");
|
||||||
|
|
||||||
const filterKeywords = ref("");
|
const filterKeywords = ref("");
|
||||||
const filterLocation = ref("");
|
const filterLocation = ref("");
|
||||||
@@ -330,13 +334,13 @@ handleLoad();
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.page-workshops {
|
.page-workshops {
|
||||||
.events-list {
|
.events {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.event {
|
.event-card {
|
||||||
background-color: var(--base-color-light);
|
background-color: var(--base-color-light);
|
||||||
box-shadow: 0 5px 10px -3px rgba(0, 0, 0, 0.25);
|
box-shadow: 0 5px 10px -3px rgba(0, 0, 0, 0.25);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -359,6 +363,7 @@ handleLoad();
|
|||||||
.title {
|
.title {
|
||||||
margin: 0 0 16px 0;
|
margin: 0 0 16px 0;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
@@ -387,7 +392,7 @@ handleLoad();
|
|||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.page-workshops {
|
.page-workshops {
|
||||||
.events-list {
|
.events {
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,43 +400,9 @@ handleLoad();
|
|||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
.page-workshops {
|
.page-workshops {
|
||||||
.events-list {
|
.events {
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// .sm-page-workshop-list {
|
|
||||||
// background-color: #f8f8f8;
|
|
||||||
|
|
||||||
// .toolbar {
|
|
||||||
// display: flex;
|
|
||||||
// flex-direction: row;
|
|
||||||
// flex: 1;
|
|
||||||
|
|
||||||
// & > * {
|
|
||||||
// padding-left: map-get($spacer, 1);
|
|
||||||
// padding-right: map-get($spacer, 1);
|
|
||||||
|
|
||||||
// &:first-child {
|
|
||||||
// padding-left: 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// &:last-child {
|
|
||||||
// padding-right: 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @media screen and (max-width: 768px) {
|
|
||||||
// .sm-page-workshop-list .toolbar {
|
|
||||||
// flex-direction: column;
|
|
||||||
|
|
||||||
// & > * {
|
|
||||||
// padding-left: 0;
|
|
||||||
// padding-right: 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,67 +1,70 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMMastHead title="Dashboard" />
|
<SMMastHead title="Dashboard" />
|
||||||
<div class="boxes">
|
<SMContainer>
|
||||||
<router-link to="/dashboard/details" class="box">
|
<div class="cards">
|
||||||
|
<router-link to="/dashboard/details" class="admin-card details">
|
||||||
<ion-icon name="location-outline" />
|
<ion-icon name="location-outline" />
|
||||||
<h2>My Details</h2>
|
<h3>My Details</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/posts')"
|
v-if="userStore.permissions.includes('admin/posts')"
|
||||||
:to="{ name: 'dashboard-post-list' }"
|
:to="{ name: 'dashboard-post-list' }"
|
||||||
class="box">
|
class="admin-card posts">
|
||||||
<ion-icon name="newspaper-outline" />
|
<ion-icon name="newspaper-outline" />
|
||||||
<h2>Posts</h2>
|
<h3>Posts</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/users')"
|
v-if="userStore.permissions.includes('admin/users')"
|
||||||
:to="{ name: 'dashboard-user-list' }"
|
:to="{ name: 'dashboard-user-list' }"
|
||||||
class="box">
|
class="admin-card users">
|
||||||
<ion-icon name="people-outline" />
|
<ion-icon name="people-outline" />
|
||||||
<h2>Users</h2>
|
<h3>Users</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/events')"
|
v-if="userStore.permissions.includes('admin/events')"
|
||||||
:to="{ name: 'dashboard-event-list' }"
|
:to="{ name: 'dashboard-event-list' }"
|
||||||
class="box">
|
class="admin-card events">
|
||||||
<ion-icon name="calendar-outline" />
|
<ion-icon name="calendar-outline" />
|
||||||
<h2>Events</h2>
|
<h3>Events</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/courses')"
|
v-if="userStore.permissions.includes('admin/courses')"
|
||||||
:to="{ name: 'dashboard-event-list' }"
|
:to="{ name: 'dashboard-event-list' }"
|
||||||
class="box">
|
class="admin-card courses">
|
||||||
<ion-icon name="school-outline" />
|
<ion-icon name="school-outline" />
|
||||||
<h2>{{ courseBoxTitle }}</h2>
|
<h3>{{ courseBoxTitle }}</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/media')"
|
v-if="userStore.permissions.includes('admin/media')"
|
||||||
:to="{ name: 'dashboard-media-list' }"
|
:to="{ name: 'dashboard-media-list' }"
|
||||||
class="box">
|
class="admin-card media">
|
||||||
<ion-icon name="film-outline" />
|
<ion-icon name="film-outline" />
|
||||||
<h2>Media</h2>
|
<h3>Media</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('admin/media')"
|
v-if="userStore.permissions.includes('admin/media')"
|
||||||
:to="{ name: 'dashboard-media-list' }"
|
:to="{ name: 'dashboard-media-list' }"
|
||||||
class="box"
|
class="admin-card minecraft"
|
||||||
style="background-image: url('/img/minecraft.png')">
|
style="background-image: url('/img/minecraft.png')">
|
||||||
<img src="/img/minecraft-grass-block.png" />
|
<img src="/img/minecraft-grass-block.png" />
|
||||||
<h2>Minecraft</h2>
|
<h3>Minecraft</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.permissions.includes('logs/discord')"
|
v-if="userStore.permissions.includes('logs/discord')"
|
||||||
:to="{ name: 'dashboard-discord-bot-logs' }"
|
:to="{ name: 'dashboard-discord-bot-logs' }"
|
||||||
class="box">
|
class="admin-card discord">
|
||||||
<ion-icon name="logo-discord" />
|
<ion-icon name="logo-discord" />
|
||||||
<h2>Discord Bot Logs</h2>
|
<h3>Discord Bot Logs</h3>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
</SMContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useUserStore } from "../../store/UserStore";
|
import { useUserStore } from "../../store/UserStore";
|
||||||
import SMMastHead from "../../components/SMMastHead.vue";
|
import SMMastHead from "../../components/SMMastHead.vue";
|
||||||
|
import SMContainer from "../../components/SMContainer.vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
@@ -75,51 +78,36 @@ const courseBoxTitle = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.boxes {
|
.page-dashboard {
|
||||||
|
.cards {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
gap: 30px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: -#{map-get($spacer, 3)};
|
|
||||||
|
|
||||||
.box {
|
.admin-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-basis: map-get($spacer, 5) * 4.5;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-radius: 12px;
|
flex-basis: 224px;
|
||||||
border: 2px solid $primary-color-dark;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
padding: map-get($spacer, 5) map-get($spacer, 4);
|
|
||||||
margin: map-get($spacer, 3);
|
|
||||||
font-size: map-get($spacer, 3);
|
|
||||||
color: $primary-color-dark !important;
|
|
||||||
margin-bottom: map-get($spacer, 5);
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
color: var(--base-color-text);
|
||||||
|
border-radius: 10px;
|
||||||
h2 {
|
background-color: var(--base-color-light);
|
||||||
margin-top: map-get($spacer, 2);
|
text-decoration: none;
|
||||||
margin-bottom: 0;
|
box-shadow: var(--base-shadow);
|
||||||
}
|
padding: 32px;
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
font-size: map-get($spacer, 5);
|
font-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: map-get($spacer, 5);
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&.minecraft {
|
||||||
text-decoration: none;
|
color: #eee;
|
||||||
background-color: $primary-color-lighter;
|
}
|
||||||
border-color: $primary-color-darker;
|
|
||||||
color: $primary-color-darker !important;
|
|
||||||
box-shadow: 0 0 14px rgba(0, 0, 0, 0.25);
|
|
||||||
transform: scale(1.01);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<SMPage class="sm-page-user-edit">
|
<SMMastHead
|
||||||
<template #container>
|
:title="pageHeading"
|
||||||
<SMHeading :heading="pageHeading" />
|
:back-link="{ name: 'dashboard' }"
|
||||||
|
back-title="Back to Dashboard" />
|
||||||
|
<SMContainer>
|
||||||
<SMForm :model-value="form" @submit="handleSubmit">
|
<SMForm :model-value="form" @submit="handleSubmit">
|
||||||
|
<SMRow>
|
||||||
|
<SMColumn><SMInput control="username" disabled /></SMColumn>
|
||||||
|
<SMColumn><SMInput control="display_name" /></SMColumn>
|
||||||
|
</SMRow>
|
||||||
<SMRow>
|
<SMRow>
|
||||||
<SMColumn><SMInput control="first_name" /></SMColumn>
|
<SMColumn><SMInput control="first_name" /></SMColumn>
|
||||||
<SMColumn><SMInput control="last_name" /></SMColumn>
|
<SMColumn><SMInput control="last_name" /></SMColumn>
|
||||||
</SMRow>
|
</SMRow>
|
||||||
<SMRow>
|
<SMRow>
|
||||||
<SMColumn><SMInput control="email" /></SMColumn>
|
<SMColumn><SMInput control="email" /></SMColumn>
|
||||||
<SMColumn><SMInput control="phone" /></SMColumn>
|
<SMColumn
|
||||||
|
><SMInput control="phone">This field is optional</SMInput>
|
||||||
|
</SMColumn>
|
||||||
</SMRow>
|
</SMRow>
|
||||||
<SMRow>
|
<SMRow>
|
||||||
<SMColumn>
|
<SMColumn>
|
||||||
@@ -25,31 +33,34 @@
|
|||||||
</SMColumn>
|
</SMColumn>
|
||||||
</SMRow>
|
</SMRow>
|
||||||
</SMForm>
|
</SMForm>
|
||||||
</template>
|
</SMContainer>
|
||||||
</SMPage>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, reactive } from "vue";
|
import { computed, reactive } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { openDialog } from "../../components/SMDialog";
|
import { openDialog } from "../../components/SMDialog";
|
||||||
import SMDialogChangePassword from "../../components/dialogs/SMDialogChangePassword.vue";
|
import SMDialogChangePassword from "../../components/dialogs/SMDialogChangePassword.vue";
|
||||||
import SMButton from "../../components/SMButton.vue";
|
import SMButton from "../../components/SMButton.vue";
|
||||||
import SMForm from "../../components/SMForm.vue";
|
import SMForm from "../../components/SMForm.vue";
|
||||||
import SMFormFooter from "../../components/SMFormFooter.vue";
|
import SMFormFooter from "../../components/SMFormFooter.vue";
|
||||||
import SMHeading from "../../components/SMHeading.vue";
|
import SMInput from "../../components/SMInput.vue";
|
||||||
import SMInput from "../../depreciated/SMInput-old.vue";
|
|
||||||
import { api } from "../../helpers/api";
|
import { api } from "../../helpers/api";
|
||||||
import { UserResponse } from "../../helpers/api.types";
|
import { UserResponse } from "../../helpers/api.types";
|
||||||
import { Form, FormControl } from "../../helpers/form";
|
import { Form, FormControl } from "../../helpers/form";
|
||||||
import { And, Email, Phone, Required } from "../../helpers/validate";
|
import { And, Email, Phone, Required } from "../../helpers/validate";
|
||||||
import { useUserStore } from "../../store/UserStore";
|
import { useUserStore } from "../../store/UserStore";
|
||||||
|
import SMMastHead from "../../components/SMMastHead.vue";
|
||||||
|
import { useToastStore } from "../../store/ToastStore";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
let form = reactive(
|
let form = reactive(
|
||||||
Form({
|
Form({
|
||||||
|
username: FormControl("", And([Required()])),
|
||||||
|
display_name: FormControl("", And([Required()])),
|
||||||
first_name: FormControl("", And([Required()])),
|
first_name: FormControl("", And([Required()])),
|
||||||
last_name: FormControl("", And([Required()])),
|
last_name: FormControl("", And([Required()])),
|
||||||
email: FormControl("", And([Required(), Email()])),
|
email: FormControl("", And([Required(), Email()])),
|
||||||
@@ -65,7 +76,7 @@ const loadData = async () => {
|
|||||||
try {
|
try {
|
||||||
form.loading(true);
|
form.loading(true);
|
||||||
const result = await api.get({
|
const result = await api.get({
|
||||||
url: "users/{id}",
|
url: "/users/{id}",
|
||||||
params: {
|
params: {
|
||||||
id: route.params.id,
|
id: route.params.id,
|
||||||
},
|
},
|
||||||
@@ -85,6 +96,7 @@ const loadData = async () => {
|
|||||||
form.loading(false);
|
form.loading(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
form.controls.username.value = userStore.username;
|
||||||
form.controls.first_name.value = userStore.firstName;
|
form.controls.first_name.value = userStore.firstName;
|
||||||
form.controls.last_name.value = userStore.lastName;
|
form.controls.last_name.value = userStore.lastName;
|
||||||
form.controls.phone.value = userStore.phone;
|
form.controls.phone.value = userStore.phone;
|
||||||
@@ -99,7 +111,7 @@ const handleSubmit = async () => {
|
|||||||
try {
|
try {
|
||||||
form.loading(true);
|
form.loading(true);
|
||||||
const result = await api.put({
|
const result = await api.put({
|
||||||
url: "users/{id}",
|
url: "/users/{id}",
|
||||||
params: {
|
params: {
|
||||||
id: userStore.id,
|
id: userStore.id,
|
||||||
},
|
},
|
||||||
@@ -117,7 +129,15 @@ const handleSubmit = async () => {
|
|||||||
userStore.setUserDetails(data.user);
|
userStore.setUserDetails(data.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
form.message("Your details have been updated", "success");
|
useToastStore().addToast({
|
||||||
|
title: route.params.id ? "Details Updated" : "User Created",
|
||||||
|
content: route.params.id
|
||||||
|
? "The user has been updated."
|
||||||
|
: "The user has been created.",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
router.push({ name: "dashboard" });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
form.apiErrors(err);
|
form.apiErrors(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user