diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 98d9696e..a85de316 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -26,6 +26,8 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps diff --git a/.github/workflows/pnpm-check.yml b/.github/workflows/pnpm-check.yml index dfe43e4d..09a9ccbf 100644 --- a/.github/workflows/pnpm-check.yml +++ b/.github/workflows/pnpm-check.yml @@ -28,6 +28,8 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run pnpm check run: pnpm check @@ -54,6 +56,8 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run pnpm build run: pnpm build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ad052d3f..b3f18c54 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,8 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install Playwright Browsers run: pnpm exec playwright install diff --git a/.npmrc b/.npmrc index b6f27f13..cbe4585c 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,4 @@ engine-strict=true + +@edufeed-org:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9934a855..dca9cf04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,16 @@ services: + # If the app needs to be started via docker compose, uncomment these lines of code and add a Dockerfile + # app: + # tty: true + # stdin_open: true + # build: + # context: . + # dockerfile: Dockerfile + # target: development + # volumes: + # - .:/home/node/app + # ports: + # - "5173:5173" nostr-relay: image: scsibug/nostr-rs-relay:latest ports: diff --git a/package.json b/package.json index 96e4c09d..c7cfea52 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ ] }, "dependencies": { + "@edufeed-org/oer-finder-plugin": "^0.0.5", "@nostr-dev-kit/ndk": "2.14.2", "@nostr-dev-kit/svelte": "^2.0.8", "jsoncrush": "^1.1.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e506d2b..71c97c52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,9 @@ importers: .: dependencies: + '@edufeed-org/oer-finder-plugin': + specifier: ^0.0.5 + version: 0.0.5 '@nostr-dev-kit/ndk': specifier: ^2.14.2 version: 2.17.4(nostr-tools@2.14.3(typescript@5.9.3)) @@ -246,6 +249,12 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@edufeed-org/oer-finder-api-client@0.0.3': + resolution: {integrity: sha512-rTth4/f1//e8nhQc4PUN44LXETzFogOldgSXpjv2eiOQ3ZfLQwvsOxwc9iul4hpdElJjX0Oe1a78XJ5axr0grg==, tarball: https://npm.pkg.github.com/download/@edufeed-org/oer-finder-api-client/0.0.3/49a71f32e6d7ed36ba148ca31b5f27728df02074} + + '@edufeed-org/oer-finder-plugin@0.0.5': + resolution: {integrity: sha512-kxMcb66lvfczP0lH71fyLZsoqDA4RfJbLvXmqK8TU8NUsRseRub+uqXBx9vPiJfxYM51m82x5lfsSVcLAxAplg==, tarball: https://npm.pkg.github.com/download/@edufeed-org/oer-finder-plugin/0.0.5/8749bdd90492bf54dfbc0b776c0a2527ad8255fb} + '@esbuild/aix-ppc64@0.25.10': resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} @@ -454,6 +463,7 @@ packages: '@finom/zod-to-json-schema@3.24.11': resolution: {integrity: sha512-fL656yBPiWebtfGItvtXLWrFNGlF1NcDFS0WdMQXMs9LluVg0CfT5E2oXYp0pidl0vVG53XkW55ysijNkU5/hA==} + deprecated: 'Use https://www.npmjs.com/package/zod-v3-to-json-schema instead. See issue comment for details: https://github.com/StefanTerdell/zod-to-json-schema/issues/178#issuecomment-3533122539' peerDependencies: zod: ^4.0.14 @@ -529,6 +539,12 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@lit-labs/ssr-dom-shim@1.4.0': + resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} + + '@lit/reactive-element@2.1.1': + resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} + '@lucide/svelte@0.544.0': resolution: {integrity: sha512-9f9O6uxng2pLB01sxNySHduJN3HTl5p0HDu4H26VR51vhZfiMzyOMe9Mhof3XAk4l813eTtl+/DYRvGyoRR+yw==} peerDependencies: @@ -1126,6 +1142,9 @@ packages: '@types/react@19.2.2': resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1980,6 +1999,15 @@ packages: linkifyjs@4.3.2: resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + lit-element@4.2.1: + resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} + + lit-html@3.3.1: + resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} + + lit@3.3.1: + resolution: {integrity: sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==} + local-access@1.1.0: resolution: {integrity: sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==} engines: {node: '>=6'} @@ -2166,6 +2194,12 @@ packages: oniguruma-to-es@4.3.3: resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} + openapi-fetch@0.13.8: + resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3123,6 +3157,15 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@edufeed-org/oer-finder-api-client@0.0.3': + dependencies: + openapi-fetch: 0.13.8 + + '@edufeed-org/oer-finder-plugin@0.0.5': + dependencies: + '@edufeed-org/oer-finder-api-client': 0.0.3 + lit: 3.3.1 + '@esbuild/aix-ppc64@0.25.10': optional: true @@ -3357,6 +3400,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@lit-labs/ssr-dom-shim@1.4.0': {} + + '@lit/reactive-element@2.1.1': + dependencies: + '@lit-labs/ssr-dom-shim': 1.4.0 + '@lucide/svelte@0.544.0(svelte@5.39.11)': dependencies: svelte: 5.39.11 @@ -4012,6 +4061,8 @@ snapshots: csstype: 3.1.3 optional: true + '@types/trusted-types@2.0.7': {} + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -4925,6 +4976,22 @@ snapshots: linkifyjs@4.3.2: {} + lit-element@4.2.1: + dependencies: + '@lit-labs/ssr-dom-shim': 1.4.0 + '@lit/reactive-element': 2.1.1 + lit-html: 3.3.1 + + lit-html@3.3.1: + dependencies: + '@types/trusted-types': 2.0.7 + + lit@3.3.1: + dependencies: + '@lit/reactive-element': 2.1.1 + lit-element: 4.2.1 + lit-html: 3.3.1 + local-access@1.1.0: {} local-pkg@1.1.2: @@ -5112,6 +5179,12 @@ snapshots: regex: 6.0.1 regex-recursion: 6.0.2 + openapi-fetch@0.13.8: + dependencies: + openapi-typescript-helpers: 0.0.15 + + openapi-typescript-helpers@0.0.15: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 diff --git a/src/lib/components/OerImagePicker.svelte b/src/lib/components/OerImagePicker.svelte new file mode 100644 index 00000000..8ee3768c --- /dev/null +++ b/src/lib/components/OerImagePicker.svelte @@ -0,0 +1,84 @@ + + +
+ + + + +
+ + diff --git a/src/lib/stores/settingsStore.svelte.ts b/src/lib/stores/settingsStore.svelte.ts index 9c0c5f35..8fc007ae 100644 --- a/src/lib/stores/settingsStore.svelte.ts +++ b/src/lib/stores/settingsStore.svelte.ts @@ -59,6 +59,11 @@ export interface SettingsState { learningInitialConfidence: number; // Startwert für neue Patterns (Default: 0.3) learningConfidenceIncrement: number; // Increment bei erfolgreicher Nutzung (Default: 0.15) learningMinUsageCount: number; // Mindestanzahl Nutzungen für "learned" Status (Default: 3) + + oerFinderPlugin: { + apiUrl: string, + language: string + } } /** @@ -169,6 +174,11 @@ KRITISCH: Bei "leg an" / "erstelle" IMMER JSON! NIEMALS nur Text!`, learningInitialConfidence: 0.3, learningConfidenceIncrement: 0.15, learningMinUsageCount: 3, + + oerFinderPlugin: { + apiUrl: "http://localhost:3001", + language: "de" + }, }; /** diff --git a/src/routes/cardsboard/CardDialog.svelte b/src/routes/cardsboard/CardDialog.svelte index fbeacc30..ead3e4a2 100644 --- a/src/routes/cardsboard/CardDialog.svelte +++ b/src/routes/cardsboard/CardDialog.svelte @@ -10,6 +10,7 @@ import { Separator } from '$lib/components/ui/separator/index.js'; import { boardStore } from '$lib/stores/kanbanStore.svelte.js'; import type { CardProps, PublishState } from '../../lib/classes/BoardModel.js'; + import OerImagePicker from '$lib/components/OerImagePicker.svelte'; interface Props { card: CardProps | null; @@ -87,6 +88,7 @@ let isSubmitting = $state(false); let activeTab = $state<'content' | 'settings'>('content'); let isUserEditing = $state(false); // Guard gegen $effect Überschreibung während Editing + let imageMode = $state<'url' | 'oer'>('url'); // Neue Label und Link Input let newLabel = $state(''); @@ -218,7 +220,7 @@ onClose(); } }}> - + {card?.heading || 'Neue Karte'} @@ -268,21 +270,53 @@ - Kartenbild (URL) - - Kartenbild + + +
+ + +
+ + {#if imageMode === 'url'} + + + + {#if errors.image} + + {/if} + {:else} + { + formData.image = url; + imageMode = 'url'; + }} /> -
- {#if errors.image} - {/if} - - + + {#if previewCard?.image}
{:else if formData.image} -