332 lines
13 KiB
Vue
332 lines
13 KiB
Vue
<template>
|
|
<Modal :is-open="isOpen" @close="close" title="Help & information" :initialWidth="800" :initialHeight="600">
|
|
<div class="flex flex-col h-full">
|
|
<!-- Tabs -->
|
|
<div class="flex border-b border-gray-200">
|
|
<button v-for="(tab, index) in tabs" :key="index" @click="activeTab = index" class="px-4 py-2 font-medium text-sm transition-colors" :class="activeTab === index ? 'text-blue-600 border-b-2 border-blue-500' : 'text-gray-600 hover:text-blue-500'">
|
|
{{ tab.name }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Tab Content -->
|
|
<div class="flex-1 overflow-auto p-4">
|
|
<!-- Video Instructions Tab -->
|
|
<div v-if="activeTab === 0" class="h-full flex flex-col">
|
|
<h3 class="text-lg font-semibold mb-4">Video tutorial</h3>
|
|
<div class="flex-1 bg-gray-100 rounded-lg flex items-center justify-center">
|
|
<div class="w-full aspect-video max-w-3xl mx-auto">
|
|
<video controls class="w-full h-full object-contain rounded-lg shadow-md">
|
|
<source src="@/assets/tut.mp4" type="video/mp4" />
|
|
</video>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- About & Instructions Tab -->
|
|
<div v-if="activeTab === 1" class="h-full overflow-y-auto">
|
|
<h3 class="text-lg font-semibold mb-4">About Spritesheet generator</h3>
|
|
|
|
<div class="max-w-none text-gray-700">
|
|
<p class="mb-4 text-base leading-relaxed">Spritesheet generator is a free, open-source tool for creating spritesheets for game development and animation projects. This tool allows you to upload individual sprite images and arrange them into a spritesheet with customizable layout.</p>
|
|
|
|
<h4 class="mt-6 mb-3 text-lg font-medium text-gray-900">How to use:</h4>
|
|
<ol class="list-decimal pl-6 space-y-2 mb-4">
|
|
<li>Upload your sprite images by dragging and dropping them or clicking the upload area</li>
|
|
<li>If you upload a single large image, you'll be asked if you want to split it into individual sprites</li>
|
|
<li>Arrange your sprites by dragging them to the desired position</li>
|
|
<li>Adjust the number of columns to change the layout</li>
|
|
<li>Preview your animation using the "Preview Animation" button</li>
|
|
<li>Download your spritesheet as a PNG file</li>
|
|
</ol>
|
|
|
|
<h4 class="mt-6 mb-3 text-lg font-medium text-gray-900">Tips:</h4>
|
|
<ul class="list-disc pl-6 space-y-2">
|
|
<li>For best results, use sprites with consistent dimensions</li>
|
|
<li>When uploading a spritesheet, you can split it automatically into individual sprites</li>
|
|
<li>The spritesheet splitter allows you to specify rows and columns or try auto-detection</li>
|
|
<li>The preview animation plays frames in the order they appear in the spritesheet (left to right, top to bottom)</li>
|
|
<li>You can adjust the animation speed in the preview window</li>
|
|
<li>The tool works entirely in your browser - no files are uploaded to any server</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Donations Tab -->
|
|
<div v-if="activeTab === 2" class="h-full overflow-y-auto">
|
|
<h3 class="text-lg font-semibold mb-4">Support my <a href="https://xvx.sh" title="XVX" target="_blank" class="text-blue-500 hover:text-blue-600 transition-colors">projects</a>.</h3>
|
|
|
|
<p class="mb-6">
|
|
Spritesheet generator is free and open-source software. If you find it useful, please consider supporting the project with a donation. Check out the source code on
|
|
<a href="https://gitea.directonline.io/noxious/spritesheet-generator" title="Source code" target="_blank" class="text-blue-500 hover:text-blue-600 transition-colors">Gitea</a>.
|
|
</p>
|
|
|
|
<div class="space-y-6">
|
|
<!-- Bitcoin -->
|
|
<div class="p-4 bg-gray-50 rounded-lg border border-gray-200">
|
|
<div class="flex items-center mb-3">
|
|
<div class="w-8 h-8 mr-3 flex items-center justify-center bg-orange-100 rounded-full">
|
|
<svg class="w-5 h-5 text-orange-500" viewBox="0 0 24 24" fill="currentColor">
|
|
<path
|
|
d="M23.638 14.904c-1.602 6.43-8.113 10.34-14.542 8.736C2.67 22.05-1.244 15.525.362 9.105 1.962 2.67 8.475-1.243 14.9.358c6.43 1.605 10.342 8.115 8.738 14.548v-.002zm-6.35-4.613c.24-1.59-.974-2.45-2.64-3.03l.54-2.153-1.315-.33-.525 2.107c-.345-.087-.705-.167-1.064-.25l.526-2.127-1.32-.33-.54 2.165c-.285-.067-.565-.132-.84-.2l-1.815-.45-.35 1.407s.975.225.955.236c.535.136.63.486.615.766l-1.477 5.92c-.075.166-.24.406-.614.314.015.02-.96-.24-.96-.24l-.66 1.51 1.71.426.93.242-.54 2.19 1.32.327.54-2.17c.36.1.705.19 1.05.273l-.51 2.154 1.32.33.545-2.19c2.24.427 3.93.257 4.64-1.774.57-1.637-.03-2.58-1.217-3.196.854-.193 1.5-.76 1.68-1.93h.01zm-3.01 4.22c-.404 1.64-3.157.75-4.05.53l.72-2.9c.896.23 3.757.67 3.33 2.37zm.41-4.24c-.37 1.49-2.662.735-3.405.55l.654-2.64c.744.18 3.137.524 2.75 2.084v.006z"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<h4 class="text-md font-medium">Bitcoin (BTC)</h4>
|
|
</div>
|
|
<div class="flex">
|
|
<input type="text" readonly value="bc1ql2a3nxnhfwft7qex0cclj5ar2lfsslvs0aygeq" class="flex-1 p-2 text-sm bg-white border border-gray-200 rounded-l-md focus:outline-none" />
|
|
<button @click="copyToClipboard('bc1ql2a3nxnhfwft7qex0cclj5ar2lfsslvs0aygeq')" class="px-3 bg-blue-500 text-white rounded-r-md hover:bg-blue-600 transition-colors">Copy</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Litecoin -->
|
|
<div class="p-4 bg-gray-50 rounded-lg border border-gray-200">
|
|
<div class="flex items-center mb-3">
|
|
<div class="w-8 h-8 mr-3 flex items-center justify-center bg-blue-100 rounded-full">
|
|
<svg class="w-5 h-5 text-blue-500" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M12 0a12 12 0 1 0 0 24 12 12 0 0 0 0-24zm-.738 4.8h2.616l-1.654 6.187 2.566-.338-1.017 3.63-2.115.338-1.23 4.6h7.12l-.56 2.07H6.96l1.654-6.16-2.565.337.952-3.38 2.18-.338 1.23-4.662H4.8l.504-2.285h5.958z" />
|
|
</svg>
|
|
</div>
|
|
<h4 class="text-md font-medium">Litecoin (LTC)</h4>
|
|
</div>
|
|
<div class="flex">
|
|
<input type="text" readonly value="ltc1qdkn46hpt39ppmhk25ed2eycu7m2pj5cdzuxw84" class="flex-1 p-2 text-sm bg-white border border-gray-200 rounded-l-md focus:outline-none" />
|
|
<button @click="copyToClipboard('ltc1qdkn46hpt39ppmhk25ed2eycu7m2pj5cdzuxw84')" class="px-3 bg-blue-500 text-white rounded-r-md hover:bg-blue-600 transition-colors">Copy</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ethereum -->
|
|
<div class="p-4 bg-gray-50 rounded-lg border border-gray-200">
|
|
<div class="flex items-center mb-3">
|
|
<div class="w-8 h-8 mr-3 flex items-center justify-center bg-purple-100 rounded-full">
|
|
<svg class="w-5 h-5 text-purple-500" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M11.944 17.97L4.58 13.62 11.943 24l7.37-10.38-7.372 4.35h.003zM12.056 0L4.69 12.223l7.365 4.354 7.365-4.35L12.056 0z" />
|
|
</svg>
|
|
</div>
|
|
<h4 class="text-md font-medium">Ethereum (ETH)</h4>
|
|
</div>
|
|
<div class="flex">
|
|
<input type="text" readonly value="0x30843c72DF6E9A9226d967bf2403602f1C2aB67b" class="flex-1 p-2 text-sm bg-white border border-gray-200 rounded-l-md focus:outline-none" />
|
|
<button @click="copyToClipboard('0x30843c72DF6E9A9226d967bf2403602f1C2aB67b')" class="px-3 bg-blue-500 text-white rounded-r-md hover:bg-blue-600 transition-colors">Copy</button>
|
|
</div>
|
|
</div>
|
|
|
|
<p class="text-center text-gray-600 mt-6">Thank you for your support! ❤️</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Changelog Tab -->
|
|
<div v-if="activeTab === 3" class="h-full overflow-y-auto changelog-container">
|
|
<h3 class="text-lg font-semibold mb-4">Changelog</h3>
|
|
|
|
<div v-if="!changelogHtml" class="text-gray-500 text-center py-8">Loading changelog...</div>
|
|
|
|
<div v-else class="prose prose-sm max-w-none" v-html="changelogHtml"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue';
|
|
import { marked } from 'marked';
|
|
import Modal from './utilities/Modal.vue';
|
|
|
|
const props = defineProps<{
|
|
isOpen: boolean;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'close'): void;
|
|
}>();
|
|
|
|
const activeTab = ref(0);
|
|
const changelogHtml = ref<string>('');
|
|
|
|
const tabs = [{ name: 'Video tutorial' }, { name: 'About & instructions' }, { name: 'Support the project' }, { name: 'Changelog' }];
|
|
|
|
const loadChangelog = async () => {
|
|
try {
|
|
const response = await fetch('/CHANGELOG.md');
|
|
const text = await response.text();
|
|
|
|
// Configure marked options
|
|
marked.setOptions({
|
|
gfm: true, // GitHub Flavored Markdown
|
|
breaks: true, // Convert line breaks to <br>
|
|
});
|
|
|
|
// Convert markdown to HTML
|
|
changelogHtml.value = await marked(text);
|
|
} catch (error) {
|
|
console.error('Failed to load changelog:', error);
|
|
changelogHtml.value = '<p class="text-red-500">Failed to load changelog</p>';
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
loadChangelog();
|
|
});
|
|
|
|
const close = () => {
|
|
emit('close');
|
|
};
|
|
|
|
const copyToClipboard = (text: string) => {
|
|
navigator.clipboard
|
|
.writeText(text)
|
|
.then(() => {
|
|
alert('Address copied to clipboard!');
|
|
})
|
|
.catch(err => {
|
|
console.error('Failed to copy: ', err);
|
|
});
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
/* Global styles for changelog content */
|
|
.changelog-container .prose {
|
|
color: #374151; /* text-gray-700 */
|
|
}
|
|
|
|
.changelog-container .prose h1 {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
margin-bottom: 1rem;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
.changelog-container .prose h2 {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
margin-bottom: 0.75rem;
|
|
margin-top: 1.25rem;
|
|
border-left-width: 2px;
|
|
padding-left: 1rem;
|
|
padding-top: 0.5rem;
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
.changelog-container .prose h2:first-of-type {
|
|
border-left-color: #3b82f6; /* border-blue-500 */
|
|
}
|
|
|
|
.changelog-container .prose h2:not(:first-of-type) {
|
|
border-left-color: #d1d5db; /* border-gray-300 */
|
|
}
|
|
|
|
.changelog-container .prose h3 {
|
|
font-size: 1.125rem;
|
|
font-weight: 500;
|
|
margin-bottom: 0.5rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose h4 {
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
margin-bottom: 0.5rem;
|
|
margin-top: 0.75rem;
|
|
}
|
|
|
|
.changelog-container .prose ul {
|
|
list-style-type: disc;
|
|
list-style-position: inside;
|
|
margin-bottom: 1rem;
|
|
margin-left: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose ol {
|
|
list-style-type: decimal;
|
|
list-style-position: inside;
|
|
margin-bottom: 1rem;
|
|
margin-left: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose li {
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.changelog-container .prose p {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose a {
|
|
color: #3b82f6; /* text-blue-500 */
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.changelog-container .prose a:hover {
|
|
color: #2563eb; /* text-blue-600 */
|
|
}
|
|
|
|
.changelog-container .prose strong {
|
|
font-weight: 700;
|
|
}
|
|
|
|
.changelog-container .prose em {
|
|
font-style: italic;
|
|
}
|
|
|
|
.changelog-container .prose blockquote {
|
|
padding-left: 1rem;
|
|
border-left-width: 4px;
|
|
border-left-color: #d1d5db; /* border-gray-300 */
|
|
font-style: italic;
|
|
margin-top: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose code {
|
|
background-color: #f3f4f6; /* bg-gray-100 */
|
|
border-radius: 0.25rem;
|
|
padding-left: 0.25rem;
|
|
padding-right: 0.25rem;
|
|
padding-top: 0.125rem;
|
|
padding-bottom: 0.125rem;
|
|
font-family: monospace;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.changelog-container .prose pre {
|
|
background-color: #f3f4f6; /* bg-gray-100 */
|
|
border-radius: 0.25rem;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.changelog-container .prose pre code {
|
|
background-color: transparent;
|
|
padding: 0;
|
|
}
|
|
|
|
.changelog-container .prose hr {
|
|
margin-top: 2rem;
|
|
margin-bottom: 2rem;
|
|
border-top-width: 1px;
|
|
border-color: #e5e7eb; /* border-gray-200 */
|
|
}
|
|
|
|
.changelog-container .prose table {
|
|
width: 100%;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.changelog-container .prose th {
|
|
padding: 0.5rem 1rem;
|
|
border-width: 1px;
|
|
border-color: #d1d5db; /* border-gray-300 */
|
|
background-color: #f9fafb; /* bg-gray-50 */
|
|
font-weight: 600;
|
|
}
|
|
|
|
.changelog-container .prose td {
|
|
padding: 0.5rem 1rem;
|
|
border-width: 1px;
|
|
border-color: #d1d5db; /* border-gray-300 */
|
|
}
|
|
</style>
|