How to dynamically build tailwind class names

Issue #950 Inspired by shadcn Combine tailwind-merge: Utility function to efficiently merge Tailwind CSS classes in JS without style conflicts. clsx: constructing className strings conditionally. import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }

November 4, 2023 路 1 min 路 Khoa Pham

How to store Codable in AppStorage

Issue #949 AppStorage and SceneStorage accepts RawRepresentable where value is Int or String. Creates a property that can read and write to a string user default, transforming that to RawRepresentable data type. init(wrappedValue:_:store:) init( wrappedValue: Value, _ key: String, store: UserDefaults? = nil ) where Value : RawRepresentable, Value.RawValue == String One clever thing (that does not work) is to use a custom Codable type that conforms to RawRepresentable, like below...

October 3, 2023 路 2 min 路 Khoa Pham

How to update widget for iOS 17

Issue #948 iOS 17 has a new Stand by mode so SwiftUI introduces containerBackground for the system to decide when to draw background. It also automatically applies margin to widget so we may need to disable that To update existing widgets, we can write some useful extension extension View { @ViewBuilder func safeContainerBackground(@ViewBuilder content: () -> some View) -> some View { if #available(iOS 17.0, *) { self.containerBackground(for: .widget, content: content) } else { self....

October 2, 2023 路 1 min 路 Khoa Pham

How to get Supabase user token from server API

Issue #947 Sometimes Row Level Security is not enough and we want to do all logic server side, then we need a way for the server to get hold onto current user token. Send JWT token in Authorization header From client, we can get session from supabase auth, then send that as Bearer in Authorization header const session = await supabase.auth.getSession().data.session const token = session.access_token const response = await fetch(url, { 'GET', headers: { Authorization: `Bearer ${token}` } }) Decode token From the nextjs API Route, we can handle all auth logic in middleware....

August 30, 2023 路 2 min 路 Khoa Pham

How to mirror auth.users on Supabase

Issue #946 For security purposes, the auth schema is not exposed on the auto-generated API. We can make a profiles table in public namespace and mirror data from auth.users when user signs up. I need id, username and raw_user_metadata so I will mirror these columns. For easy, you can leverage Supabase SQL Editor -> Quickstarts -> User Management Starter script I don鈥檛 need Row Level Security as I manage database from server....

August 30, 2023 路 2 min 路 Khoa Pham

How to force localized language with SwiftGen

Issue #945 The default SwiftGen generate generated strings L10n file like this extension L10n { private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) return String(format: format, locale: Locale.current, arguments: args) } } // swiftlint:disable convenience_type private final class BundleToken { static let bundle: Bundle = { #if SWIFT_PACKAGE return Bundle.module #else return Bundle(for: BundleToken....

August 26, 2023 路 1 min 路 Khoa Pham

How to make tag flow layout using Layout protocol in SwiftUI

Issue #944 SwiftUI in iOS 16 supports Layout protocol to arrange subviews We need to implement 2 methods sizeThatFits(proposal:subviews:cache:) reports the size of the composite layout view. placeSubviews(in:proposal:subviews:cache:) assigns positions to the container鈥檚 subviews. We will make a custom layout that arranges elements from top leading and span element to new rows if it can鈥檛 fit the current row. Start by defining a FlowLayout struct that conforms to Layout protocol....

August 22, 2023 路 3 min 路 Khoa Pham

How to use hover annotation in Swift Charts

Issue #943 In this tutorial, we鈥檒l learn how to use Swift Charts to visualize ranking data. We use default AxisMarks and AxisMarks to let Swift Charts interpolate x and y grid lines. For y axis, I want to have finer grain control over the grid, so I specify an arrayLiteral Note that for rank, the lower value the better ranking, so we make use of chartYScale with reversed automatic domain to flip from 0 -> 100 to 100 -> 0...

August 18, 2023 路 2 min 路 Khoa Pham

How to use Supabase auth with React Context

Issue #942 Expose supabase with createClient useSupabase.ts import { createClient } from '@supabase/supabase-js' const supabaseUrl = process.env.SUPABASE_URL const supabaseAnonKey = process.env.SUPABASE_ANON_KEY export const supabase = createClient(supabaseUrl!, supabaseAnonKey!) export const signIn = async () => { await supabase.auth.signInWithOAuth({ provider: 'twitter' }); } export const signOut = async () => { await supabase.auth.signOut(); } Wrap auth state in React Context AuthProvider.tsx import React, { useContext, createContext, useState, useEffect } from 'react' import { Session, User } from '@supabase/supabase-js' import { supabase } from '....

August 12, 2023 路 2 min 路 Khoa Pham

How to create React app with Parcel

Issue #941 In this tutorial we will be creating a React app with Parcel 2 with Typescript and Tailwind Install the following dependencies. Parcel supports TypeScript out of the box without any additional configuration. npm install --save-dev parcel npm install react react-dom npm install @types/react @types/react-dom --dev npm install -D tailwindcss postcss npx tailwindcss init We will be adding files to src folder src - index.html - App.tsx - App.css Create a ....

August 3, 2023 路 3 min 路 Khoa Pham

How to make Chrome extension with Nextjs 13

Issue #940 We can develop Nextjs 13 apps and export it to a Chrome extension. Start by init the project npx create-next-app@latest Here is the project structure with app router and not using src directory. I put an extension to the root of the project, where we can copy over the generated out folder extension - manifest.json app - page.tsx public - images Here is my script to build and copy over generated out and public images to extension folder...

August 2, 2023 路 1 min 路 Khoa Pham

How to scale image fill without affect layout in SwiftUI

Issue #939 Instead of letting the Image decide the size, we can put it as background or overlay. I use clipped and contentShape to avoid the fill image obscuring touch event Color.clear .frame(height: 100) .overlay { AsyncImage(url: item.imageUrl) { image in image .resizable() .scaledToFill() } placeholder: { ProgressView() } } .clipped() .contentShape(Rectangle())

July 30, 2023 路 1 min 路 Khoa Pham

How to move Core Data database to AppGroup folder

Issue #938 To let app and extension to talk to the same database, we need to use AppGroup. Here is how to use replacePersistentStore Replaces one persistent store with another actor DatabaseMigrator { @AppStorage("DatabaseMigrator.hasMigrated") var hasMigrated = false func migrateIfNeeded() { guard !hasMigrated else { return } migrate() hasMigrated = true } private func migrate() { let oldContainer = NSPersistentCloudKitContainer(name: "Bookmarks") guard let oldStoreUrl = oldContainer.persistentStoreDescriptions.first?.url, let newStoreUrl = Constants....

July 30, 2023 路 1 min 路 Khoa Pham

How to read write files to iCloud Drive

Issue #937 First, you need to enable iCloud Documents capability. Go to target settings -> Signing & Capabilities -> iCloud ` Then inside your Info.plist, add this with your iCloud identifier and app name <key>NSUbiquitousContainers</key> <dict> <key>iCloud.com.onmyway133.PastePal</key> <dict> <key>NSUbiquitousContainerIsDocumentScopePublic</key> <true/> <key>NSUbiquitousContainerName</key> <string>PastePal</string> <key>NSUbiquitousContainerSupportedFolderLevels</key> <string>Any</string> </dict> </dict> To access to your iCloud Drive folder, we use FileManager to retrieve the folder. Returns the URL for the iCloud container associated with the specified identifier and establishes access to that container....

July 28, 2023 路 2 min 路 Khoa Pham

How to make reusable Button component in React

Issue #936 From https://github.com/antonioerdeljac/next13-spotify import { forwardRef } from "react"; import { twMerge } from "tailwind-merge"; export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {} const Button = forwardRef<HTMLButtonElement, ButtonProps>(({ className, children, disabled, type = 'button', ...props }, ref) => { return ( <button type={type} className={twMerge( ` w-full rounded-full bg-green-500 border border-transparent px-3 py-3 disabled:cursor-not-allowed disabled:opacity-50 text-black font-bold hover:opacity-75 transition `, disabled && 'opacity-75 cursor-not-allowed', className )} disabled={disabled} ref={ref} {...props} > {children} </button> ); }); Button....

July 21, 2023 路 1 min 路 Khoa Pham

How to make fullstack web app

Issue #935 I prefer UI Component that works with Nextjs and Tailwind CSS UI Libraries https://ui.shadcn.com/ https://daisyui.com/ https://www.radix-ui.com/ 馃憤 https://preline.co/ https://nextui.org/ https://mantine.dev/ https://chakra-ui.com/ https://getbootstrap.com/ https://bulma.io/ https://www.floatui.com/ Tailwind CSS templates https://preline.co/ https://tailwindui.com/ https://flowbite.com/ Icon Library https://github.com/lucide-icons/lucide https://github.com/react-icons/react-icons Lib https://github.com/timolins/react-hot-toast https://github.com/pmndrs/zustand https://github.com/react-hook-form/react-hook-form https://github.com/sindresorhus/query-string https://github.com/davidhu2000/react-spinners https://github.com/lukeed/clsx https://github.com/pacocoursey/next-themes https://github.com/colinhacks/zod https://github.com/remarkjs/react-markdown https://github.com/tameemsafi/typewriterjs https://github.com/lodash/lodash https://github.com/dcastil/tailwind-merge https://ahooks.js.org/ https://zod.dev/ Services Support https://crisp.chat Ref https://github.com/antonioerdeljac/next13-spotify https://github.com/shadcn-ui/taxonomy https://github.com/steven-tey/dub https://github.com/Elliott-Chong/quizmify

July 20, 2023 路 1 min 路 Khoa Pham

How to use keychain in Swift

Issue #934 There are a few keychain wrappers around but for simple needs, you can write it yourself Here is a basic implementation. I use actor to go with async/await, and a struct KeychainError to contain status code in case we want to deal with error cases. accessGroup is to define kSecAttrAccessGroup to share keychain across your apps public actor Keychain { public struct KeychainError: Error { let status: OSStatus } let service: String let accessGroup: String?...

July 20, 2023 路 2 min 路 Khoa Pham

How to handle route case sensitivity in Nextjs

Issue #933 By default, Nextjs route is case sensitive, so localhost:3000/About and localhost:3000/about are different routes. To make uppercase routes become lowercase routes, we can add a middleware.tsx file to the src so it is same level as pages import { NextResponse, NextRequest } from "next/server" const Middleware = (req: NextRequest) => { if (req.nextUrl.pathname === req.nextUrl.pathname.toLowerCase()) { return NextResponse.next() } return NextResponse.redirect( new URL(req.nextUrl.origin + req.nextUrl.pathname.toLowerCase()) ) } export default Middleware

July 17, 2023 路 1 min 路 Khoa Pham

How to make share and action extension in iOS

Issue #932 Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension SwiftUI I usually make a ShareView in SwiftUI with ShareViewModel to control the logic struct ShareView: View { @ObservedObject var vm: ShareViewModel var body: some View { NavigationStack(path: $vm.routes) { List {} } } } In ShareViewController, we can just conform to UIViewController and add our SwiftUI view as child view controller...

July 12, 2023 路 2 min 路 Khoa Pham

AppStore screenshots size checklist

Issue #931 AppStore screenshots Screenshot specifications iPhone 6.7" Portrait 1290 x 2796 iPhone 6.5" Portrait 1242 x 2688 In-App Purchase screenshots In-app purchase information iOS 640 x 920 tvO 1920 x1080 pixels macOS 1280 x 800 pixels

July 12, 2023 路 1 min 路 Khoa Pham