ren 판매

Linkwarden is a self-hosted, open-source bookmark manager that captures screenshots, PDFs, and full-page archives of webpages to prevent link rot, with support for annotations, collections, and team collaboration.
This block is the full Linkwarden monorepo: a self-hosted collaborative bookmark manager with a Next.js web app, an Expo React Native mobile app, and a background worker. The primary integration target for most buyers is apps/mobile, which provides production-ready screens, stores, and components for browsing, searching, and managing bookmarked links against any Linkwarden API instance.
.devcontainer/ - VS Code dev-container configuration for reproducible local setup.github/ - CI workflows (Playwright tests, container release, locale sync) and issue templates.vscode/ - Editor settings for consistent formattingapps/mobile/ - Expo 52 React Native app: screens, navigation, components, stores, and theme utilitiesapps/web/ - Next.js web frontend for Linkwardenapps/worker/ - Background job processor (screenshot/PDF capture, archiving)assets/ - Shared static assets (logo, home screenshot)packages/ - Shared internal packages: @linkwarden/router, @linkwarden/types, @linkwarden/prisma.eslintrc.json - Monorepo-wide ESLint config.prettierrc.json - Prettier formatting configdocker-compose.yml - Full-stack local Docker environmentpackage.json - Monorepo root with Yarn workspacesnpm install expo expo-router expo-application expo-clipboard
npm install react-native react-native-safe-area-context react-native-svg
npm install react-native-reanimated react-native-actions-sheet
npm install nativewind tailwindcss
npm install lucide-react-native
npm install zustand
npm install @tanstack/react-query
Native build steps are required for iOS and Android:
# Install iOS native dependencies
npx pod-install ios
# Or use Expo's managed prebuild
npx expo prebuild
# For Android, gradle linking is handled automatically via prebuild
source/ into your project root. The monorepo uses Yarn workspaces; ensure your root package.json has "workspaces": ["apps/*", "packages/*"].격리된 샌드박스를 띄워 서버에서 바로 실행하세요 — 로컬 설정 불필요.
이 버전에 대한 Tetrees AI Review
This React, React Native mobile app completed archive review with strong static results. Structure, dependency manifests, documentation, functional source, and common risk patterns were checked by the Tetrees verification pipeline; runtime phases are stated separately.
Deterministic AVCP artifact review
파이프라인 avcp-2026-08-04.1 · SHA-256 8b17a950089e167f…
This version-scoped review deterministically inspects the submitted archive for structure, dependencies, documentation, functional source, and common malicious or high-risk signals. Build and test phases are reported as passed only after an isolated sandbox audition. It is not a guarantee of perfect security.
검토일 2026년 8월 4일
이 제품을 AI IDE, 웹 빌더 또는 클라우드 IDE로 바로 가져오세요.
Tetrees를 호환 AI IDE에 연결해 보유 제품을 불러오고, 판매자 업로드 권한을 노출하지 않은 채 검증된 ZIP을 받으세요.
아직 리뷰가 없습니다.
토론을 불러오는 중…
yarn install
apps/mobile/tsconfig.json:
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"],
"@linkwarden/router/*": ["../../packages/router/*"],
"@linkwarden/types/*": ["../../packages/types/*"]
}
}
}
metro.config.js in apps/mobile to resolve monorepo packages:
const { getDefaultConfig } = require("expo/metro-config");
const config = getDefaultConfig(__dirname);
config.watchFolders = [path.resolve(__dirname, "../../packages")];
module.exports = config;
apps/mobile/.env:
EXPO_PUBLIC_API_URL=https://your-linkwarden-instance.com
cd apps/mobile && npx expo start
import useAuthStore from "@/store/auth";
const { auth, signOut } = useAuthStore();
// auth.session: string | null — active session token
// signOut: () => void — clears session and redirects to login
Zustand store that persists authentication state across app restarts. Pass auth to all @linkwarden/router hooks to authenticate API requests.
import { useCollections } from "@linkwarden/router/collections";
import useAuthStore from "@/store/auth";
const { auth } = useAuthStore();
const collections = useCollections(auth);
// collections.data: CollectionIncludingMembersAndLinkCount[]
// collections.isLoading: boolean
// collections.refetch: () => void
TanStack Query hook that fetches all collections for the authenticated user. Returns collections with member list and link counts, ready to render in a FlatList.
import { useDashboardData } from "@linkwarden/router/dashboardData";
const {
data: { links, numberOfPinnedLinks, numberOfTags, collectionLinks } = {
links: [],
},
...dashboardData
} = useDashboardData(auth);
// links: Link[] — recently added/pinned links
// numberOfPinnedLinks: number
// numberOfTags: number
// collectionLinks: Record<string, Link[]>
Fetches aggregated dashboard data including pinned links and per-collection link counts. Used in DashboardScreen to populate summary statistics and section lists.
import { useLinks } from "@linkwarden/router/links";
const { links, data } = useLinks(
{
sort: 0,
searchQueryString: "typescript",
},
auth
);
// links: Link[] — flat array of matching links
// data: UseInfiniteQueryResult — full query result for pagination
Infinite-scroll hook for paginated link retrieval. Pass sort (numeric sort order) and searchQueryString to filter results. Integrates directly with the Links component.
Display all user collections in a flat list with pull-to-refresh. This mirrors the production CollectionsScreen.
import React, { useEffect, useState } from "react";
import { FlatList, View, Text, ActivityIndicator } from "react-native";
import useAuthStore from "@/store/auth";
import { useCollections } from "@linkwarden/router/collections";
import { CollectionIncludingMembersAndLinkCount } from "@linkwarden/types/global";
export default function MyCollectionsScreen() {
const { auth } = useAuthStore();
const collections = useCollections(auth);
const [items, setItems] = useState<CollectionIncludingMembersAndLinkCount[]>([]);
useEffect(() => {
setItems(collections.data ?? []);
}, [collections.data]);
if (collections.isLoading) {
return <ActivityIndicator size="large" />;
}
return (
<FlatList
data={items}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<View>
<Text>{item.name}</Text>
<Text>{item._count?.links ?? 0} links</Text>
</View>
)}
onRefresh={() => collections.refetch()}
refreshing={collections.isRefetching}
/>
);
}
Wire a search input to useLinks to filter the user's bookmarks in real time.
import React, { useState } from "react";
import { View, TextInput } from "react-native";
import useAuthStore from "@/store/auth";
import { useLinks } from "@linkwarden/router/links";
import Links from "@/components/Links";
export default function SearchScreen() {
const { auth } = useAuthStore();
const [query, setQuery] = useState("");
const { links, data } = useLinks(
{ sort: 0, searchQueryString: query },
auth
);
return (
<View className="flex-1 bg-base-100">
<TextInput
value={query}
onChangeText={setQuery}
placeholder="Search bookmarks..."
className="border border-neutral rounded px-3 py-2 m-4"
/>
<Links links={links} data={data} />
</View>
);
}
Replicate the version-aware dashboard stats panel, using isAtLeastInstanceVersion to conditionally fall back to the legacy tags endpoint.
import React from "react";
import { View, Text } from "react-native";
import useAuthStore from "@/store/auth";
import { useDashboardData } from "@linkwarden/router/dashboardData";
import { isAtLeastInstanceVersion, useConfig } from "@linkwarden/router/config";
import { useTags } from "@linkwarden/router/tags";
const TAG_COUNT_VERSION = "2.14.0";
export default function StatsBar() {
const { auth } = useAuthStore();
const { data: { links = [], numberOfTags = 0 } = {} } = useDashboardData(auth);
const config = useConfig(auth);
const supportsTagCount = isAtLeastInstanceVersion(
config.data?.INSTANCE_VERSION,
TAG_COUNT_VERSION
);
const useLegacy = config.isError || (config.isSuccess && !supportsTagCount);
const legacyTags = useTags(auth, { enabled: useLegacy });
const tagCount = useLegacy
? (legacyTags.data?.length ?? 0)
: numberOfTags;
return (
<View>
<Text>Links: {links.length}</Text>
<Text>Tags: {tagCount}</Text>
</View>
);
}
apps/mobile/app/index.tsx - Landing screen; redirects authenticated users to /dashboard, otherwise renders the welcome UI with sign-in entry points.apps/mobile/app/(tabs)/collections/index.tsx - Collections tab: fetches and filters useCollections data, renders as a pull-to-refresh FlatList.apps/mobile/app/(tabs)/dashboard/index.tsx - Dashboard tab: aggregates links, collections, tags, and user preferences into section-based summary view.apps/mobile/app/(tabs)/links/index.tsx - All-links tab: passes search param from URL into useLinks and delegates rendering to the shared Links component.apps/mobile/app/(tabs)/settings/index.tsx - Settings tab: theme toggle (light/dark/system), sign-out, app version display, preferred collection routing.apps/mobile/store/ - Zustand stores for auth state (auth) and persisted app data (data).apps/mobile/components/ - Shared UI: Links, CollectionListing, DashboardSection, design-system primitives (Button, Spinner).apps/mobile/lib/colors.ts - Theme token map (rawTheme) keyed by ThemeName; used to pass hex values into SVG and native components that don't accept CSS classes.packages/ - @linkwarden/router (TanStack Query hooks), @linkwarden/types (shared TypeScript types), @linkwarden/prisma (Prisma client + generated types).@linkwarden/* packages: Add config.watchFolders pointing to packages/ in metro.config.js and symlink or set resolver.nodeModulesPaths.nativewind class names not applied on Android: Run npx expo prebuild --clean after adding or changing tailwind.config.js; stale native builds ignore new class generation.react-native-reanimated Babel plugin missing: Add "react-native-reanimated/plugin" as the last entry in plugins in babel.config.js; omitting it causes silent runtime crashes on animated screens.useColorScheme returns null on first render: Guard with colorScheme ?? "light" before indexing into rawTheme; the value is async on initial mount.useAuthStore Zustand store must use persist middleware with AsyncStorage; verify @react-native-async-storage/async-storage is installed and linked.SafeAreaView edges cut off bottom buttons on Android: Use edges={["bottom"]} prop explicitly rather than relying on default edge insets; defaults differ across RN versions.I have purchased the Linkwarden mobile source block. The source is in `source/`
and the integration guide is in `USAGE.md`. The upstream npm package is
`user@example.com` (monorepo root).
My project is a React Native / Expo app that needs to display and manage
bookmarks against a self-hosted Linkwarden instance.
Please integrate the source step by step:
1. Read USAGE.md fully before making any changes.
2. Configure Yarn workspaces so `apps/mobile` and `packages/*` resolve correctly.
3. Wire `metro.config.js` to watch `source/packages/` for `@linkwarden/router`,
`@linkwarden/types`, and `@linkwarden/prisma`.
4. Set up `tsconfig.json` path aliases matching those in USAGE.md ## Project setup.
5. Add the `useAuthStore` Zustand store from `source/apps/mobile/store/auth` to
my project and connect it to the Expo Router login flow.
6. Create a Collections screen using `useCollections` from
`@linkwarden/router/collections`, following the pattern in
`source/apps/mobile/app/(tabs)/collections/index.tsx`.
7. Create a Links search screen using `useLinks` from
`@linkwarden/router/links`, following the example in USAGE.md.
8. Add the theme utilities from `source/apps/mobile/lib/colors` and configure
`nativewind` with the existing `tailwind.config.js`.
9. Show me all modified files with complete content, not diffs.
Linkwarden is released under the GNU Affero General Public License v3.0 (AGPL-3.0). See source/LICENSE.md for the full license text. Any modified version of this software that is served over a network must also be made available as open source under the same license.
Upstream project: https://github.com/linkwarden/linkwarden
This product’s unique contribution is clean room implementation of valuable code block into AVCP compatible standard.
전체 설치 가이드와 연동 프롬프트는 구매 후 열람할 수 있습니다.
Automation, Utilities & Developer Tools
무료