Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COURSE: JavaScript for a 10 Year Old #461

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions apps/codingcatdev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@auth/sveltekit": "^0.3.7",
"@codingcatdev/blackcatui": "^0.1.0",
"@firebase/app-types": "~0.9.0",
"@fontsource/shadows-into-light": "^5.0.13",
"@playwright/test": "^1.38.1",
"@skeletonlabs/skeleton": "2.3.0",
"@skeletonlabs/tw-plugin": "0.2.2",
"@steeze-ui/heroicons": "^2.2.3",
"@steeze-ui/simple-icons": "^1.5.1",
"@steeze-ui/svelte-icon": "^1.5.0",
"@sveltejs/adapter-auto": "^2.1.0",
"@sveltejs/adapter-vercel": "^3.0.3",
"@sveltejs/kit": "^1.25.1",
"@tailwindcss/forms": "^0.5.6",
"@types/marked": "^5.0.2",
"@tailwindcss/typography": "0.5.10",
"@types/node": "^20.8.6",
"@types/prismjs": "^1.26.1",
"@types/video.js": "^7.3.53",
"autoprefixer": "^10.4.16",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte3": "^4.0.0",
"feed": "^4.2.2",
"firebase-admin": "^11.11.0",
"flexsearch": "^0.7.31",
Expand Down Expand Up @@ -61,6 +61,7 @@
"firebase": "^10.4.0",
"gsap": "^3.12.2",
"prism-svelte": "^0.5.0",
"prism-themes": "^1.9.0"
"prism-themes": "^1.9.0",
"sveltefire": "^0.4.2"
}
}
17 changes: 5 additions & 12 deletions apps/codingcatdev/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');

const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

module.exports = config;
4 changes: 2 additions & 2 deletions apps/codingcatdev/src/app.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" data-theme="codingcatdev">
<head>
<meta charset="utf-8" />
Expand Down Expand Up @@ -89,7 +89,7 @@

%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<body data-sveltekit-preload-data="hover" data-theme="codingcatdev"">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
6 changes: 3 additions & 3 deletions apps/codingcatdev/src/app.postcss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import './styles/theme.css';
@import '@codingcatdev/blackcatui/dist/styles/all.css';
@import './styles/tailwind.css';
@import './styles/app.css';
@import './styles/nav-list.css';
@import './styles/grid-card.css';
@import './styles/markdown.css';
@import '@fontsource/shadows-into-light'
@import './styles/typography.css';
@import '@fontsource/shadows-into-light';
173 changes: 95 additions & 78 deletions apps/codingcatdev/src/lib/client/firebase.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
import { browser } from '$app/environment';

import { toastStore } from '@codingcatdev/blackcatui';
import { initializeApp, getApps, FirebaseError } from 'firebase/app';
import { getAuth, setPersistence, browserSessionPersistence, signInWithEmailAndPassword, signInWithPopup, type AuthProvider, type Auth, createUserWithEmailAndPassword } from 'firebase/auth';
import { getFirestore, collection, doc, addDoc, onSnapshot, Firestore } from 'firebase/firestore';
import { initializeApp, getApps } from 'firebase/app';
import {
getAuth,
signInWithEmailAndPassword,
signInWithPopup,
type AuthProvider,
type Auth,
createUserWithEmailAndPassword
} from 'firebase/auth';
import {
getFirestore,
collection,
doc,
addDoc,
onSnapshot,
Firestore,
setDoc,
type DocumentData,
initializeFirestore
} from 'firebase/firestore';
import { httpsCallable, getFunctions, type Functions } from 'firebase/functions';
import { getAnalytics, type Analytics, logEvent, type AnalyticsCallOptions } from "firebase/analytics";
import {
getAnalytics,
type Analytics,
logEvent,
type AnalyticsCallOptions
} from 'firebase/analytics';

import { env } from '$env/dynamic/public';

Expand All @@ -19,125 +40,121 @@ export const firebaseConfig = {
measurementId: env.PUBLIC_FB_MEASUREMENT_ID
};

let app = getApps().at(0);
let auth: Auth;
let db: Firestore;
let functions: Functions;
let analytics: Analytics;
export let app = getApps().at(0);
export let auth: Auth;
export let firestore: Firestore;
export let functions: Functions;
export let analytics: Analytics;

if (!app &&
if (
!app &&
browser &&
firebaseConfig.apiKey &&
firebaseConfig.authDomain &&
firebaseConfig.projectId &&
firebaseConfig.storageBucket &&
firebaseConfig.messagingSenderId &&
firebaseConfig.appId &&
firebaseConfig.measurementId) {

firebaseConfig.measurementId
) {
app = initializeApp(firebaseConfig);

auth = getAuth(app);

// As httpOnly cookies are to be used, do not persist any state client side.
setPersistence(auth, browserSessionPersistence);
db = getFirestore(app);
// setPersistence(auth, browserSessionPersistence);
firestore = initializeFirestore(app, { ignoreUndefinedProperties: true });
functions = getFunctions(app);
analytics = getAnalytics(app);
} else {
console.debug('Skipping Firebase Initialization, check firebaseconfig.')
if (
browser &&
(!firebaseConfig.apiKey ||
!firebaseConfig.authDomain ||
!firebaseConfig.projectId ||
!firebaseConfig.storageBucket ||
!firebaseConfig.messagingSenderId ||
!firebaseConfig.appId ||
!firebaseConfig.measurementId)
)
console.debug('Skipping Firebase Initialization, check firebaseconfig.');
}

/* AUTH */

const setCookie = (idToken: string) => {
document.cookie = '__ccdlogin=' + idToken + ';max-age=3600';
}
};

export const ccdSignInWithEmailAndPassword = async ({ email, password }: { email: string, password: string }) => {
export const ccdSignInWithEmailAndPassword = async ({
email,
password
}: {
email: string;
password: string;
}) => {
const userResponse = await signInWithEmailAndPassword(auth, email, password);
const idToken = await userResponse.user.getIdToken();
setCookie(idToken);
}
};

export const ccdSignUpWithEmailAndPassword = async ({ email, password }: { email: string, password: string }) => {
export const ccdSignUpWithEmailAndPassword = async ({
email,
password
}: {
email: string;
password: string;
}) => {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const idToken = await userCredential.user.getIdToken();
setCookie(idToken);
}
};

export const ccdSignInWithPopUp = async (provider: AuthProvider) => {
try {
const result = await signInWithPopup(auth, provider)
const idToken = await result.user.getIdToken()

if (!idToken)
throw 'Missing id Token'
setCookie(idToken);
} catch (err) {
if (err instanceof FirebaseError) {
if (err.code === 'auth/account-exists-with-different-credential') {
toastStore.trigger({
message: 'Account Exists with Different Login Method. Please first login and then link within your Account page.',
background: 'variant-filled-warning',
})
} else {
toastStore.trigger({
message: err.message,
background: 'variant-filled-error'
})
}
} else {
console.error(err);
}
}
}
const result = await signInWithPopup(auth, provider);
const idToken = await result.user.getIdToken();

if (!idToken) throw 'Missing id Token';
setCookie(idToken);
};

/* DB */
export const updateUser = async (docRef: string, data: DocumentData) => {
return setDoc(doc(firestore, docRef), data, { merge: true });
};

/* STRIPE */
export const addSubscription = async (price: string, uid: string) => {
const userDoc = doc(collection(db, 'stripe-customers'), uid)
const docRef = await addDoc(collection(userDoc, 'checkout_sessions'), {
const userDoc = doc(collection(firestore, 'stripe-customers'), uid);
return await addDoc(collection(userDoc, 'checkout_sessions'), {
price,
success_url: window.location.href,
cancel_url: window.location.href,
})
onSnapshot(docRef, (snap) => {
const { error, url } = snap.data() as { error: Error, url: string };
if (error) {
toastStore.trigger({
message: error.message,
background: 'variant-filled-error'
})
}
if (url) {
// We have a Stripe Checkout URL, let's redirect.
window.location.assign(url);
}
cancel_url: window.location.href
});
};

/* FUNCTIONS */
export const openStripePortal = async () => {
const functionRef = httpsCallable(functions, 'ext-firestore-stripe-payments-createPortalLink');
const { data } = await functionRef({
returnUrl: window.location.href,
}) as { data: { url: string } };
const { data } = (await functionRef({
returnUrl: window.location.href
})) as { data: { url: string } };
window.location.assign(data.url);
}
};

/* Analytics */
export const analyticsLogPageView = async (eventParams?: {
page_title?: string;
page_location?: string;
page_path?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}, options?: AnalyticsCallOptions) => {

export const analyticsLogPageView = async (
eventParams?: {
page_title?: string;
page_location?: string;
page_path?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
},
options?: AnalyticsCallOptions
) => {
if (firebaseConfig.apiKey) {
logEvent(analytics, "page_view", eventParams, options)
logEvent(analytics, 'page_view', eventParams, options);
} else {
console.debug('Skipping Firebase Analytics, no key specified.')
console.debug('Skipping Firebase Analytics, no key specified.');
}
}
};
4 changes: 3 additions & 1 deletion apps/codingcatdev/src/lib/components/content/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
let count = 0;
</script>

<button class="bcu-button variant-filled-primary" on:click={() => count++}>{count}</button>
<button class="btn variant-filled-primary" on:click={() => count++}
>{count ? count : 'Click Me'}</button
>
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
copyButton.innerHTML = 'Copy';
}, 1500);
});
copyButton.className =
'copy absolute top-0 right-0 mt-2 mr-2 bcu-button variant-ringed-primary';
copyButton.className = 'copy absolute top-0 right-0 mt-2 mr-2 btn variant-ringed-primary';
copyButton.innerText = 'Copy';
pre.appendChild(copyButton);
}
Expand Down
5 changes: 3 additions & 2 deletions apps/codingcatdev/src/lib/search/Search.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import { Icon } from '@steeze-ui/svelte-icon';
import { MagnifyingGlass } from '@steeze-ui/heroicons';
import { modalStore, type ModalSettings } from '@codingcatdev/blackcatui';
import { getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
const modalStore = getModalStore();
import SearchModal from '$lib/search/SearchModal.svelte';
import { query } from './stores.js';

Expand Down Expand Up @@ -35,7 +36,7 @@
/>

<button
class="bcu-button p-2 px-4 space-x-4 variant-soft hover:variant-soft-primary flex align-middle"
class="btn p-2 px-4 space-x-4 variant-soft hover:variant-soft-primary flex align-middle"
on:mousedown|preventDefault={() => showSearch()}
on:touchend|preventDefault={() => showSearch()}
>
Expand Down
7 changes: 4 additions & 3 deletions apps/codingcatdev/src/lib/search/SearchModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ It appears when the user clicks on the `Search` component or presses the corresp
import { query, recent } from './stores';
import SearchResults from './SearchResults.svelte';
import SearchWorker from './search-worker?worker';
import { modalStore } from '@codingcatdev/blackcatui';
import { getModalStore } from '@skeletonlabs/skeleton';
const modalStore = getModalStore();

/** @type {HTMLElement} */
let modal;
Expand Down Expand Up @@ -79,7 +80,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
}
</script>

<div class="bcu-card p-2 md:p-8 flex flex-col gap-2 md:gap-8 w-full h-full md:w-[80%] md:h-[80%]">
<div class="card p-2 md:p-8 flex flex-col gap-2 md:gap-8 w-full h-full md:w-[80%] md:h-[80%]">
<div class="flex gap-2">
<!-- svelte-ignore a11y-autofocus -->
<input
Expand All @@ -99,7 +100,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
spellcheck="false"
class="input p-2"
/>
<button class="bcu-button variant-ringed" on:click={() => modalStore.close()}>
<button class="btn variant-ringed" on:click={() => modalStore.close()}>
<Icon src={XMark} theme="solid" class="w-6 h-6" />
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/codingcatdev/src/lib/search/SearchResultList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

<ul>
{#each results as result (result.href)}
<li class="bcu-card variant-ghost px-2">
<li class="card variant-ghost px-2">
<a
class="!no-underline !text-token"
data-sveltekit-preload-data
Expand Down
Loading