mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-08-18 08:27:14 +02:00
Improved dark mode Added company banner and moved change company Changed campaign trends, and now requires 2 campaigns atleast Menu collapses if open and link clicked Changed calendar event type indicator Changed mobile menu Changed campaign event timeline and event cards Various UI changes Signed-off-by: Ronni Skansing <rskansing@gmail.com>
136 lines
3.2 KiB
Svelte
136 lines
3.2 KiB
Svelte
<script>
|
|
import { tweened } from 'svelte/motion';
|
|
import { cubicOut } from 'svelte/easing';
|
|
|
|
export let title = '';
|
|
export let value = 0;
|
|
export let borderColor = 'border-cta-blue';
|
|
export let iconColor = 'text-cta-blue';
|
|
export let percentages = [];
|
|
|
|
let initialValueSet = false;
|
|
let previousValue = 0;
|
|
let flash = false;
|
|
let currentPercentageIndex = 0;
|
|
|
|
const displayValue = tweened(0, {
|
|
duration: 200,
|
|
easing: cubicOut
|
|
});
|
|
|
|
$: validPercentages = percentages.filter((p) => p.baseValue && p.baseValue > 0);
|
|
|
|
$: {
|
|
if (!initialValueSet && value > 0) {
|
|
displayValue.set(value, { duration: 0 });
|
|
initialValueSet = true;
|
|
previousValue = value;
|
|
} else if (initialValueSet && value !== previousValue) {
|
|
displayValue.set(value);
|
|
if (value > previousValue) {
|
|
flash = true;
|
|
setTimeout(() => (flash = false), 1000);
|
|
}
|
|
previousValue = value;
|
|
}
|
|
}
|
|
|
|
function cyclePercentage() {
|
|
if (validPercentages.length > 1) {
|
|
currentPercentageIndex = (currentPercentageIndex + 1) % validPercentages.length;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
class="bg-white dark:bg-gray-900/80 p-6 rounded-lg shadow-md dark:shadow-none border-l-[12px] {borderColor} hover:shadow-lg dark:hover:shadow-none transition-all duration-200 dark:ring-1 dark:ring-gray-600/30"
|
|
>
|
|
<div
|
|
class="text-grayblue-dark dark:text-gray-500 text-sm font-semibold transition-colors duration-200"
|
|
>
|
|
{title}
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center">
|
|
<span
|
|
class="text-3xl font-bold text-pc-darkblue dark:text-gray-300 transition-colors duration-200 {flash
|
|
? 'flash'
|
|
: ''}"
|
|
>
|
|
{Math.floor($displayValue)}
|
|
</span>
|
|
<div class="ml-2">
|
|
<slot name="icon">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-5 w-5 {iconColor}"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M13 10V3L4 14h7v7l9-11h-7z"
|
|
/>
|
|
</svg>
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{#if validPercentages.length > 0}
|
|
<button
|
|
class="mt-2 text-sm text-gray-600 dark:text-gray-500 flex items-center transition-colors duration-200"
|
|
on:click={cyclePercentage}
|
|
class:cursor-pointer={validPercentages.length > 1}
|
|
>
|
|
<div class="flex items-center">
|
|
<span
|
|
class="text-pc-darkblue dark:text-gray-400 font-semibold transition-colors duration-200"
|
|
>
|
|
{validPercentages[currentPercentageIndex].value}%
|
|
</span>
|
|
<span class="ml-1">
|
|
{validPercentages[currentPercentageIndex].relativeTo}
|
|
</span>
|
|
</div>
|
|
{#if validPercentages.length > 1}
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-4 w-4 ml-1 text-gray-400 dark:text-gray-600 transition-colors duration-200"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
|
|
/>
|
|
</svg>
|
|
{/if}
|
|
</button>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.flash {
|
|
animation: flash-animation 1s ease-out;
|
|
}
|
|
|
|
@keyframes flash-animation {
|
|
0% {
|
|
color: inherit;
|
|
}
|
|
25% {
|
|
color: #5dd8c4;
|
|
}
|
|
100% {
|
|
color: inherit;
|
|
}
|
|
}
|
|
</style>
|