mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-22 09:56:51 +01:00
lib reorg
This commit is contained in:
parent
a65b7ff201
commit
cd1e3dd0b3
@ -1,6 +1,6 @@
|
|||||||
import { defineConfig } from 'astro/config'
|
import { defineConfig } from 'astro/config'
|
||||||
import remarkLeadParagraph from '../src/lib/remark-lead-paragraph'
|
import { remarkLeadParagraph } from '../src/lib/remark-lead-paragraph/remark-lead-paragraph'
|
||||||
import remarkToc from '../src/lib/remark-toc'
|
import { remarkToc } from '../src/lib/remark-toc/remark-toc'
|
||||||
import react from '@astrojs/react'
|
import react from '@astrojs/react'
|
||||||
import sitemap from '@astrojs/sitemap'
|
import sitemap from '@astrojs/sitemap'
|
||||||
import expressiveCode from 'astro-expressive-code'
|
import expressiveCode from 'astro-expressive-code'
|
||||||
|
@ -2,7 +2,7 @@ import fs from 'node:fs/promises'
|
|||||||
import { existsSync, mkdirSync, readFileSync } from 'node:fs'
|
import { existsSync, mkdirSync, readFileSync } from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import slugify from '../../src/lib/slugify.js'
|
import { slugify } from '../../src/lib/slugify'
|
||||||
import type { Ora } from 'ora'
|
import type { Ora } from 'ora'
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import fs from 'node:fs/promises'
|
import fs from 'node:fs/promises'
|
||||||
import { existsSync, mkdirSync, readFileSync } from 'node:fs'
|
import { existsSync, mkdirSync, readFileSync } from 'node:fs'
|
||||||
import slugify from '../../src/lib/slugify.js'
|
import { slugify } from '../../src/lib/slugify'
|
||||||
import { readOutExif } from '../../src/lib/exif/index.js'
|
import { readOutExif } from '@lib/exif'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import type { Ora } from 'ora'
|
import type { Ora } from 'ora'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import type { Exif } from '@lib/exif/types'
|
import type { Exif } from '@lib/exif'
|
||||||
import {
|
import {
|
||||||
Camera,
|
Camera,
|
||||||
Crosshair,
|
Crosshair,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import type { CollectionEntry } from 'astro:content'
|
import type { CollectionEntry } from 'astro:content'
|
||||||
import slugify from '@lib/slugify'
|
import { slugify } from '@lib/slugify'
|
||||||
import config from '@config/blog.config'
|
import config from '@config/blog.config'
|
||||||
import Tag from '@components/Tag.astro'
|
import Tag from '@components/Tag.astro'
|
||||||
import styles from './Meta.module.css'
|
import styles from './Meta.module.css'
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export { getAllPosts } from './getAllPosts'
|
export * from './getAllPosts'
|
||||||
export { getAllTags } from './getAllTags'
|
export * from './getAllTags'
|
||||||
export { getPostsByTag } from './getPostsByTag'
|
export * from './getPostsByTag'
|
||||||
export { loadAndFormatCollection } from './loadAndFormatCollection'
|
export * from './getSlug'
|
||||||
export { sortPosts } from './sortPosts'
|
export * from './loadAndFormatCollection'
|
||||||
export { getAllPostsForSearch } from './getAllPostsForSearch'
|
export * from './sortPosts'
|
||||||
|
export * from './getAllPostsForSearch'
|
||||||
|
78
src/lib/exif/format.test.ts
Normal file
78
src/lib/exif/format.test.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { it, describe, expect } from 'vitest'
|
||||||
|
import { formatGps, formatExposure, formatExif } from './format'
|
||||||
|
import type { FastExif } from '.'
|
||||||
|
|
||||||
|
describe('Exif formatting functions', () => {
|
||||||
|
describe('formatGps', () => {
|
||||||
|
it('should format GPS data correctly', () => {
|
||||||
|
const input: FastExif['gps'] = {
|
||||||
|
GPSLatitudeRef: 'N',
|
||||||
|
GPSLatitude: [52, 30, 0],
|
||||||
|
GPSLongitudeRef: 'E',
|
||||||
|
GPSLongitude: [13, 23, 0]
|
||||||
|
}
|
||||||
|
const result = formatGps(input)
|
||||||
|
expect(result).toEqual({
|
||||||
|
latitude: 52.5,
|
||||||
|
longitude: 13.383333333333333
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('formatExposure', () => {
|
||||||
|
it('should format exposure correctly for positive numbers', () => {
|
||||||
|
const input = 0.25
|
||||||
|
const result = formatExposure(input)
|
||||||
|
expect(result).toBe('+ 0.25 ev')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should format exposure correctly for negative numbers', () => {
|
||||||
|
const input = -0.25
|
||||||
|
const result = formatExposure(input)
|
||||||
|
expect(result).toBe('- 0.25 ev')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('formatExif', () => {
|
||||||
|
it('should format EXIF data correctly', () => {
|
||||||
|
const input: FastExif = {
|
||||||
|
image: { Model: 'FC7203' },
|
||||||
|
exif: {
|
||||||
|
ISO: 100,
|
||||||
|
FNumber: 2.8,
|
||||||
|
ExposureTime: 1 / 50,
|
||||||
|
FocalLength: 24,
|
||||||
|
ExposureBiasValue: 0,
|
||||||
|
DateTimeOriginal: '2020-12-31T23:59:59.000Z'
|
||||||
|
},
|
||||||
|
gps: {
|
||||||
|
GPSLatitudeRef: 'N',
|
||||||
|
GPSLatitude: [52, 30, 0],
|
||||||
|
GPSLongitudeRef: 'E',
|
||||||
|
GPSLongitude: [13, 23, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const result = formatExif(input)
|
||||||
|
expect(result).toEqual({
|
||||||
|
date: expect.any(String),
|
||||||
|
iso: 'ISO 100',
|
||||||
|
model: 'DJI Mavic Mini',
|
||||||
|
fstop: 'ƒ/2.8',
|
||||||
|
shutterspeed: '1/50s',
|
||||||
|
focalLength: '24mm',
|
||||||
|
lensModel: undefined,
|
||||||
|
exposure: '+/- 0 ev',
|
||||||
|
gps: {
|
||||||
|
latitude: 52.5,
|
||||||
|
longitude: 13.383333333333333
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns nothing when no exif received', () => {
|
||||||
|
const input: FastExif = {}
|
||||||
|
const result = formatExif(input)
|
||||||
|
expect(result).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -5,7 +5,7 @@ import getCoordinates from 'dms2dec'
|
|||||||
import Fraction from 'fraction.js'
|
import Fraction from 'fraction.js'
|
||||||
import type { ExifFormatted, FastExif } from './types.ts'
|
import type { ExifFormatted, FastExif } from './types.ts'
|
||||||
|
|
||||||
function formatGps(gpsData: FastExif['gps']): {
|
export function formatGps(gpsData: FastExif['gps']): {
|
||||||
latitude: number
|
latitude: number
|
||||||
longitude: number
|
longitude: number
|
||||||
} {
|
} {
|
||||||
@ -24,18 +24,16 @@ function formatGps(gpsData: FastExif['gps']): {
|
|||||||
return { latitude, longitude }
|
return { latitude, longitude }
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatExposure(exposureMode: number) {
|
export function formatExposure(exposureMode: number) {
|
||||||
if (exposureMode === null || exposureMode === undefined) return
|
if (!exposureMode || exposureMode === 0) return `+/- 0 ev`
|
||||||
|
|
||||||
const exposureShortened = parseFloat(exposureMode.toFixed(2))
|
const exposureShortened = parseFloat(exposureMode.toFixed(2))
|
||||||
let exposure
|
let exposure
|
||||||
|
|
||||||
if (exposureMode === 0) {
|
if (exposureMode > 0) {
|
||||||
exposure = `+/- ${exposureShortened} ev`
|
|
||||||
} else if (exposureMode > 0) {
|
|
||||||
exposure = `+ ${exposureShortened} ev`
|
exposure = `+ ${exposureShortened} ev`
|
||||||
} else {
|
} else {
|
||||||
exposure = `${exposureShortened} ev`
|
exposure = `- ${Math.abs(exposureShortened)} ev`
|
||||||
}
|
}
|
||||||
|
|
||||||
return exposure
|
return exposure
|
||||||
@ -76,12 +74,12 @@ export function formatExif(exifData: FastExif): ExifFormatted | undefined {
|
|||||||
const exposure = formatExposure(exposureValue)
|
const exposure = formatExposure(exposureValue)
|
||||||
|
|
||||||
// Model
|
// Model
|
||||||
model === 'FC7203' ? 'DJI Mavic Mini' : model
|
const formattedModel = model === 'FC7203' ? 'DJI Mavic Mini' : model
|
||||||
|
|
||||||
return {
|
return {
|
||||||
date: date as string,
|
date: date as string,
|
||||||
iso,
|
iso,
|
||||||
model,
|
model: formattedModel,
|
||||||
fstop,
|
fstop,
|
||||||
shutterspeed,
|
shutterspeed,
|
||||||
focalLength,
|
focalLength,
|
||||||
|
@ -1,35 +1,2 @@
|
|||||||
import fs from 'node:fs'
|
export * from './readOutExif'
|
||||||
import path from 'node:path'
|
export * from './types'
|
||||||
import { read } from 'fast-exif'
|
|
||||||
import iptc from 'node-iptc'
|
|
||||||
import type { Exif, ExifFormatted } from './types.ts'
|
|
||||||
import { formatExif } from './format.ts'
|
|
||||||
|
|
||||||
export async function readOutExif(filePath: string): Promise<Exif | undefined> {
|
|
||||||
if (!filePath) return
|
|
||||||
|
|
||||||
const imageId = path.basename(filePath, path.extname(filePath))
|
|
||||||
|
|
||||||
try {
|
|
||||||
// exif
|
|
||||||
const exifData = await read(filePath, true)
|
|
||||||
if (!exifData) return
|
|
||||||
|
|
||||||
// iptc
|
|
||||||
const file = fs.readFileSync(filePath)
|
|
||||||
const iptcData = iptc(file)
|
|
||||||
|
|
||||||
// format before output
|
|
||||||
const exifDataFormatted = formatExif(exifData)
|
|
||||||
|
|
||||||
const exif = {
|
|
||||||
image: imageId,
|
|
||||||
exif: { ...exifDataFormatted } as ExifFormatted,
|
|
||||||
iptc: { ...iptcData }
|
|
||||||
}
|
|
||||||
|
|
||||||
return exif
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error(`${imageId}: ${error.message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
35
src/lib/exif/readOutExif.ts
Normal file
35
src/lib/exif/readOutExif.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { read } from 'fast-exif'
|
||||||
|
import iptc from 'node-iptc'
|
||||||
|
import type { Exif, ExifFormatted } from './types.ts'
|
||||||
|
import { formatExif } from './format.ts'
|
||||||
|
|
||||||
|
export async function readOutExif(filePath: string): Promise<Exif | undefined> {
|
||||||
|
if (!filePath) return
|
||||||
|
|
||||||
|
const imageId = path.basename(filePath, path.extname(filePath))
|
||||||
|
|
||||||
|
try {
|
||||||
|
// exif
|
||||||
|
const exifData = await read(filePath, true)
|
||||||
|
if (!exifData) return
|
||||||
|
|
||||||
|
// iptc
|
||||||
|
const file = fs.readFileSync(filePath)
|
||||||
|
const iptcData = iptc(file)
|
||||||
|
|
||||||
|
// format before output
|
||||||
|
const exifDataFormatted = formatExif(exifData)
|
||||||
|
|
||||||
|
const exif = {
|
||||||
|
image: imageId,
|
||||||
|
exif: { ...exifDataFormatted } as ExifFormatted,
|
||||||
|
iptc: { ...iptcData }
|
||||||
|
}
|
||||||
|
|
||||||
|
return exif
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`${imageId}: ${error.message}`)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { it, describe, expect } from 'vitest'
|
import { it, describe, expect } from 'vitest'
|
||||||
import { getFeedContent } from './feed'
|
import { getFeedContent } from '.'
|
||||||
|
|
||||||
describe('getFeedContent', () => {
|
describe('getFeedContent', () => {
|
||||||
it('should generate post feed content with an image', async () => {
|
it('should generate post feed content with an image', async () => {
|
@ -1,5 +1,5 @@
|
|||||||
import type { CollectionEntry } from 'astro:content'
|
import type { CollectionEntry } from 'astro:content'
|
||||||
import { markdownToHtml } from './markdown'
|
import { markdownToHtml } from '../markdown'
|
||||||
|
|
||||||
export async function getFeedContent(
|
export async function getFeedContent(
|
||||||
post: CollectionEntry<'articles' | 'photos' | 'links'>
|
post: CollectionEntry<'articles' | 'photos' | 'links'>
|
1
src/lib/feed/index.ts
Normal file
1
src/lib/feed/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './feed'
|
@ -1,5 +1,5 @@
|
|||||||
import { it, describe, expect, vi } from 'vitest'
|
import { it, describe, expect, vi } from 'vitest'
|
||||||
import { getRepo } from './github'
|
import { getRepo } from '.'
|
||||||
|
|
||||||
describe('getRepo Function', () => {
|
describe('getRepo Function', () => {
|
||||||
const mockResponseData = {
|
const mockResponseData = {
|
1
src/lib/github/index.ts
Normal file
1
src/lib/github/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './github'
|
1
src/lib/remark-lead-paragraph/index.ts
Normal file
1
src/lib/remark-lead-paragraph/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './remark-lead-paragraph'
|
@ -4,7 +4,7 @@ import remarkRehype from 'remark-rehype'
|
|||||||
import rehypeStringify from 'rehype-stringify'
|
import rehypeStringify from 'rehype-stringify'
|
||||||
import { VFile } from 'vfile'
|
import { VFile } from 'vfile'
|
||||||
import { test, expect, beforeAll } from 'vitest'
|
import { test, expect, beforeAll } from 'vitest'
|
||||||
import remarkLeadParagraph, { type MyFile } from './remark-lead-paragraph'
|
import { remarkLeadParagraph, type MyFile } from '.'
|
||||||
|
|
||||||
let processor: ReturnType<typeof unified>
|
let processor: ReturnType<typeof unified>
|
||||||
|
|
@ -17,7 +17,7 @@ export interface MyFile extends VFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function remarkLeadParagraph(): Transformer {
|
export function remarkLeadParagraph(): Transformer {
|
||||||
return (tree, file) => {
|
return (tree, file) => {
|
||||||
// Check if the file is the type we want to process
|
// Check if the file is the type we want to process
|
||||||
if (!file.history[0]?.includes('articles')) return
|
if (!file.history[0]?.includes('articles')) return
|
1
src/lib/remark-toc/index.ts
Normal file
1
src/lib/remark-toc/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './remark-toc'
|
@ -4,7 +4,7 @@ import remarkRehype from 'remark-rehype'
|
|||||||
import rehypeStringify from 'rehype-stringify'
|
import rehypeStringify from 'rehype-stringify'
|
||||||
import { VFile } from 'vfile'
|
import { VFile } from 'vfile'
|
||||||
import { test, expect } from 'vitest'
|
import { test, expect } from 'vitest'
|
||||||
import remarkToc, { type MyFile } from './remark-toc' // Replace with the actual path
|
import { remarkToc, type MyFile } from '.'
|
||||||
|
|
||||||
const expectedToc: string = `<ul>
|
const expectedToc: string = `<ul>
|
||||||
<li>
|
<li>
|
@ -19,7 +19,7 @@ export interface MyFile extends VFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function remarkToc(): Transformer {
|
export function remarkToc(): Transformer {
|
||||||
return (tree, file) => {
|
return (tree, file) => {
|
||||||
// Check if the file is the type we want to process
|
// Check if the file is the type we want to process
|
||||||
if (!file.history[0]?.includes('articles')) return
|
if (!file.history[0]?.includes('articles')) return
|
1
src/lib/slugify/index.ts
Normal file
1
src/lib/slugify/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './slugify'
|
@ -1,5 +1,5 @@
|
|||||||
import { test, expect } from 'vitest'
|
import { test, expect } from 'vitest'
|
||||||
import slugify, { slugifyAll } from './slugify'
|
import { slugify, slugifyAll } from '.'
|
||||||
|
|
||||||
test('slugify should convert text to slug', () => {
|
test('slugify should convert text to slug', () => {
|
||||||
const text = 'Hello World!'
|
const text = 'Hello World!'
|
@ -1,8 +1,6 @@
|
|||||||
import slugifyLib from 'slugify'
|
import slugifyLib from 'slugify'
|
||||||
|
|
||||||
const slugify = (text: string) =>
|
export const slugify = (text: string) =>
|
||||||
slugifyLib(text, { lower: true, remove: /[*+~.()'"!:@]/g })
|
slugifyLib(text, { lower: true, remove: /[*+~.()'"!:@]/g })
|
||||||
|
|
||||||
export const slugifyAll = (arr: string[]) => arr.map((str) => slugify(str))
|
export const slugifyAll = (arr: string[]) => arr.map((str) => slugify(str))
|
||||||
|
|
||||||
export default slugify
|
|
1
src/lib/umami/index.ts
Normal file
1
src/lib/umami/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './umami'
|
@ -1,5 +1,5 @@
|
|||||||
import { test, expect } from 'vitest'
|
import { test, expect } from 'vitest'
|
||||||
import { getUmamiConfig } from './umami'
|
import { getUmamiConfig } from '.'
|
||||||
|
|
||||||
test('should throw an error if Umami environment variables are missing in production', () => {
|
test('should throw an error if Umami environment variables are missing in production', () => {
|
||||||
const mockEnv = {
|
const mockEnv = {
|
Loading…
Reference in New Issue
Block a user