Files
thetool/public/plugins/vue/tt-core
2025-12-09 05:34:24 +00:00
..
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00
2025-12-09 05:34:24 +00:00

TT-Core Component Library (Vue 3)

Modern, reusable Vue 3 components and utilities for TheTool applications. Built with the Composition API and designed for maximum performance and developer experience.

Version: 2.0.0 (Vue 3)

📦 What's Included

Components

Data Display

  • <tt-data-table> - Enhanced data table with loading states, skeletons, and placeholders
  • <tt-status-chip> - Smart online/offline status chip with lazy loading and IP copy

Feedback

  • <tt-loading-indicator> - Processing indicator with animated progress bar
  • <tt-skeleton> - Skeleton loader for loading states

Forms

  • <tt-smart-autocomplete> - Advanced autocomplete with mode switching (XINON/ESTMK)
  • <tt-file-dropzone> - Drag & drop file upload component

Overlays

  • <tt-dialog> - Modern modal dialog with portal rendering

Navigation

  • <tt-view-switcher> - Tab-based view switching with mobile support

Utilities

Available globally via window.TT_CORE:

// Clipboard
TT_CORE.copyToClipboard(text)

// Formatting
TT_CORE.formatBytes(bytes, decimals)
TT_CORE.formatDuration(seconds)
TT_CORE.formatNumber(num, decimals, decimalSep, thousandsSep)
TT_CORE.formatBits(bps)

// Validation
TT_CORE.calculateSimilarity(str1, str2)
TT_CORE.validateData(street, zip, city, info, threshold)
TT_CORE.validateEmail(email)
TT_CORE.generatePassword(length)

// Script Loading
TT_CORE.loadScript(src)
TT_CORE.loadScripts([src1, src2, ...])

Composables (Vue 3 Composition API)

// Use in setup() function with Composition API
import { useIntersectionObserver, useInfiniteScroll, useAsyncData } from 'window.TT_CORE';

// Intersection Observer
const { targetRef } = TT_CORE.useIntersectionObserver((entry) => {
    console.log('Element is visible!', entry);
}, { threshold: 0.1 });

// Infinite Scroll
const items = ref([...]);
const { sentinelRef, visibleItems, loadMore } = TT_CORE.useInfiniteScroll(items, {
    initialCount: 50,
    incrementBy: 50
});

// Async Data Fetching
const { data, isLoading, hasError, fetchData } = TT_CORE.useAsyncData();
await fetchData('/api/users');

Mixins (Options API - Backward Compatibility)

// Use with Options API (if not using Composition API)
export default {
    mixins: [
        TT_CORE.createIntersectionObserverMixin({ threshold: 0.1 }),
        TT_CORE.createInfiniteScrollMixin({ initialCount: 50 }),
        TT_CORE.createAsyncDataMixin()
    ]
}

🚀 Quick Start with Vue 3 CDN

1. Include Vue 3 and TT-Core

<!DOCTYPE html>
<html>
<head>
    <!-- TT-Core CSS -->
    <link rel="stylesheet" href="/public/plugins/vue/tt-core/styles/tt-core.css">

    <!-- Vue 3 CDN -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <div id="app">
        <tt-data-table :items="users" :is-loading="loading">
            <!-- ... -->
        </tt-data-table>
    </div>

    <!-- TT-Core Library -->
    <script src="/public/plugins/vue/tt-core/index.js" type="module"></script>

    <!-- TT-Core Components -->
    <script src="/public/plugins/vue/tt-core/components/data-display/TtDataTable.js"></script>
    <script src="/public/plugins/vue/tt-core/components/data-display/TtStatusChip.js"></script>
    <script src="/public/plugins/vue/tt-core/components/feedback/TtLoadingIndicator.js"></script>
    <script src="/public/plugins/vue/tt-core/components/feedback/TtSkeleton.js"></script>
    <script src="/public/plugins/vue/tt-core/components/forms/TtSmartAutocomplete.js"></script>
    <script src="/public/plugins/vue/tt-core/components/forms/TtFileDropzone.js"></script>
    <script src="/public/plugins/vue/tt-core/components/overlays/TtDialog.js"></script>
    <script src="/public/plugins/vue/tt-core/components/navigation/TtViewSwitcher.js"></script>

    <!-- Your App -->
    <script>
        const { createApp, ref } = Vue;

        const app = createApp({
            setup() {
                const users = ref([
                    { name: 'John', email: 'john@example.com' },
                    { name: 'Jane', email: 'jane@example.com' }
                ]);
                const loading = ref(false);

                return { users, loading };
            }
        });

        // IMPORTANT: Register TT-Core components with your app
        TT_CORE.registerComponents(app);

        app.mount('#app');
    </script>
</body>
</html>

📘 Component Usage Examples

Data Table

<script setup>
import { ref } from 'vue';

const users = ref([...]);
const loading = ref(false);
const hasSearched = ref(true);
</script>

<template>
    <tt-data-table
        :items="users"
        :is-loading="loading"
        :has-searched="hasSearched"
        density="compact"
    >
        <template #head>
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Status</th>
                </tr>
            </thead>
        </template>

        <template #skeleton-row>
            <td><tt-skeleton /></td>
            <td><tt-skeleton /></td>
            <td><tt-skeleton width="80px" /></td>
        </template>

        <template #row="{ item, index }">
            <td>{{ item.name }}</td>
            <td>{{ item.email }}</td>
            <td>
                <tt-status-chip
                    :username="item.username"
                    @scan-ip="handleScan"
                />
            </td>
        </template>
    </tt-data-table>
</template>

Smart Autocomplete (v-model support)

<script setup>
import { ref } from 'vue';

const customerName = ref('');

const handleSelect = ({ custnum, display }) => {
    console.log('Selected:', custnum, display);
};
</script>

<template>
    <tt-smart-autocomplete
        v-model="customerName"
        placeholder="Suche Kunde..."
        @select="handleSelect"
        @enter="search"
    />
</template>

File Dropzone

<script setup>
const handleFile = async (file) => {
    console.log('File selected:', file.name);
    // Process file...
};
</script>

<template>
    <tt-file-dropzone
        accept=".xlsx,.xls"
        @file-selected="handleFile"
        buttonText="Datei auswählen"
    />
</template>

Dialog/Modal

<script setup>
import { ref } from 'vue';

const showModal = ref(false);
</script>

<template>
    <tt-dialog
        :show="showModal"
        title="User Details"
        size="wide"
        @close="showModal = false"
    >
        <p>Modal content here...</p>

        <template #footer>
            <button @click="save">Save</button>
            <button @click="showModal = false">Cancel</button>
        </template>
    </tt-dialog>
</template>

View Switcher (v-model support)

<script setup>
import { ref } from 'vue';

const currentView = ref('users');

const views = [
    { id: 'users', name: 'Users', icon: 'fa fa-users' },
    { id: 'settings', name: 'Settings', icon: 'fa fa-cog' }
];
</script>

<template>
    <tt-view-switcher
        v-model="currentView"
        :options="views"
    />

    <div v-if="currentView === 'users'">Users View</div>
    <div v-else-if="currentView === 'settings'">Settings View</div>
</template>

🎯 Using Composables in Your Components

Intersection Observer

<script setup>
const { targetRef } = window.TT_CORE.useIntersectionObserver((entry) => {
    console.log('Element visible!', entry);
}, { threshold: 0.5, once: true });
</script>

<template>
    <div ref="targetRef">
        I will trigger when 50% visible!
    </div>
</template>

Infinite Scroll

<script setup>
import { ref } from 'vue';

const allItems = ref([/* 1000 items */]);

const { sentinelRef, visibleItems, hasMore } = window.TT_CORE.useInfiniteScroll(allItems, {
    initialCount: 50,
    incrementBy: 25
});
</script>

<template>
    <div>
        <div v-for="item in visibleItems" :key="item.id">
            {{ item.name }}
        </div>

        <!-- Sentinel element for infinite scroll -->
        <div ref="sentinelRef" v-if="hasMore">Loading more...</div>
    </div>
</template>

Async Data Fetching

<script setup>
import { onMounted } from 'vue';

const { data, isLoading, hasError, errorMessage, fetchData } = window.TT_CORE.useAsyncData();

onMounted(async () => {
    await fetchData('/api/users');
});
</script>

<template>
    <div>
        <div v-if="isLoading">Loading...</div>
        <div v-else-if="hasError">Error: {{ errorMessage }}</div>
        <div v-else>
            <div v-for="user in data" :key="user.id">
                {{ user.name }}
            </div>
        </div>
    </div>
</template>

🔧 Options API (Traditional Vue Syntax)

If you prefer the Options API over Composition API:

<template>
    <div>
        <tt-data-table :items="users" :is-loading="loading">
            <!-- ... -->
        </tt-data-table>
    </div>
</template>

<script>
export default {
    mixins: [
        window.TT_CORE.createInfiniteScrollMixin({
            initialCount: 50,
            itemsKey: 'users'
        })
    ],

    data() {
        return {
            users: [],
            loading: false
        };
    },

    mounted() {
        this.loadUsers();
    },

    methods: {
        async loadUsers() {
            this.loading = true;
            // ... fetch logic
            this.loading = false;
        }
    }
}
</script>

📝 Migration from Vue 2

Key Changes

  1. Component Registration:

    • Vue 2: Components auto-register globally via Vue.component()
    • Vue 3: Must call TT_CORE.registerComponents(app) after creating your app
  2. v-model:

    • Vue 2: v-modelvalue prop + input event
    • Vue 3: v-modelmodelValue prop + update:modelValue event
  3. Lifecycle Hooks:

    • beforeDestroybeforeUnmount
    • destroyedunmounted
  4. Composables:

    • Vue 2: Use mixins with createXxxMixin()
    • Vue 3: Use composables with useXxx() in setup()

Update Your Code:

// Vue 2
const app = new Vue({
    el: '#app',
    data: { ... }
});

// Vue 3
const { createApp } = Vue;
const app = createApp({
    setup() {
        // Composition API
    }
});
TT_CORE.registerComponents(app);  // ← REQUIRED!
app.mount('#app');

🎨 Styling

All components use the .tt-scope class for scoping. Customize via CSS variables:

:root {
    --tt-brand-blue: #005384;
    --tt-accent: #005384;
    --tt-accent-2: #1e88c9;
    --tt-ok: #0f9d58;
    --tt-bad: #e03131;
    --tt-border: #e6e9ef;
    --tt-radius: 10px;
    --tt-shadow: 0 8px 24px rgba(0, 83, 132, .08);
}

📁 Directory Structure

tt-core/
├── index.js                 # Main entry point (Vue 3)
├── README.md                # This file
├── MIGRATION_GUIDE.md       # Detailed migration guide
├── SUMMARY.md               # Project summary
├── utils/                   # Utility functions
│   ├── clipboard.js
│   ├── formatting.js
│   ├── validation.js
│   └── script-loader.js
├── components/              # Vue 3 components
│   ├── data-display/
│   │   ├── TtDataTable.js
│   │   └── TtStatusChip.js
│   ├── feedback/
│   │   ├── TtLoadingIndicator.js
│   │   └── TtSkeleton.js
│   ├── forms/
│   │   ├── TtSmartAutocomplete.js
│   │   └── TtFileDropzone.js
│   ├── overlays/
│   │   └── TtDialog.js
│   └── navigation/
│       └── TtViewSwitcher.js
├── composables/             # Vue 3 composables + mixins
│   ├── useIntersectionObserver.js
│   ├── useInfiniteScroll.js
│   └── useAsyncData.js
└── styles/                  # CSS styles
    └── tt-core.css

🚀 Performance Tips

  1. Lazy Load Components: Only load components you need
  2. Use Composition API: Better tree-shaking and performance
  3. Leverage Composables: Reuse logic across components
  4. CSS Variables: Fast theme changes without re-rendering

🐛 Troubleshooting

Components not rendering?

Make sure you called TT_CORE.registerComponents(app) after creating your Vue app!

const app = createApp({...});
TT_CORE.registerComponents(app);  // ← Don't forget!
app.mount('#app');

v-model not working?

Vue 3 uses modelValue instead of value. TT-Core components support both automatically.

Composables not working?

Make sure you're using them inside setup() or <script setup>:

<script setup>
// ✅ Correct
const { data } = TT_CORE.useAsyncData();
</script>

<script>
export default {
    // ❌ Wrong - can't use composables here
    data() {
        const { data } = TT_CORE.useAsyncData(); // Error!
    }
}
</script>

📚 Additional Resources

📝 License

Internal use only - TheTool Development Team


Version: 2.0.0 (Vue 3) Last Updated: December 2024