From 1dc32781259285d7b8cb6fedfa6c58f613389692 Mon Sep 17 00:00:00 2001 From: SnaveSutit Date: Sun, 2 Mar 2025 19:37:11 -0500 Subject: [PATCH 01/20] =?UTF-8?q?=E2=9C=A8=20Add=20a=20search=20bar=20to?= =?UTF-8?q?=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also updated ESLint and improved config (sorry not sorry that I did it all in one commit 😈) --- eslint.config.js | 33 -- eslint.config.ts | 266 ++++++++++++ package.json | 14 +- src/lib/styles/kit-docs.css | 4 +- src/routes/+layout.svelte | 16 +- src/types/global.d.ts | 2 +- tslintNamingConventionRule.d.ts | 185 ++++++++ yarn.lock | 739 ++++++++++++++++++++++---------- 8 files changed, 991 insertions(+), 268 deletions(-) delete mode 100644 eslint.config.js create mode 100644 eslint.config.ts create mode 100644 tslintNamingConventionRule.d.ts diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 5a7eb2c..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,33 +0,0 @@ -import js from '@eslint/js' -import ts from 'typescript-eslint' -import svelte from 'eslint-plugin-svelte' -import prettier from 'eslint-config-prettier' -import globals from 'globals' - -/** @type {import('eslint').Linter.FlatConfig[]} */ -export default [ - js.configs.recommended, - ...ts.configs.recommended, - ...svelte.configs['flat/recommended'], - prettier, - ...svelte.configs['flat/prettier'], - { - languageOptions: { - globals: { - ...globals.browser, - ...globals.node - } - } - }, - { - files: ['**/*.svelte'], - languageOptions: { - parserOptions: { - parser: ts.parser - } - } - }, - { - ignores: ['build/', '.svelte-kit/', 'dist/'] - } -] diff --git a/eslint.config.ts b/eslint.config.ts new file mode 100644 index 0000000..a0a29b1 --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,266 @@ +import svelteEslint from 'eslint-plugin-svelte' +import svelteParser from 'svelte-eslint-parser' +import tsESLint, { type ConfigWithExtends } from 'typescript-eslint' +import svelteConfig from './svelte.config' +import type { NamingConventionRule } from './tslintNamingConventionRule' + +console.log(`[${new Date().toLocaleTimeString()}] Loading ESLint config`) + +const IGNORE_PATTERNS = [ + '.DS_Store', + '.env', + '.env.*', + '.github', + '.vscode', + '**/node_modules/**', + + // Blockbench Plugin Template + 'dist/**/*', + + // Ignore files for PNPM, NPM and YARN + 'pnpm-lock.yaml', + 'package-lock.json', + 'yarn.lock' +] + +const CUSTOM_RULES: ConfigWithExtends['rules'] = { + // ESLint + semi: ['error', 'never'], + 'prefer-const': 'warn', + 'no-fallthrough': 'off', + 'no-mixed-spaces-and-tabs': 'off', + 'no-unreachable': 'warn', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + vars: 'local', + args: 'after-used', + argsIgnorePattern: '^_', + ignoreRestSiblings: true + } + ], + // Svelte + 'svelte/html-quotes': ['warn', { prefer: 'double' }], + 'svelte/block-lang': ['error', { script: ['ts', null], style: null }], + 'svelte/comment-directive': ['error', { reportUnusedDisableDirectives: true }], + // Check File + 'check-file/filename-naming-convention': [ + 'error', + { + 'src/**/*.{ts.d.ts}': 'CAMEL_CASE', + 'tools/**/*.{ts.d.ts}': 'CAMEL_CASE' + } + ], + 'check-file/folder-naming-convention': [ + 'error', + { + 'src/**': 'KEBAB_CASE', + 'tools/**': 'KEBAB_CASE' + } + ], + // TypeScript + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], + '@typescript-eslint/array-type': ['warn', { default: 'array-simple' }], + '@typescript-eslint/consistent-indexed-object-style': ['warn', 'record'], + '@typescript-eslint/consistent-generic-constructors': 'warn', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/require-await': 'warn', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/triple-slash-reference': 'off', + // Naming conventions + '@typescript-eslint/naming-convention': [ + 'warn', + { + // DFU Version imports + selector: ['import'], + modifiers: ['default'], + filter: { + regex: 'v\\d+_\\d+_\\d+$', + match: true + }, + custom: { + match: true, + regex: 'v\\d+_\\d+_\\d+$' + }, + format: null + }, + { + selector: ['import'], + modifiers: ['default'], + format: ['camelCase', 'PascalCase', 'UPPER_CASE'] + }, + { + selector: 'class', + format: ['PascalCase'] + }, + { + selector: ['classProperty', 'classMethod'], + format: ['camelCase'] + }, + { + selector: ['classProperty', 'classMethod'], + leadingUnderscore: 'allow', + format: ['camelCase'] + }, + { + selector: ['classProperty', 'classMethod'], + modifiers: ['private'], + leadingUnderscore: 'allowDouble', + trailingUnderscore: 'allowDouble', + format: ['camelCase'] + }, + { + selector: 'typeProperty', + format: null + }, + { + selector: 'variable', + modifiers: ['const', 'destructured'], + format: null + }, + { + selector: 'variable', + modifiers: ['const', 'global'], + types: ['function'], + leadingUnderscore: 'allow', + format: ['UPPER_CASE', 'camelCase'] + }, + { + selector: 'variable', + modifiers: ['const', 'global'], + leadingUnderscore: 'allow', + format: ['UPPER_CASE'] + }, + { + selector: 'variable', + modifiers: ['const', 'exported'], + format: ['camelCase', 'UPPER_CASE'] + }, + { + selector: 'variableLike', + format: ['camelCase'] + }, + { selector: 'interface', format: ['PascalCase'] }, + { + selector: 'interface', + modifiers: ['exported'], + format: ['PascalCase'], + prefix: ['I'] + }, + { selector: 'typeLike', format: ['PascalCase'] }, + { selector: 'objectLiteralProperty', format: null }, + { selector: 'default', format: ['camelCase'] }, + { + selector: 'parameter', + modifiers: ['unused'], + format: ['camelCase'], + leadingUnderscore: 'allow' + }, + { + selector: 'parameter', + format: ['camelCase'] + }, + { + selector: 'enumMember', + format: ['camelCase', 'PascalCase', 'UPPER_CASE'] + }, + { + selector: 'enum', + format: ['UPPER_CASE'] + } + ] satisfies NamingConventionRule +} + +export default tsESLint.config( + { + ignores: IGNORE_PATTERNS + }, + ...tsESLint.configs.stylisticTypeChecked, + ...svelteEslint.configs['flat/prettier'], + { + plugins: { + '@typescript-eslint': tsESLint.plugin, + svelte: svelteEslint + } + }, + { + rules: CUSTOM_RULES + }, + { + languageOptions: { + parser: tsESLint.parser, + parserOptions: { + project: './tsconfig.json', + extraFileExtensions: ['.svelte'] + }, + globals: { + browser: true, + node: true + } + } + }, + { + files: ['**/*.svelte'], + rules: { + // Causes issues with Svelte and global types + 'no-undef': 'off', + '@typescript-eslint/naming-convention': [ + 'warn', + { + selector: 'variable', + modifiers: ['exported'], + format: ['camelCase'] + }, + { + selector: 'variable', + modifiers: ['const', 'global'], + format: ['UPPER_CASE'] + }, + { + selector: 'variable', + modifiers: ['const', 'global'], + types: ['function'], + format: ['camelCase'] + }, + { + selector: 'variable', + format: ['camelCase'], + leadingUnderscore: 'allow' + } + ] satisfies NamingConventionRule + }, + languageOptions: { + parser: svelteParser, + parserOptions: { + parser: tsESLint.parser, + svelteConfig: svelteConfig, + extraFileExtensions: ['.svelte'] + }, + globals: { + browser: true, + node: true + } + }, + settings: { + ignoreWarnings: ['svelte/a11y-no-onchange', 'a11y-no-onchange'] + } + }, + { + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: '.' + } + }, + linterOptions: { + reportUnusedDisableDirectives: true + } + } +) diff --git a/package.json b/package.json index 4e6e08c..3d5239b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "format": "prettier --write ." }, "devDependencies": { + "@algolia/client-search": "^5.20.3", + "@docsearch/css": "^3.9.0", + "@docsearch/js": "^3.9.0", "@iconify-json/ri": "^1.0.0", "@iconify/json": "^2.2.219", "@sveltejs/adapter-auto": "^3.0.0", @@ -20,19 +23,24 @@ "@sveltejs/vite-plugin-svelte": "^3.0.0", "@svelteness/kit-docs": "^1.1.5", "@types/eslint": "^8.56.7", + "@types/react": "^19.0.10", "clsx": "^1.0.0", - "eslint": "^9.0.0", + "eslint": "^9.21.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.36.0", + "eslint-plugin-svelte": "^3.0.2", "globals": "^15.0.0", + "jiti": "^2.4.2", "prettier": "^3.1.1", "prettier-plugin-svelte": "^3.1.2", + "react": "^19.0.0", + "react-dom": "^19.0.0", "shiki": "^0.12.0", "svelte": "^4.2.7", "svelte-check": "^3.6.0", + "svelte-eslint-parser": "^1.0.0", "tslib": "^2.4.1", "typescript": "^5.0.0", - "typescript-eslint": "^8.0.0-alpha.20", + "typescript-eslint": "^8.25.0", "unplugin-icons": "^0.19.0", "vite": "^5.0.3" }, diff --git a/src/lib/styles/kit-docs.css b/src/lib/styles/kit-docs.css index f92791a..2accce7 100644 --- a/src/lib/styles/kit-docs.css +++ b/src/lib/styles/kit-docs.css @@ -1,13 +1,15 @@ :root, .prefers-light-scheme { --kd-color-brand: 0 172 237; - --kd-color-focus: 79 70 229; + --kd-color-focus: 0 172 237 !important; --kd-color-soft: 68 78 94; --kd-color-body: 250 250 250; --kd-color-elevate: 243 244 246; --kd-color-inverse: 5 11 23; --kd-color-border: 209 213 219; + --kd-color-subtle: rgb(181 186 199); + --kd-code-fence-bg: rgb(212 217 251); --kd-code-fence-fg: rgb(26, 29, 36); } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index b491f01..7be2e4a 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,10 +1,15 @@ @@ -24,7 +25,7 @@ '-6pLFvW5_Dk', // Camera Animation Test 'sC3FqzpDrpQ', // Diamond Golem 'fs0NUGmsa10', // Butter Dog - '4VlwyI0EHo4' // Funny Mobile Game + '4VlwyI0EHo4', // Funny Mobile Game ] async function getYoutubeVideoTitle(id: string) { @@ -50,10 +51,8 @@ {:catch error} {/await} -
- {#each VIDEOS as id} + {#each VIDEOS as id, index}
+
{ + if ( + e.target.parentElement?.parentElement?.parentElement?.classList.contains( + 'transition-in' + ) + ) + return + e.target.parentElement.parentElement.parentElement.classList.add( + 'transition-in' + ) + }} + >
+ {#await getYoutubeVideoTitle(id)}

Loading Title...

{:then title} @@ -102,6 +116,15 @@ display: flex; flex-direction: column; align-items: center; + transition: + transform 0.2s ease 0s, + opacity 0.2s ease 0s; + transform: translateY(16px) scale(0.9); + opacity: 0; + } + .thumbnail-container:global(.transition-in) { + transform: translateY(0) scale(1); + opacity: 1; } .thumbnail-container :global(button span) { display: flex; diff --git a/src/kit-docs/WigglyText.svelte b/src/kit-docs/WigglyText.svelte index 65969cc..f13eed5 100644 --- a/src/kit-docs/WigglyText.svelte +++ b/src/kit-docs/WigglyText.svelte @@ -27,4 +27,10 @@ animation: wave 1.5s infinite; animation-timing-function: ease-in-out; } + + @media (prefers-reduced-motion: reduce) { + .wiggly-text { + animation: none; + } + } diff --git a/src/kit-docs/kofi-logo.svelte b/src/kit-docs/kofi-logo.svelte new file mode 100644 index 0000000..d8a2c88 --- /dev/null +++ b/src/kit-docs/kofi-logo.svelte @@ -0,0 +1,8 @@ + + Ko-fi + + diff --git a/src/lib/inView.ts b/src/lib/inView.ts index cb26ece..fbcea18 100644 --- a/src/lib/inView.ts +++ b/src/lib/inView.ts @@ -4,10 +4,10 @@ interface ISetObserverOptions { bottom?: number } -export default function inView(node: HTMLElement, options: ISetObserverOptions = {}) { +export function inView(node: HTMLElement, options: ISetObserverOptions = {}) { let observer: IntersectionObserver - const handleIntersect: IntersectionObserverCallback = (e) => { + const handleIntersect: IntersectionObserverCallback = e => { const v = e[0].isIntersecting ? 'enter' : 'exit' node.dispatchEvent(new CustomEvent(v)) } @@ -31,6 +31,6 @@ export default function inView(node: HTMLElement, options: ISetObserverOptions = destroy() { if (observer) observer.disconnect() - } + }, } } diff --git a/src/lib/index.ts b/src/lib/index.ts index b2decee..fa9efd3 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1,3 @@ // place files you want to import through the `$lib` alias in this folder. -export { default as inView } from './inView' +export * from './scrollAnim' +export * from './inView' diff --git a/src/lib/scrollAnim.ts b/src/lib/scrollAnim.ts new file mode 100644 index 0000000..e41aca5 --- /dev/null +++ b/src/lib/scrollAnim.ts @@ -0,0 +1,70 @@ +import { quartOut } from 'svelte/easing' + +interface IScrollAnimatorOptions { + x?: number + yOffset?: number + opacity?: number + scale?: number + rate?: number + easing?: (t: number) => number +} + +export function scrollAnimator(element: HTMLElement, options: IScrollAnimatorOptions = {}) { + const rect = element.getBoundingClientRect() + const docRect = document.body.getBoundingClientRect() + element.style.opacity = '0' + element.style.transition = 'opacity 0.1s ease, transform 0.1s ease' + + const rate = options.rate || 1 + + let top = rect.top - docRect.top - window.innerHeight / 2 + if (options.yOffset) top += options.yOffset + else top += -rect.height / 2 + + const moveX = options.x || 0 + const scale = options.scale + + const updateTransform = (t: number) => { + t = (options.easing ?? quartOut)(t) + const x = -moveX + moveX * t + let s = 1 + if (scale) { + s = scale + (1 - scale) * t + } + element.style.transform = `translateX(${x}px) scale(${s})` + } + + const updateOpacity = (t: number) => { + element.style.opacity = `${Math.min(t * 1.25, 1)}` + } + + const observer = () => { + const scroll = window.scrollY + + const localScroll = Math.min(Math.max(scroll - top, 0), rect.height) + const percent = Math.min(Math.max(localScroll / (rect.height * rate), 0), 1) + updateTransform(percent) + updateOpacity(percent) + } + + let intervalID: number | undefined + const setObserver = ({}: IScrollAnimatorOptions) => { + if (intervalID) clearInterval(intervalID) + // if (observer) removeEventListener('scroll', observer) + intervalID = setInterval(observer, 16) + // addEventListener('scroll', observer, { passive: true }) + observer() + } + + setObserver(options) + + return { + update(args: IScrollAnimatorOptions) { + setObserver(args) + }, + + destroy() { + if (observer) removeEventListener('scroll', observer) + }, + } +} diff --git a/src/lib/strings.ts b/src/lib/strings.ts new file mode 100644 index 0000000..6be0f12 --- /dev/null +++ b/src/lib/strings.ts @@ -0,0 +1 @@ +export const SLOGAN = 'Effortlessly craft complex animations for Minecraft: Java Edition' diff --git a/src/lib/styles/kit-docs.css b/src/lib/styles/kit-docs.css index 2accce7..f8a0ae0 100644 --- a/src/lib/styles/kit-docs.css +++ b/src/lib/styles/kit-docs.css @@ -8,7 +8,7 @@ --kd-color-inverse: 5 11 23; --kd-color-border: 209 213 219; - --kd-color-subtle: rgb(181 186 199); + --kd-color-subtle: rgb(103 111 124); --kd-code-fence-bg: rgb(212 217 251); --kd-code-fence-fg: rgb(26, 29, 36); @@ -16,7 +16,7 @@ :root { font-size: 16px; - scroll-padding-top: 6rem; + scroll-padding-top: 8rem; --kd-font-family-sans: Inter VF, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', @@ -77,7 +77,7 @@ --kd-color-body: 31 33 40; --kd-color-focus: 129 140 248; - --kd-color-subtle: rgb(106, 116, 132); + --kd-color-subtle: rgb(144 156 176); --kd-code-fence-bg: rgb(22 23 27); --kd-code-fence-fg: rgb(186 190 216); @@ -111,3 +111,7 @@ code:not(pre code) { td { text-wrap: balance !important; } + +.on-this-page { + display: none !important; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 7be2e4a..b5408cf 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -7,41 +7,34 @@ import '@svelteness/kit-docs/client/styles/fonts.css' import '@svelteness/kit-docs/client/styles/theme.css' import '$lib/styles/kit-docs.css' - import { Algolia } from '@svelteness/kit-docs/client/algolia' - import { page } from '$app/stores' - + import { PUBLIC_ALGOLIA_ID, PUBLIC_ALGOLIA_SEARCH_KEY } from '$env/static/public' import DiscordIcon from '~icons/ri/discord-fill' import GithubIcon from '~icons/ri/github-fill' + import KofiIcon from '../kit-docs/kofi-logo.svelte' + import { Button, KitDocs, KitDocsLayout, createSidebarContext } from '@svelteness/kit-docs' + import { SLOGAN } from '$lib/strings' - import { - Button, - KitDocs, - KitDocsLayout, - createSidebarContext, - type NavbarConfig - } from '@svelteness/kit-docs' - import type { LayoutData } from './$types' - - export let data: LayoutData + export let data $: ({ meta, sidebar } = data) - const navbar: NavbarConfig = { - links: [ - { title: 'Home', slug: '/', match: /\// }, - { title: 'Documentation', slug: '/docs', match: /\/docs/ } - ] - } + const links = [ + { title: 'Home', slug: '/', icon: false }, + { title: 'Documentation', slug: '/docs', icon: false }, + { title: 'Discord', slug: '/discord', icon: DiscordIcon }, + { title: 'Source', slug: '/source', icon: GithubIcon }, + { title: 'Ko-fi', slug: 'https://ko-fi.com/snavesutit', icon: KofiIcon }, + ] + + console.log(KofiIcon) const { activeCategory } = createSidebarContext(sidebar) $: category = $activeCategory ? `${$activeCategory}: ` : '' $: title = meta ? `Animated Java | ${category}${meta.title}` : 'Animated Java' - $: description = - meta?.description || - 'A Blockbench plugin that makes complex animation a breeze in Minecraft: Java Edition.' + $: description = meta?.description || SLOGAN @@ -65,23 +58,41 @@ - - + + + +
+ + {#if $page.url.pathname !== '/'} Support Us! @@ -139,6 +155,33 @@ --kd-color-brand-rgb: 213, 149, 76; } + :global(:has(> .hide-parent)) { + display: none; + } + + .nav-links { + display: flex; + flex-direction: row; + gap: 1rem; + } + .nav-links > li { + list-style: none; + color: rgb(var(--kd-color-soft) / var(--tw-text-opacity)); + } + .nav-links > li > a { + display: flex; + align-items: center; + gap: 0.5rem; + } + .nav-links > li > a.active { + color: rgb(var(--kd-color-brand)); + border-bottom: 2px solid rgb(var(--kd-color-brand)); + } + /* .nav-links > li > img, + .nav-links > li > :global(svg) { + color: rgb(var(--kd-color-soft) / var(--tw-text-opacity)); + } */ + .ko-fi-button { position: fixed; bottom: 16px; @@ -184,6 +227,9 @@ margin-top: 8px; margin-bottom: 0 !important; } + .logo img.banner { + display: none !important; + } } :global(.aj-welcome-page-header) { @@ -205,6 +251,16 @@ overflow: hidden; } + .logo img.icon { + width: 48px; + border-radius: 8px; + box-shadow: 2px 2px 4px -2px black; + } + .logo img.banner { + width: 200px; + margin: 8px 0; + } + .footer { display: flex; flex-direction: column; @@ -212,17 +268,22 @@ } .footer-wip-warning { - /* margin-bottom: 1rem; */ text-align: center; } .footer-social { display: flex; + flex-direction: column; justify-content: center; margin-top: 2rem; margin-bottom: 2rem; } + .footer-copywrite { + margin: 32px; + color: var(--kd-color-subtle); + } + .header-container { display: flex; align-items: center; @@ -236,14 +297,6 @@ justify-content: center; margin-left: 1rem; } - .header-container img { - width: 48px; - border-radius: 8px; - box-shadow: 2px 2px 4px -2px black; - } - .header-container h1 { - font-size: 1.5rem; - } .social-container { display: flex; diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index 37d7125..2b7486b 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -6,6 +6,6 @@ export const load = createKitDocsLoader({ sidebar: { '/': null, '/docs': '/docs', - '/404': '/docs' - } + '/404': '/docs', + }, }) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e5df690..6d34eee 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,156 +1,198 @@ + +
-
- - +
+ Animated Java Logo
-

Welcome to Animated Java!

-
-

- A Blockbench plugin that makes complex animation a breeze in Minecraft: Java Edition. -

+ +

+ {SLOGAN} +

+
+

What is Animated Java?

+
+ +
+
+

+ Animated Java is a Blockbench plugin that enables the creation of intricate animated + models for Vanilla Minecraft: Java Edition. With a wide range of features and + options, Animated Java is the perfect tool for Map Makers and Data Pack Developers + looking to add a touch of life to their creations. +

+
+
+ + {#if scroll < 100} +
+ +

Scroll to see more

+ +
+ {/if} +
{#each PANELS as panel, i} -
- {#if i % 2 == 0} + {@const isLeftSide = i % 2 == 0} +
+ {#if isLeftSide} {panel.title} {/if}

{panel.title} -


{panel.description}

- {#if i % 2 == 1} + {#if !isLeftSide} {panel.title} {/if} -
{ - if (e.target.parentElement.classList.contains('panel-fade-in')) return - e.target.parentElement.classList.add('panel-fade-in') - }} - />
{/each}
-
+

Made with Animated Java!


- -
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 6d34eee..ccb0e6d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,23 +1,41 @@ + +